#!/usr/bin/env python3
"""
看图拼词 (core_writing_imgMakeWord) 多步 LLM prompt 模板

生成流水线（7步，Step 5 为规则生成）：
  Step 1: 学习流程配置 (intermediate text)
  Step 2: 互动描述 (intermediate text)
  Step 3: taskInfo → JSON
  Step 4: preDialog → JSON
  Step 5: imageInfo → 规则生成 (不需要 prompt)
  Step 6: questionList → JSON
  Step 7: studyInfo → JSON
"""

# ── Step 1: 学习流程配置 ──
STEP1_LEARNING_FLOW = r"""你是一名儿童英语学习助手，负责为学习者生成互动式的巩固练习题。请根据以下信息生成练习内容：

**输入信息**
$学习过程$

**生成要求**

1. 为每个【学习过程】中的每个单词生成一个小题，包含以下结构：

   ```
   # 小题 X
   ## 互动题目
   1. 抄写题
   Brainy：如图所示，首先/接着/最后要帮 Sarah 整理的物品是"中文词"，该词的英文是"英文词"。先来抄写一下这个词吧！

   2. 听写题
   Brainy：很好。接下来，记一下"英文词"的拼写，是"字母拆分"。然后看着图片，试试听写出"中文词"这个词吧！

   Brainy：没错！"中文词"对应的英文词汇是"英文词"，你的拼写完全正确！
   ```

2. 每个知识词汇生成一题，顺序与知识词汇列表一致。

3. 拼写拆解用字母加"-"表示，多个单词间用空格分隔（如 teddy bear → t-e-d-d-y  b-e-a-r）。

4. 最后生成一个"完结反馈"：

   ```
   Brainy：太棒了！你复习了所有的关键知识点，拼对了每一个词，相信下一次你一定可以做得更好！
   ```

5. 输出中文引号全部使用英文引号""，不要使用中文引号"「」"。

6. 不输出额外说明或过程，只生成完整互动题内容。

### 三、示例输出（参考格式）
```
# 小题 1
## 互动题目
1. 抄写题
Brainy：如图所示，首先要帮 Sally 整理的物品是"照片"，"照片"的英文是"photo"。先来抄写一下这个词吧！

2. 听写题
Brainy：很好。接下来，记一下"photo"的拼写，是"p-h-o-t-o"。然后看着图片，试试听写出"照片"这个词吧！

Brainy：没错！"照片"对应的英文词汇是"photo"，你的拼写完全正确！

# 小题 2
## 互动题目
1. 抄写题
Brainy：如图所示，接着要帮 Sally 整理的物品是"奖牌"，"奖牌"的英文是"medal"。先来抄写一下这个词吧！

2. 听写题
Brainy：很好。接下来，记一下"medal"的拼写，是"m-e-d-a-l"。然后看着图片，试试听写出"奖牌"这个词吧！

Brainy：没错！"奖牌"对应的英文词汇是"medal"，你的拼写完全正确！


# 完结反馈
Brainy：太棒了！你复习了所有的关键知识点，拼对了每一个词，相信下一次你一定可以做得更好！
```

# 输出
现在请按照上述信息和要求，直接输出目标内容。"""


# ── Step 2: 互动描述 ──
STEP2_INTERACTION_DESC = r"""# 任务目标
你是一个儿童英语学习内容生成助手。现在需要根据给定的任务信息、知识词汇和前置对话，生成一句符合场景的英文描述句，并附上对应中文翻译。

# 输入信息
* 任务信息：
$任务信息$

* 前置对话：
$前置对话$

# 生成要求
只输出：
一句完整、自然、符合儿童英语学习场景的英文描述句
对应中文翻译（放在括号中）
英文句子要求：
必须结合「任务名称」与「知识」中的词汇
尽量自然使用多个知识词汇
句子简洁、口语化、符合少儿英语水平
与「前置对话」场景保持一致
中文翻译要求：
与英文句子语义完全对应
表达自然通顺
输出格式固定如下（禁止输出任何解释）：
English sentence.（中文翻译。）

# 输出示例
Dear Kate, I'd like to say thank you in this letter. Thank you for taking care of me. I have to go away now. Let's meet in the holidays.（亲爱的凯特，我想在这封信里向你表达感谢。感谢你对我的照顾。我现在必须离开了。咱们假期见。）"""


# ── Step 3: taskInfo ──
STEP3_TASK_INFO = r"""# 字段内容要求
{
    "cId": "{ID}", // 字符串类型
    "cType": "core_writing_imgMakeWord",
    "title": {任务信息}中的【任务名称】,
    "sceneDesc": {任务信息}中的【任务背景】,
    "cDesc": "xxx", // {互动描述}的全部内容
    "key": [ // {任务信息}中的【通关知识】
        {
            "desc": "",
            "keyList": [
                {
                    "type": "default", //固定
                    "content": 知识点内容（英文部分）,
                    "desc": 知识点解释（中文部分，如果是单词前面会带有英文缩写的词性标识）
                },
                 ... ...
            ]
        },
        ...
    ],
    "resourceMapping"(抽取出{角色配置}中的全部 name:id映射 可为空。id必须为int类型):
    {
    样例:
    "Tom":43,
    "Jerry":10
    }
}

# 输出格式
- 整个输出必须在一行内完成，**不要换行**。
- **不要使用 markdown 代码块**（如 ```json）包裹输出。

样例:
{"cId":"0000999","cType":"core_writing_imgMakeWord","title":"帮助sarah整理物品","sceneDesc":"场景描述，场景描述，看图说话场景描述","cDesc":"xxxxxx","key":[{"desc":"","keyList":[{"type":"default","content":"passport"},{"type":"default","content":"suitcase"},{"type":"default","content":"clothes"},{"type":"default","content":"pack"}]}],"resourceMapping":{"brainy":291,"jack":210}}

# 输入
{ID}:
$ID$

{任务信息}：
$任务信息$

{互动描述}：
$互动描述$

{角色配置}：
$角色配置$

# 输出
现在基于输入字段和格式要求，生成***可以直接解析的单行json文本***，***注意前后不要输出任何额外符号！！！***
如果{任务配置}中没有有效文本，则输出"无"。"""


# ── Step 4: preDialog ──
STEP4_PRE_DIALOG = r"""# 字段内容要求
[ // 从{互动配置}中的【前置对话】中抽取
    {
        "type": "npc",
        "npcName": "xxx",
        "content": "xxxxxxxx"
    },
    {
        "type": "user", // 如果是user则没有npcName
        "content": "xxxxxxxx"
    },
    ......
]

# 输出格式
- 整个输出必须在一行内完成，**不要换行**。
- **不要使用 markdown 代码块**（如 ```json）包裹输出。

样例:
[{"type":"npc","npcName":"Brainy","content":"OK,let's try to the scene the scene together."},{"type":"npc","npcName":"Amy","content":"OK,let's try to the scene the scene together."},{"type":"npc","npcName":"Brainy","content":"OK,let's try to the scene the scene together."}]

# 输入
{互动配置}：
$前置对话$

# 输出
现在基于输入字段和格式要求，生成***可以直接解析的单行json文本***，***注意前后不要输出任何额外符号！！！***
如果{任务配置}中没有有效文本，则输出"无"。"""


# ── Step 6: questionList ──
STEP6_QUESTION_LIST = r"""# 字段内容要求
[ // 从{互动配置}中的内容抽取为下面格式，有几个题目则有几个item
    {
        "desc": "(x)", // 题干中抽取
        "imageInfo": {
            "questionImg": "{ID}_question_{图片编号}.png" // 图片编号从【互动问题】中该小题对应的抽取
        },
        "optionList": [ // 选项中抽取
            {
                 "option": "a"
            },
           {
                 "option": "b"
            },
            ......
        ],
        "answerText": "xxxxx" // 答案中抽取
    },
    ......
]

# 输出格式
- 整个输出必须在一行内完成，**不要换行**。
- **不要使用 markdown 代码块**（如 ```json）包裹输出。

样例:
[{"desc":"(5)","imageInfo":{"questionImg":"012310_question_00.png"},"optionList":[{"option":"o"},{"option":"h"},{"option":"x"},{"option":"P"},{"option":"t"},{"option":"o"},{"option":"k"}],"answerText":"Photo"},{"desc":"(5)","imageInfo":{"questionImg":"012310_question_01.png"},"optionList":[{"option":"m"},{"option":"d"},{"option":"l"},{"option":"q"},{"option":"e"},{"option":"d"},{"option":"m"},{"option":"a"}],"answerText":"medal"},{"desc":"(6)","imageInfo":{"questionImg":"012310_question_02.png"},"optionList":[{"option":"a"},{"option":"j"},{"option":"k"},{"option":"t"},{"option":"e"},{"option":"v"},{"option":"c"},{"option":"z"},{"option":"a"}],"answerText":"jacket"},{"desc":"(5) (4)","imageInfo":{"questionImg":"012310_question_03.png"},"optionList":[{"option":"b"},{"option":"e"},{"option":"t"},{"option":"r"},{"option":"y"},{"option":"a"},{"option":"d"},{"option":"e"},{"option":"t"},{"option":"d"},{"option":"y"}],"answerText":"teddy bear"}]

# 输入
{互动配置}：
$互动问题$

{ID}:
$ID$

# 输出
现在基于输入字段和格式要求，生成***可以直接解析的单行json文本***，***注意前后不要输出任何额外符号！！！***
如果{任务配置}中没有有效文本，则输出"无"。"""


# ── Step 7: studyInfo ──
STEP7_STUDY_INFO = r"""# 字段内容要求
{
    "learningPart": [ // {学习流程配置}中有几个小题则learningPart中有几个元素
    {
        "type": "npc",
        "npcName": "Brainy",
        "content": "xxxx" // {任务信息}里【通关知识】和该小题对应的单词
        "image": "{ID}_question_{两位自增索引}.png"  // 索引从00开始
        "learning": [
        {
            "question": {
                "type": "npc",
                "npcName": "Brainy",
                "content": "xxx", // 抄写题题干
                "desc": "xxx", // {任务信息}里【通关知识】和该小题对应的单词
                "answerText": "xxx",   // {任务信息}里【通关知识】和该小题对应的单词
            },
          "optionList": [ // 单词的所有字母
            {"option": "a"},
            {"option": "b"},
            ......
          ]
    },
    {
            "question": {
                "type": "npc",
                "npcName": "Brainy",
                "content": "xxx", // 听写题题干
                "desc": "（x）", // x为{任务信息}里【通关知识】和该小题对应的单词的字母个数
                "answerText": "xxx",   // {任务信息}里【通关知识】和该小题对应的单词
            },
           "optionList": [ // 单词的所有字母
                {"option": "a"},
                {"option": "b"},
                ......
          ],
          "feedback": {
                "type": "npc",
                "npcName": "Brainy",
                "content": "xxxxxx"
           }
    },
    {
     ......
     "image": "{ID}_question_01.png"
     ......
     },
......
    "closing": { //{学习流程配置}中的 完结反馈中提取
        "type": "npc",
        "npcName": "Brainy",
        "content": "xxxxx"
    }
}

# 输出格式
- 整个输出必须在一行内完成，**不要换行**。
- **不要使用 markdown 代码块**（如 ```json）包裹输出。

样例:
{"learningPart":[{"type":"npc","npcName":"Brainy","content":"Photo","image":"012310_question_00.png","learning":[{"question":{"type":"npc","npcName":"Brainy","content":"如图所示，首先要帮 Sally 整理的物品是「照片」，「照片」的英文是「photo」。先来抄写一下这个词吧！","desc":"Photo","answerText":"Photo"},"optionList":[{"option":"P"},{"option":"h"},{"option":"o"},{"option":"t"},{"option":"o"}]},{"question":{"type":"npc","npcName":"Brainy","content":"很好。接下来，记一下「photo」的拼写，是「p-h-o-t-o」。然后看着图片，试试听写出「照片」这个词吧！","desc":"(5)","answerText":"Photo"},"optionList":[{"option":"P"},{"option":"h"},{"option":"o"},{"option":"t"},{"option":"o"}],"feedback":{"type":"npc","npcName":"Brainy","content":"没错!「照片」对应的英文词汇是「photo」,你的拼写完全正确!"}}]},{"type":"npc","npcName":"Brainy","content":"medal","image":"012310_question_01.png","learning":[{"question":{"type":"npc","npcName":"Brainy","content":" 如图所示，接着要帮 Sally 整理的物品是「奖牌」，「奖牌」的英文是「medal」。先来抄写一下这个词吧！","desc":"medal","answerText":"medal"},"optionList":[{"option":"m"},{"option":"e"},{"option":"d"},{"option":"a"},{"option":"l"}]},{"question":{"type":"npc","npcName":"Brainy","content":"很好。接下来，记一下「medal」的拼写，是「m-e-d-a-l」。然后看着图片，试试听写出「奖牌」这个词吧！","desc":"(5)","answerText":"medal"},"optionList":[{"option":"m"},{"option":"e"},{"option":"d"},{"option":"a"},{"option":"l"}],"feedback":{"type":"npc","npcName":"Brainy","content":"没错！「奖牌」对应的英文词汇是「medal」，你的拼写完全正确！"}}]},{"type":"npc","npcName":"Brainy","content":"jetcak","image":"012310_question_02.png","learning":[{"question":{"type":"npc","npcName":"Brainy","content":" 如图所示，接着要帮 Sally 整理的物品是「奖牌」，「奖牌」的英文是「medal」。先来抄写一下这个词吧！","desc":"jetcak","answerText":"jetcak"},"optionList":[{"option":"j"},{"option":"e"},{"option":"t"},{"option":"c"},{"option":"a"},{"option":"k"}]},{"question":{"type":"npc","npcName":"Brainy","content":"很好。接下来，记一下「medal」的拼写，是「m-e-d-a-l」。然后看着图片，试试听写出「奖牌」这个词吧！","desc":"(6)","answerText":"jetcak"},"optionList":[{"option":"j"},{"option":"e"},{"option":"t"},{"option":"c"},{"option":"a"},{"option":"k"}],"feedback":{"type":"npc","npcName":"Brainy","content":"没错！「夹克」对应的英文词汇是「jetcak」，你的拼写完全正确！"}}]},{"type":"npc","npcName":"Brainy","content":"teddy bear","image":"012310_question_03.png","learning":[{"question":{"type":"npc","npcName":"Brainy","content":"很好。接下来，记一下「medal」的拼写，是「m-e-d-a-l」。然后看着图片，试试听写出「奖牌」这个词吧！","desc":"teddy bear","answerText":"teddy bear"},"optionList":[{"option":"t"},{"option":"e"},{"option":"d"},{"option":"d"},{"option":"y"},{"option":"b"},{"option":"e"},{"option":"a"},{"option":"r"}]},{"question":{"type":"npc","npcName":"Brainy","content":"很好。接下来，记一下「medal」的拼写，是「m-e-d-a-l」。然后看着图片，试试听写出「奖牌」这个词吧！","desc":"(5) (4)","answerText":"teddy bear"},"optionList":[{"option":"t"},{"option":"e"},{"option":"d"},{"option":"d"},{"option":"y"},{"option":"b"},{"option":"e"},{"option":"a"},{"option":"r"}],"feedback":{"type":"npc","npcName":"Brainy","content":"没错！「泰迪熊」对应的英文词汇是「teddy bear」，你的拼写完全正确！"}}]}],"closing":{"type":"npc","npcName":"Brainy","content":"太棒了！你复习了所有的关键知识点，拼对了每一个词，相信下一次你一定可以做得更好！"}}

# 输入
{学习流程配置}：
$学习流程配置$

{任务信息}:
$任务信息$

{ID}:
$ID$

# 输出
现在基于输入字段和格式要求，生成***可以直接解析的单行json文本***，***注意前后不要输出任何额外符号！！！***直接以"{"开头，输出一定保持单行！如果{学习流程配置}中没有有效文本，则输出"无"。"""


# ══════════════════════════════════════════════════════════════════════════════
# Steps Registry & Builder
# ══════════════════════════════════════════════════════════════════════════════

CORE_WRITING_IMGMAKEWORD_STEPS = {
    "step1_learning_flow": {"template": STEP1_LEARNING_FLOW, "description": "学习流程配置", "output_type": "text"},
    "step2_interaction_desc": {"template": STEP2_INTERACTION_DESC, "description": "互动描述", "output_type": "text"},
    "step3_task_info": {"template": STEP3_TASK_INFO, "description": "taskInfo", "output_type": "json"},
    "step4_pre_dialog": {"template": STEP4_PRE_DIALOG, "description": "preDialog", "output_type": "json"},
    "step6_question_list": {"template": STEP6_QUESTION_LIST, "description": "questionList", "output_type": "json"},
    "step7_study_info": {"template": STEP7_STUDY_INFO, "description": "studyInfo", "output_type": "json"},
}


def build_writing_imgmakeword_prompt(step_key, replacements):
    """Build a prompt for a given step by replacing $placeholder$ tokens."""
    info = CORE_WRITING_IMGMAKEWORD_STEPS[step_key]
    prompt = info["template"]
    for key, val in replacements.items():
        prompt = prompt.replace(f"${key}$", str(val) if val else "")
    return prompt
