File size: 2,265 Bytes
2a0825b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
"""Dictation generation prompt + light text cleanup for the Gradio Space.

The LLM turns a learner's word list + CEFR level into ONE short German
dictation paragraph. This is distinct from the Anki flashcard prompts in
sys.md / sys1.md, which emit JSON — here we want plain prose to be read aloud.
"""

import re

DICTATION_SYSTEM_PROMPT = (
    "You are a German teacher writing a short dictation (Diktat) for a language "
    "learner.\n"
    "\n"
    "Write ONE coherent German paragraph of 2-4 natural, everyday sentences that "
    "uses EVERY target word the user provides at least once (inflect it naturally; "
    "the exact base form need not appear). The text must suit the given CEFR level:\n"
    "- A1/A2: short main clauses, common vocabulary, present tense, simple word order.\n"
    "- B1/B2: allow subordinate clauses, connectors and varied tenses, still everyday.\n"
    "\n"
    "Use correct standard German spelling, capitalization, umlauts (ä/ö/ü) and ß.\n"
    "Output ONLY the German dictation text. No title, no label, no quotation marks, "
    "no translation, no commentary, no markdown."
)


def build_user_prompt(words: list[str], level: str) -> str:
    """The user turn: the target words and the requested level."""
    joined = ", ".join(words)
    return f"Level: {level}\nTarget words: {joined}"


def parse_word_list(raw: str) -> list[str]:
    """Split learner input on commas and/or newlines into trimmed words,
    dropping blanks while preserving order (spec §4)."""
    parts = re.split(r"[,\n]+", raw or "")
    return [w.strip() for w in parts if w.strip()]


_LABEL_RE = re.compile(r"^\s*(diktat|dictation|text)\s*:\s*", re.IGNORECASE)


def clean_dictation(text: str) -> str:
    """Strip a leading label line (e.g. 'Diktat:') and wrapping quotes the LLM
    may add despite instructions (spec §4)."""
    text = (text or "").strip()
    text = _LABEL_RE.sub("", text, count=1).strip()
    # Strip one layer of matching surrounding quotes (straight or typographic).
    pairs = [('"', '"'), ("'", "'"), ("“", "”"), ("„", "“")]
    for open_q, close_q in pairs:
        if len(text) >= 2 and text[0] == open_q and text[-1] == close_q:
            text = text[1:-1].strip()
            break
    return text