All posts
product4 min read

Saju AI - Real Solar Time, and Stopping the Model From Making Things Up

It doesn't stop at your birth date. The chart is computed properly, and when the model invents something the chart doesn't contain, the app falls back to rule-based text.

A birth date alone doesn't set the pillars

The pillars in Korean saju aren't set by the calendar date. The year and month pillars are divided by solar terms, and the day and hour pillars by true solar time at that location. Someone born in Seoul and someone born in Busan at the same clock time have the sun in different places. Skip that, and anyone born near a boundary gets an entirely different chart.

So the calculation came first

  • Year and month pillars follow the solar terms. Born before the start of spring and the year pillar belongs to the previous year.
  • Day and hour pillars use true solar time, derived from the birthplace longitude and the equation of time.
  • Korean standard time has changed several times since 1908, and daylight saving periods are included.

The server and the app share one TypeScript package for this. That means the chart still builds inside the app with no server connection. I didn't want an app that shows nothing without internet.

The model inventing stems and branches

The interpretive text is written by a model, and that caused a problem right away. While producing a plausible paragraph, the model slips in a stem or branch that isn't in the chart. Readers don't go back and check the computation, so they believe it.

So every response is checked. Format and length, and above all whether a stem or branch appears that the chart doesn't contain. On a mismatch the generated text is discarded, rule-based text is used instead, and the reason is written to the server log.

The first version of that checker produced many false positives, because ordinary Korean words contain those two-character sequences inside them. Matching on word boundaries fixed it.

Text written by the model is labelled as such on screen. With no server, only the rule-based text appears.

Tarot reads the cards you drew

For a tarot reading you write what's going on, up to 500 characters, and draw three cards yourself from the full 78-card deck. Those cards go to the server and the server interprets exactly those. It does not draw again. If you pull a card and the result discusses a different one, that isn't a reading, it's just generated text.

Requests a tarot reading can't answer are turned away before the model is called: writing code, translation, diagnosis, investment decisions. Anything touching self-harm gets counselling numbers instead of a reading, and that refusal doesn't consume the daily allowance.

There is no login

No name, no email. Users are told apart by one value: a device key, the hash of a device identifier. The server never sees the original identifier, and deleting the app produces a new one.

Birth profiles are removed after 365 days without access, reading history after 90. Requests with a missing or malformed device key are rejected with a 400. Collecting unlabelled requests in one place turns that place into a shared drawer, where one person's stored birth data is readable by the next.

Keeping the cost down

Interpretations are cached. When the material going into the prompt is identical, the stored text is returned instead of calling the model again. A chart doesn't change, and a daily fortune only changes when the date does, so reopening the same reading costs no tokens. The cache key is a hash of that material.

AI tarot readings are limited to three per device per day. Cache hits don't call the model, so they don't count against it. Past the limit the cards and their individual meanings still appear; only the generated passage is missing, and the screen says why.

Where it stands

It's on Google Play. Most readings are free, and once the daily allowance is used up a single reading can be bought on its own. It's a consumable, not a subscription, and the store handles payment. All the server receives is a transaction receipt.

Readings are for enjoyment and reflection, not a substitute for medical, legal or financial advice. That sentence is in the app too.