lila/data-pipeline/prompt
lila 37c978e230 implementing phase 3 pipeline: gemini structured output, validation, sqlite staging
Prompt is now a template (fixes the hardcoded en/es leftovers in rules
2, 3, 15, 16, 26, 31). pipeline.ts replaces the pseudocode: wordlist
normalization, skip-already-staged idempotency, batches of 20 against
gemini-3.6-flash with responseSchema, raw responses persisted per batch,
per-entry validation with rejection log, one transaction per word into
db/staging.db. Flags: --langs --pos --max-batches --delay-ms --dry-run.

Smoke run: 40/40 words staged (de+es, one batch each), 0 rejections.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-09 19:04:04 +02:00

180 lines
6.2 KiB
Text

You are a multilingual lexicographer generating vocabulary data for a language-learning app.
Source language: {{SOURCE_LANGUAGE_NAME}} ("{{SOURCE_LANGUAGE_CODE}}")
Part of speech: {{POS}}
Target languages: {{TARGET_LANGUAGE_CODES}}
Input words:
{{INPUT_WORDS}}
Return ONLY valid JSON.
Do not include markdown fences.
Do not include explanations.
Do not include comments.
Do not include trailing commas.
The response must be a JSON array with exactly one object per input word, in the same order as the input words.
Each word object must have this shape:
{
"headword": string,
"language": "{{SOURCE_LANGUAGE_CODE}}",
"pos": "{{POS}}",
"senses": [
{
"sense_index": number,
"difficulty": "easy" | "medium" | "hard",
"definitions": string[],
"examples": string[],
"translations": [
{
"target_language": {{TARGET_LANGUAGE_UNION}},
"word": string,
"gender": "masculine" | "feminine" | "neuter" | null,
"difficulty": "easy" | "medium" | "hard"
}
]
}
]
}
Rules:
1. The headword must be exactly one of the input words.
2. language must be "{{SOURCE_LANGUAGE_CODE}}".
3. pos must be "{{POS}}".
4. Include only common, learner-relevant senses.
5. Most words should have 1 sense.
6. Polysemous words may have 2 or 3 senses.
7. Do not include rare, archaic, highly technical, or literary senses unless they are common.
8. sense_index must start at 0 and increase by 1.
9. definitions must be written in {{SOURCE_LANGUAGE_NAME}}.
10. examples must be written in {{SOURCE_LANGUAGE_NAME}}.
11. Include 1 or 2 definitions per sense.
12. Include 1 or 2 example sentences per sense.
13. Each definition must be student-friendly and at most 15 words.
14. Each example should naturally contain the headword or a clear form of it.
15. Every sense must have translations for all target languages: {{TARGET_LANGUAGE_CODES}}.
16. Do not include {{SOURCE_LANGUAGE_NAME}} ("{{SOURCE_LANGUAGE_CODE}}") as a target_language.
17. You may include up to 2 translations per target language per sense if they are genuinely common synonyms or difficulty variants.
18. Do not include more than 2 translations per target language per sense.
19. Do not duplicate the same translation word for the same target language within one sense.
20. Use the base dictionary form of the translated {{POS}}.
21. Do not include articles or determiners in translations.
22. German translation nouns must be capitalized.
23. Spanish, French, and Italian translation nouns should be lowercase unless they are proper nouns.
24. For target_language "de", gender must be "masculine", "feminine", or "neuter".
25. For target_language "it", "es", or "fr", gender must be "masculine" or "feminine".
26. gender must be null if and only if target_language is "en".
27. difficulty must be one of: "easy", "medium", "hard".
28. senses.difficulty describes how common or advanced the meaning is.
29. translations.difficulty describes how difficult the specific target-language word is for a learner.
30. A common translation like "Bank" may be easy, while a formal synonym like "Geldinstitut" may be medium.
31. If a word cannot be treated as a valid {{SOURCE_LANGUAGE_NAME}} {{POS}}, return it with "senses": [].
Difficulty calibration:
- easy: beginner, everyday vocabulary, roughly CEFR A1/A2
- medium: intermediate, less common or more formal vocabulary, roughly CEFR B1/B2
- hard: advanced, rare, literary, or technical vocabulary, roughly CEFR C1/C2
Do not include CEFR levels in the output.
Example output shape for the English noun "bank" (illustrative of the JSON shape only — your definitions and examples must be in {{SOURCE_LANGUAGE_NAME}}):
[
{
"headword": "bank",
"language": "en",
"pos": "noun",
"senses": [
{
"sense_index": 0,
"difficulty": "easy",
"definitions": [
"An institution where people deposit and borrow money."
],
"examples": [
"She deposited her paycheck at the bank."
],
"translations": [
{
"target_language": "de",
"word": "Bank",
"gender": "feminine",
"difficulty": "easy"
},
{
"target_language": "de",
"word": "Geldinstitut",
"gender": "neuter",
"difficulty": "medium"
},
{
"target_language": "it",
"word": "banca",
"gender": "feminine",
"difficulty": "easy"
},
{
"target_language": "es",
"word": "banco",
"gender": "masculine",
"difficulty": "easy"
},
{
"target_language": "fr",
"word": "banque",
"gender": "feminine",
"difficulty": "easy"
}
]
},
{
"sense_index": 1,
"difficulty": "medium",
"definitions": [
"The land alongside a river or lake."
],
"examples": [
"They picnicked on the bank of the river."
],
"translations": [
{
"target_language": "de",
"word": "Ufer",
"gender": "neuter",
"difficulty": "medium"
},
{
"target_language": "it",
"word": "riva",
"gender": "feminine",
"difficulty": "medium"
},
{
"target_language": "es",
"word": "orilla",
"gender": "feminine",
"difficulty": "medium"
},
{
"target_language": "fr",
"word": "rive",
"gender": "feminine",
"difficulty": "medium"
}
]
}
]
}
]
For target_language "en", gender MUST ALWAYS be null. English nouns do not have grammatical gender.
CRITICAL: Definitions and examples MUST be written in the SOURCE language specified above.
If source language is German, definitions MUST be in German.
If source language is Spanish, definitions MUST be in Spanish.
If source language is English, definitions MUST be in English.
A translation difficulty must never be lower than its sense difficulty.
Set senses.difficulty to the easiest translation difficulty in that sense.