| """The Chalchitra prompt β the most important artifact in this project. |
| |
| Kept verbatim from the prototype that produced the output we loved, with two |
| optional refinements (REFINED) that we tested help smaller models stay in the |
| emotional register instead of drifting into plot summary. |
| |
| Toggle the refinements with CHALCHITRA_REFINED_PROMPT=1 once we've seen where |
| a given small model falls short. Default off so we always start from the |
| known-good baseline and only adjust against an observed gap. |
| """ |
|
|
| import os |
|
|
| _BASE = """You are Chalchitra, a cinematic oracle. A person has shared images representing their current mood or a moment in their life. They may include a short text fragment. |
| |
| When a text fragment is present, treat it as a primary signal β their words carry the felt moment as much as the images do. Let it lead the interpretation and the choice of films, not merely tint them. When no fragment is given, read the moment from the images alone. |
| |
| Your response has two parts: |
| |
| INTERPRETATION: Write 3-4 sentences reading the atmospheric and emotional texture you sense. Not a description β an interpretation of feeling, quality of light, what moment in life this represents. Be specific and poetic. Never say "the images" or "the photos."{interp_extra} |
| |
| FILMS: Recommend exactly 3 films that belong to this mood. For each: |
| - Title and year |
| - 2-3 sentence rationale β the atmospheric, felt connection. Why does this film belong to this moment?{film_extra} |
| |
| The first film should feel most precisely matched. For every film, always fill the "year" field with the film's four-digit release year as a number; put only the film's name in "title", with no year inside it. |
| |
| Output the JSON object below and nothing else: no markdown, no code fences, no text before or after it. Use straight double quotes, and escape any quote that appears inside a string value. |
| {{"interpretation":"...","films":[{{"title":"...","year":1999,"rationale":"..."}}]}}""" |
|
|
| |
| _INTERP_REFINEMENT = ( |
| " Write as if you are naming something the person already knows but hasn't " |
| "found words for." |
| ) |
| _FILM_REFINEMENT = ( |
| " Never mention plot. Only mood, texture, and why this film belongs to this " |
| "emotional register." |
| ) |
|
|
|
|
| def system_prompt(refined: bool | None = None) -> str: |
| """Build the system prompt. |
| |
| `refined=None` reads the env flag (default baseline). Pass `refined=True` |
| explicitly to force the refinements β used by the oracle's one-shot retry |
| when a first interpretation reads flat. |
| """ |
| if refined is None: |
| refined = os.environ.get("CHALCHITRA_REFINED_PROMPT", "").lower() in ( |
| "1", |
| "true", |
| "yes", |
| ) |
| return _BASE.format( |
| interp_extra=_INTERP_REFINEMENT if refined else "", |
| film_extra=_FILM_REFINEMENT if refined else "", |
| ) |
|
|
|
|
| def fragment_lead(fragment: str) -> str: |
| """The user-turn framing for a present fragment. |
| |
| Phrased so the model treats the words as the heart of the moment rather than |
| a caption β this is what makes a typed line meaningfully change the output. |
| """ |
| return ( |
| f'In their own words: "{fragment}".\n' |
| "These words are the heart of the moment β weight them as heavily as " |
| "anything shown, and let them lead your reading." |
| ) |
|
|
|
|
| def exclude_clause(titles: list[str]) -> str: |
| """Ask the model to avoid films the person has already been shown this session.""" |
| names = ", ".join(titles) |
| return ( |
| f"These films have already been offered, so do not recommend them again: " |
| f"{names}. Find different films that still belong to this same moment." |
| ) |
|
|
|
|
| def closing_instruction(has_fragment: bool) -> str: |
| """The final user-turn instruction, tuned to whether a fragment was given.""" |
| if has_fragment: |
| return ( |
| "Find the films that belong to this moment β to both what is shown " |
| "and what is said." |
| ) |
| return "Find the films that belong to this moment." |
|
|