#!/usr/bin/env python3
"""
看图组句 (core_writing_imgMakeSentence) + 看图撰写 (core_writing_imgWrite) 多步 LLM prompt 模板

两种类型共享相同的输入源格式（图片类stemDesc），差异在于：
- imgMakeSentence: inputType=sentence, textInfo有optionList+answer
- imgWrite: inputType=write, textInfo有answerText+hint

生成流水线（6步）：
  Step 1: 学习流程配置 (intermediate text) — LLM生成选择题巩固练习
  Step 2: 互动描述 (intermediate text) — LLM拼接完整作文+中文翻译
  Step 3: taskInfo → JSON
  Step 4: textInfo → JSON
  Step 5: studyInfo → JSON (依赖 Step1 + Step3)
  Step 6: evalInfo → JSON (依赖 Step3 + Step4)
"""

# ══════════════════════════════════════════════════════════════════════════════
# 看图组句 (core_writing_imgMakeSentence)
# ══════════════════════════════════════════════════════════════════════════════

IMG_MAKE_SENTENCE_STEP1 = r"""你是一名英语学习助手，负责为学习者生成互动式的巩固练习题。
我会提供以下信息：
1. **任务背景**（说明学习场景或对话语境）
2. **任务描述**（说明学习者需要完成的语言目标）
3. **需要巩固的学习内容**（句子、短语、语法点等）
请你根据这些信息生成**一组选择题巩固练习**。每一个学习内容对应一个选择题。
4.**写作材料**（原始题目的相关内容）
生成要求如下：
### 一、输出格式
请严格按照以下格式组织输出：
```
# 问题1：
Brainy: （根据任务背景，生成自然的对话场景或提示，引导用户说出学习内容）
用户选项:
（选项 A）...
  Brainy: ...
（选项 B）...
  Brainy: ...
（选项 C）...
  Brainy: ...
```
其中：
* 每个问题都有一个对话场景，引出该题考察的学习内容。
* 每个问题中：
  * **一个选项为正确答案（即该学习内容）**，在其后标注 `[正确]`。
  * 另外两个为合理但错误的干扰项。
* 每个选项下方由 **Brainy** 给出即时反馈说明该选项是否合适，并说明原因。
* 题目要贴合任务背景，逻辑上前后连贯。
### 二、内容生成规范
1. 所有问题应基于给定的任务背景与任务描述。
2. 每道题的情境应连贯，像一个正在进行的英语对话。
3. 错误选项要**自然合理**，但在语义上与任务目标不符。
4. Brainy 的反馈语气要友好、鼓励性、解释清楚错误原因。
5. 若任务背景中有多个阶段（例如问路、点餐、购物），题目内容应顺着任务情节发展。
6.生成内容所用的词汇尽量参考{写作材料}中的相关词汇，避免难度过高。
### 三、示例输出（参考格式）
```
# 问题1：
Brainy: Ben 是你的老朋友，他提醒你应该记得回家的路。现在你需要问他从车站到家该怎么走。
用户选项:
（选项 A）So how can I get home from the bus stop? [正确]
  Brainy: 太棒了！你正确地询问了从车站到家的路线。
（选项 B）Where should I turn next?
  Brainy: 这句话是询问下一个拐弯的地方，不是询问从车站到家的路线。请再试一次，问清楚从车站到家的路线。
（选项 C）How long does it take to walk home from here?
  Brainy: 这句话是询问步行回家的时间，不是询问从车站到家的路线。请再试一次，问清楚从车站到家的路线。

# 问题2:
Brainy: Ben 告诉了你从车站到家的路线：先直行再左拐，遇到下一个十字路口时右拐。现在你需要问他接下来往哪里拐。
用户选项:
（选项 A）So how can I get home from the bus stop?
  Brainy: 这句话是询问从车站到家的路线，不是询问接下来的拐弯处。请再试一次，问清楚接下来往哪里拐。
（选项 B）Where should I turn next? [正确]
  Brainy: 太棒了！你正确地询问了接下来往哪里拐。
（选项 C）How long does it take to walk home from here?
  Brainy: 这句话是询问步行回家的时间，不是询问接下来的拐弯处。请再试一次，问清楚接下来往哪里拐。
```

#输入
任务背景：
$任务背景$

任务描述：
$任务描述$

写作材料：
$写作材料$

需要巩固的学习内容：
$学习内容$

# 输出
现在请按照上述信息和要求，直接输出目标内容。
如果 {需要巩固的学习内容} 内容为空，则直接输出"无"。"""


IMG_MAKE_SENTENCE_STEP2 = r"""# 任务目标
你是一个儿童英语学习内容生成助手。现在有一个写作组句配置，需要根据规则提取正确内容，并拼接成一篇完整作文。

# 输入信息
* 任务背景：
$任务背景$
* 写作材料：
$写作材料$

# 生成要求
1. **只输出最终拼接后的完整英文作文 + 对应中文翻译（放在括号中）**。
2. **作文由「写作材料」中的所有句子按顺序拼接而成**，提取规则如下：
   * 若「句子类型」为「全句预置」，则选取「句子主干」中的全部文本
   * 若「句子类型」为「全句录入」，则选取「答案」中的全部文本
   * 若「句子类型」为「挖空录入」，则将「句子主干」与「答案」拼接成完整句子
3. **所有句子按顺序组合成一段完整、通顺的英文短文**（中间用空格连接）。
4. **中文翻译需与英文完整对应，语义自然通顺**。
5. **禁止输出任何解释、过程或提示信息**。

# 输出示例
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.（亲爱的凯特，我想在这封信里向你表达感谢。感谢你对我的照顾。我现在必须离开了。咱们假期见。）"""


IMG_MAKE_SENTENCE_STEP3 = r"""# 字段内容要求
{
    "cId": {ID},
    "cType": "core_writing_imgMakeSentence",
    "title": {任务信息}中的任务名称,
    "taskDesc": {任务信息}中的任务描述,
    "sceneDesc": {任务信息}中的任务背景,
    "img": "", //固定
    "plotSummary": {任务信息}中的剧情提要, //不一定有，如果没有则为""
    "stemDesc":, // 是[{ID}-00.png、{ID}-01.png...]，编号按照顺序从上到下从{写作材料}中每个句子后的图片编号获取。可能为乱序，即出现的先后顺序为00、02、01等。名字重复后只保留一个即可。
    "key": [ // {知识}中的知识，英文内容为知识点内容，中文为知识点解释，中间用空格分开
        {
            "keyList": [
                {
                    "type": "default", //固定
                    "content": 知识点内容（英文部分）,
                    "desc": 知识点解释（中文部分，如果是单词前面会带有英文缩写的词性标识）
                },
                 ... ...
            ]
        },
        ...
    ],
    "cDesc": "xxx", // {互动描述}的全部内容
}

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

样例:
{"cId":"0110005","cType":"core_writing_imgMakeSentence","title":"提供关于 Medic 的情报","taskDesc":"快速回答唐先生关于 Medic 的特点，包括其强壮、力量大、速度快以及可能的弱点。","sceneDesc":"唐先生为了确保与 Medic 的对决万无一失，请求你提供尽可能多的关于 Medic 的情报。你与 Otis 等探讨了，总结出 Medic 的一些特点，准备与唐先生分享。","img":"","plotSummary":"剧情提要，内容可选","stemDesc":["0101001-00.png","0101001-01.png","0101001-02.png"],"key":[{"keyList":[{"type":"default","content":"Medic is too strong.","desc":"Medic 太强壮了。"},{"type":"default","content":"Medic is powerful.","desc":"Medic 力量很大。"},{"type":"default","content":"Medic is very fast.","desc":"Medic 速度很快。"}]},{"keyList":[{"type":"default","content":"I think you can ...","desc":"我认为你可以 ......"}]}],"cDesc":"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.（亲爱的凯特，我想在这封信里向你表达感谢。感谢你对我的照顾。我现在必须离开了。咱们假期见。）"}

# 输入
{ID}:
$ID$

{题目类型}：
$题目类型$

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

{知识}:
$知识$

{写作材料}:
$写作材料$

{互动描述}:
$互动描述$

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


IMG_MAKE_SENTENCE_STEP4 = r"""# 字段内容要求
{
    "inputType": "sentence",
    "passCondition": {通过规则}中的通过规则,
    "textList": [{ //{写作材料}中的写作材料,一个句子占一个{}
        "mode": "", // 句子中的句子类型，对应关系为：预置句子：preset，全句录入：universalInput，挖空录入：fillingInput
        "desc": "", // 当"mode"为preset或fillingInput时，为句子中的句子主干，当"mode"为universalInput时无该字段
        "optionList": [ // 当"mode"为universalInput或fillingInput时才有该字段，内容为句子内容中的选项，不要改变其原有顺序！
            {
                "option": "you"
            },
            {
                "option": "how"
            },
            {
                "option": "are"
            },
            {
                "option": "wow"
            },
            {
                "option": "wawa"
            }
        ],
        "answer": [1, 2, 0], // 根据{写作材料}中的答案生成正确的顺序索引，从0开始。干扰项在{写作材料}中已经明确标出，例如：[干扰]：sunshine，没有"[干扰]："的为正确选项，注意不能漏掉任何一个正确选项！
    }
    ...
    ]
}

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

样例:
{"inputType":"sentence","passCondition":"用户写出：1. 坠机在一个湖附近 2. 湖周边树木有红黄色的叶子 3. Bam 听到东北方向的噪音","textList":[{"mode":"preset","desc":"Dear Alex,"},{"mode":"universalInput","optionList":[{"option":"well"},{"option":"this email"},{"option":"you"},{"option":"finds"},{"option":"I hope"},{"option":"fine"}],"answer":[4,1,3,2,0]},{"mode":"fillingInput","desc":"We can ___ each other.","optionList":[{"option":"of"},{"option":"take"},{"option":"care"},{"option":"look"},{"option":"for"}],"answer":[1,2,0]}]}

# 输入
{通过规则}：
$通过规则$

{写作材料}
$写作材料$

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


IMG_MAKE_SENTENCE_STEP5 = r"""# 字段内容要求
{
    "learningPart": [ // 对应{taskInfo}中的stemDesc，{学习流程配置}中有几个题目则learningPart中有几个元素
    {
        "leadIn": {  // 每个题目都有独立的"leadIn"，如果遇到多个题目对应的"image"相同，则"leadIn"需要重复。
            "image": "0000004-00.png", // 内容按照{学习内容}中的末尾的图片尾号的对应关系进行关联。如果两个题目对应的图片相同，这部分也不可省略，要保证完整的"leadIn"和"learning"结构。
        },
        "learning": [{ // 对应{学习流程配置}中的问题，按照顺序依次提取
            "question": {
                "type": "npc",
                "npcName": "Brainy",
                "content": "what are you nong sha lie?"  //{学习流程配置}中问题下Brainy说的话
            },
            "optionList": [{
                "option": "Medic is too strong.", // 问题下的选项
                "feedback": {
                    "type": "npc",
                    "npcName": "Brainy",
                    "content": "太棒了！你正确地描述了Medic的力量非常强大。请大声朗读这句话！"//每个选项下Brainy的话
                }
            }, {
                "option": "Medic is very fast.", // 问题下的选项
                "feedback": {
                    "type": "npc",
                    "npcName": "Brainy",
                    "content": "这句话是描述Medic的速度，而不是力量。请再试一次，描述Medic的力量。" //每个选项下Brainy的话
                }
            }, {
                "option": "I think you can kick his back.", // 问题下的选项
                "feedback": {
                    "type": "npc",
                    "npcName": "Brainy",
                    "content": "这句话是描述Medic的弱点，而不是力量。请再试一次，描述Medic的力量。" //每个选项下Brainy的话
                }
            }],
            "answer": [0], // 带有"[正确]"标识的选项对应的索引，从0开始
            "write": { // 选对之后要抄写的句子
                "desc": "Medic is too strong.", // 正确选项
                "trans":"" // 需要生成正确选项的中文翻译
            },
            "feedback": {
                "type": "npc",
                "npcName": "Brainy",
                "content": "你写的很好！"
            }
        }]
    },
    ...
    ],
    "closing": {
        "type": "npc",
        "npcName": "Brainy",
        "content": "恭喜你，可以使用准确的单词 sandwich;短语 cook byhimself、take care of; 以及句型 He found sb doingsth，描述了三张图中的各个细节!" //根据{学习内容}中的知识总结一下巩固的内容。
    }
}

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

样例:
{"learningPart":[{"leadIn":{"image":"0000004-00.png"},"learning":[{"question":{"type":"npc","npcName":"Brainy","content":"你们正在准备给Luisa教授写求救报告的开头。按照正式邮件的惯例，你需要先写一句问候语表达关心。"},"optionList":[{"option":"Dear Alex,","feedback":{"type":"npc","npcName":"Brainy","content":"这是一个称呼，虽然正确但缺少后续的问候内容。我们需要完整的问候句子。"}},{"option":"I hope this email finds you well.","feedback":{"type":"npc","npcName":"Brainy","content":"完美！这是标准的英文邮件开头问候语，礼貌且正式，非常适合写给教授的求救报告。"}},{"option":"How are you today?","feedback":{"type":"npc","npcName":"Brainy","content":"这个问候比较口语化，通常用于朋友之间。写给教授的正式报告最好使用更正式的表达。"}}],"answer":[1],"write":{"desc":"I hope this email finds you well.","trans":"希望您收到这封邮件时一切安好。"},"feedback":{"type":"npc","npcName":"Brainy","content":"你写的很好！"}}]},{"leadIn":{"image":"0000004-01.png"},"learning":[{"question":{"type":"npc","npcName":"Brainy","content":"在报告中，你们需要说明团队成员会互相帮助，共同克服困难。请选择正确的短语来表达"互相照顾"。"},"optionList":[{"option":"look for each other","feedback":{"type":"npc","npcName":"Brainy","content":"这个短语的意思是"寻找彼此"，而不是"互相照顾"。意思不符合当前处境。"}},{"option":"take care of","feedback":{"type":"npc","npcName":"Brainy","content":"正确！"take care of" 表示"照顾、照料"，完整表达\"We can take care of each other\"意思是"我们可以互相照顾"。"}},{"option":"care of take","feedback":{"type":"npc","npcName":"Brainy","content":"单词顺序错误。英语中固定短语\"take care of\"的顺序不能改变。"}}],"answer":[1],"write":{"desc":"take care of","trans":"照顾；照料"},"feedback":{"type":"npc","npcName":"Brainy","content":"你写的很好！"}}]}],"closing":{"type":"npc","npcName":"Brainy","content":"恭喜你，可以使用准确的短语 I hope this email finds you well 和 take care of，完成了求救报告中的问候和团队互助部分的写作！"}}

# 输入
{taskInfo}：
$taskInfo$

{学习流程配置}：
$学习流程配置$

{学习内容}：
$学习内容$

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


IMG_MAKE_SENTENCE_STEP6 = r"""# 字段内容要求
{
    "title": {taskInfo}中的"title",
    "taskDesc": {taskInfo}中的"taskDesc",
    "sceneDesc": {taskInfo}中的"sceneDesc",
    "knowledge": {任务信息}中的知识，
    "passCondition": {textInfo}中的"passCondition",
    "textList": {textInfo}中的"textList"
}

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

样例:
{"title":"分析飞船坠毁信号来源","taskDesc":"根据收到的信号特征，用英语撰写一段报告，说明信号的方向、环境特征及你的判断。","sceneDesc":"Luisa 教授在分析卫星数据时，发现一个可能与飞船坠毁相关的电磁信号。你、Otis 和 Skylar 被派去分析这个信号的来源并撰写报告。","knowledge":"- 信号分析表达 I think the signal came from... 我认为信号来自…… It was near... 它位于……附近。 The sound was... 声音是……。","passCondition":"用户写出：1. 坠机在一个湖附近 2. 湖周边树木有红黄色的叶子 3. Bam 听到东北方向的噪音","textList":[{"mode":"preset","desc":"Dear Alex,"},{"mode":"universalInput","optionList":[{"option":"well"},{"option":"this email"},{"option":"you"},{"option":"finds"},{"option":"I hope"},{"option":"fine"}],"answer":[4,1,3,2,0]},{"mode":"fillingInput","desc":"We can ___ each other.","optionList":[{"option":"of"},{"option":"take"},{"option":"care"},{"option":"look"},{"option":"for"}],"answer":[1,2,0]}]}

# 输入
{taskInfo}:
$taskInfo$

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

{textInfo}:
$textInfo$

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


# ══════════════════════════════════════════════════════════════════════════════
# 看图撰写 (core_writing_imgWrite)
# ══════════════════════════════════════════════════════════════════════════════

IMG_WRITE_STEP1 = r"""你是一名英语学习助手，负责为学习者生成互动式的巩固练习题。
我会提供以下信息：
1. **任务背景**（说明学习场景或对话语境）
2. **任务描述**（说明学习者需要完成的语言目标）
3. **需要巩固的学习内容**（句子、短语、语法点等）
请你根据这些信息生成**一组选择题巩固练习**。每一个学习内容对应一个选择题。
4.**写作材料**（原始题目的相关内容）
生成要求如下：
### 一、输出格式
请严格按照以下格式组织输出：
```
# 问题1：
Brainy: （根据任务背景，生成自然的对话场景或提示，引导用户说出学习内容）
用户选项:
（选项 A）...
  Brainy: ...
（选项 B）...
  Brainy: ...
（选项 C）...
  Brainy: ...
```
其中：
* 每个问题都有一个对话场景，引出该题考察的学习内容。
* 每个问题中：
  * **一个选项为正确答案（即该学习内容）**，在其后标注 `[正确]`。
  * 另外两个为合理但错误的干扰项。
* 每个选项下方由 **Brainy** 给出即时反馈说明该选项是否合适，并说明原因。
* 题目要贴合任务背景，逻辑上前后连贯。
### 二、内容生成规范
1. 所有问题应基于给定的任务背景与任务描述。
2. 每道题的情境应连贯，像一个正在进行的英语对话。
3. 错误选项要**自然合理**，但在语义上与任务目标不符。
4. Brainy 的反馈语气要友好、鼓励性、解释清楚错误原因。
5. 若任务背景中有多个阶段（例如问路、点餐、购物），题目内容应顺着任务情节发展。
6.生成内容所用的词汇尽量参考{写作材料}中的相关词汇，避免难度过高。
### 三、示例输出（参考格式）
```
# 问题1：
Brainy: Ben 是你的老朋友，他提醒你应该记得回家的路。现在你需要问他从车站到家该怎么走。
用户选项:
（选项 A）So how can I get home from the bus stop? [正确]
  Brainy: 太棒了！你正确地询问了从车站到家的路线。
（选项 B）Where should I turn next?
  Brainy: 这句话是询问下一个拐弯的地方，不是询问从车站到家的路线。请再试一次，问清楚从车站到家的路线。
（选项 C）How long does it take to walk home from here?
  Brainy: 这句话是询问步行回家的时间，不是询问从车站到家的路线。请再试一次，问清楚从车站到家的路线。

# 问题2:
Brainy: Ben 告诉了你从车站到家的路线：先直行再左拐，遇到下一个十字路口时右拐。现在你需要问他接下来往哪里拐。
用户选项:
（选项 A）So how can I get home from the bus stop?
  Brainy: 这句话是询问从车站到家的路线，不是询问接下来的拐弯处。请再试一次，问清楚接下来往哪里拐。
（选项 B）Where should I turn next? [正确]
  Brainy: 太棒了！你正确地询问了接下来往哪里拐。
（选项 C）How long does it take to walk home from here?
  Brainy: 这句话是询问步行回家的时间，不是询问接下来的拐弯处。请再试一次，问清楚接下来往哪里拐。
```

#输入
任务背景：
$任务背景$

任务描述：
$任务描述$

写作材料：
$写作材料$

需要巩固的学习内容：
$学习内容$

# 输出
现在请按照上述信息和要求，直接输出目标内容。
如果 {需要巩固的学习内容} 内容为空，则直接输出"无"。"""


IMG_WRITE_STEP2 = r"""# 任务目标
你是一个儿童英语学习内容生成助手。现在有一个写作组句配置，需要根据规则提取正确内容，并拼接成一篇完整作文。

# 输入信息
* 任务背景：
$任务背景$
* 写作材料：
$写作材料$

# 生成要求
1. **只输出最终拼接后的完整英文作文 + 对应中文翻译（放在括号中）**。
2. **作文由「写作材料」中的所有句子按顺序拼接而成**，提取规则如下：
  - 若「句子类型」为「全句预置」，则选取「句子主干」中的全部文本
  - 若「句子类型」为「全句录入」，则选取「参考答案」中的全部文本
  - 若「句子类型」为「挖空录入」，则选取「句子主干」与「参考答案」拼合成的全部文本
3. **所有句子按顺序组合成一段完整、通顺的英文短文**（中间用空格连接）。
4. **中文翻译需与英文完整对应，语义自然通顺**。
5. **禁止输出任何解释、过程或提示信息**。

# 输出示例
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.（亲爱的凯特，我想在这封信里向你表达感谢。感谢你对我的照顾。我现在必须离开了。咱们假期见。）"""


IMG_WRITE_STEP3 = r"""# 字段内容要求
{
    "cId": {ID},
    "cType": "core_writing_imgWrite",
    "title": {任务信息}中的任务名称,
    "taskDesc": {任务信息}中的任务描述,
    "sceneDesc": {任务信息}中的任务背景,
    "img": "", //固定
    "plotSummary": {任务信息}中的剧情提要, //不一定有，如果没有则为""
    "stemDesc":, // 是[{ID}-00.png、{ID}-01.png...]，编号按照顺序从上到下从{写作材料}中每个句子后的图片编号获取。可能为乱序，即出现的先后顺序为00、02、01等。名字重复后只保留一个即可。
    "key": [ // {知识}中的知识，英文内容为知识点内容，中文为知识点解释，中间用空格分开
        {
            "keyList": [
                {
                    "type": "default", //固定
                    "content": 知识点内容（英文部分）,
                    "desc": 知识点解释（中文部分，如果是单词前面会带有英文缩写的词性标识）
                },
                 ... ...
            ]
        },
        ...
    ],
    "cDesc": "xxx", // {互动描述}的全部内容
}

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

样例:
{"cId":"9900007","cType":"core_writing_imgWrite","title":"报告雪山求救事件","taskDesc":"请根据图片内容，用英文写一段求救报告，说明你们现在的处境、遇到的困难和需要的帮助。","sceneDesc":"在前往北方山区的探索任务中，你与 Otis、Skylar 被突如其来的暴风雪困在一处山洞里。外界信号微弱，你们必须通过求救信号装置发出一份简短的求救报告，让救援队了解你们的状况。","img":"","plotSummary":"The snowstorm is getting worse. We are hiding in a cave and trying to keep warm.","stemDesc":["9900007-00.png","9900007-02.png","9900007-01.png"],"key":[{"keyList":[{"type":"default","content":"We are hiding in a cave to escape the terrible snowstorm.","desc":"我们正在一个山洞里避开可怕的暴风雪。"},{"type":"default","content":"We have dressed ourselves, but our clothes are not keeping us warm.","desc":"我们穿上了所有衣服，但仍然感到寒冷。"},{"type":"default","content":"My friend has a terrible headache, so please bring some medicine.","desc":"我的朋友头痛得厉害，请带些药来。"}]}],"cDesc":"You pressed the clean button on the drone. (你按下了无人机的清理按键。)"}

# 输入
{ID}:
$ID$

{题目类型}：
$题目类型$

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

{知识}:
$知识$

{写作材料}:
$写作材料$

{互动描述}:
$互动描述$

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


IMG_WRITE_STEP4 = r"""# 字段内容要求
{
    "inputType": "write",
    "passCondition": {通过规则}中的通过规则,
    "textList": [{ //{写作材料}中的写作材料,一个句子占一个{}
        "mode": "", // 句子中的句子类型，对应关系为：预置句子：preset，全句录入：universalInput，挖空录入：fillingInput
        "desc": "", // 当"mode"为preset或fillingInput时，为句子中的句子主干，当"mode"为universalInput时无该字段
        "answerText":"" // 句子内容中的答案
        "hint": "", // 当mode为universalInput时，为answerText的中文翻译加原始英文，格式为中文（英文）。当mode为fillingInput时，为整句话的翻译，但在需要填空的词或短语后面加上中文，中文用括号括起来。
    }
    ...
    ]
}

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

样例:
{"inputType":"write","passCondition":"能正确描述所在位置与天气。能说明身体或衣物方面的困难。能清楚表达求助请求。","textList":[{"mode":"preset","desc":"Dear Rescue Team,"},{"mode":"universalInput","answerText":"We are hiding in a cave to escape the terrible snowstorm.","hint":"我们躲在一个洞穴里以躲避可怕的暴风雪（We are hiding in a cave to escape the terrible snowstorm.）"},{"mode":"fillingInput","desc":"We have ___ ourselves, but our clothes are not keeping us warm.","answerText":"dressed","hint":"我们已经穿好（dressed）衣服，但我们的衣服不能让我们保持温暖。"},{"mode":"universalInput","answerText":"My friend has a terrible headache, so please bring some medicine.","hint":"我的朋友头痛得厉害，所以请带些药来（My friend has a terrible headache, so please bring some medicine.）"},{"mode":"preset","desc":"Thank you for your help."}]}

# 输入
{通过规则}：
$通过规则$

{写作材料}
$写作材料$

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


IMG_WRITE_STEP5 = r"""# 字段内容要求
{
    "learningPart": [ // 对应{taskInfo}中的stemDesc，{学习流程配置}中有几个题目则learningPart中有几个元素
    {
        "leadIn": {  // 每个题目都有独立的"leadIn"，如果遇到多个题目对应的"image"相同，则"leadIn"需要重复。
            "image": "0000004-00.png", // 内容按照{学习内容}中的末尾的图片尾号的对应关系进行关联。如果两个题目对应的图片相同，这部分也不可省略，要保证完整的"leadIn"和"learning"结构。
        },
        "learning": [{ // 对应{学习流程配置}中的问题，按照顺序依次提取
            "question": {
                "type": "npc",
                "npcName": "Brainy",
                "content": "what are you nong sha lie?"  //{学习流程配置}中问题下Brainy说的话
            },
            "optionList": [{
                "option": "Medic is too strong.", // 问题下的选项
                "feedback": {
                    "type": "npc",
                    "npcName": "Brainy",
                    "content": "太棒了！你正确地描述了Medic的力量非常强大。请大声朗读这句话！"//每个选项下Brainy的话
                }
            }, {
                "option": "Medic is very fast.", // 问题下的选项
                "feedback": {
                    "type": "npc",
                    "npcName": "Brainy",
                    "content": "这句话是描述Medic的速度，而不是力量。请再试一次，描述Medic的力量。" //每个选项下Brainy的话
                }
            }, {
                "option": "I think you can kick his back.", // 问题下的选项
                "feedback": {
                    "type": "npc",
                    "npcName": "Brainy",
                    "content": "这句话是描述Medic的弱点，而不是力量。请再试一次，描述Medic的力量。" //每个选项下Brainy的话
                }
            }],
            "answer": [0], // 带有"[正确]"标识的选项对应的索引，从0开始
            "write": { // 选对之后要抄写的句子
                "desc": "Medic is too strong.", // 正确选项
                "trans":"" // 需要生成正确选项的中文翻译
            },
            "feedback": {
                "type": "npc",
                "npcName": "Brainy",
                "content": "你写的很好！"
            }
        }]
    },
    ...
    ],
    "closing": {
        "type": "npc",
        "npcName": "Brainy",
        "content": "恭喜你，可以使用准确的单词 sandwich;短语 cook byhimself、take care of; 以及句型 He found sb doingsth，描述了三张图中的各个细节!" //根据{学习内容}中的知识总结一下巩固的内容，注意"leadIn"中有"image"字段时才是图片。
    }
}

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

样例:
{"learningPart":[{"leadIn":{"image":"9900007-00.png"},"learning":[{"question":{"type":"npc","npcName":"Brainy","content":"暴风雪越来越猛烈了！我们需要告诉救援队我们现在在哪里躲避。请选择一个最合适的句子来描述我们的藏身之处。"},"optionList":[{"option":"We are hiding in a cave to escape the terrible snowstorm.","feedback":{"type":"npc","npcName":"Brainy","content":"完美！这句话清楚地说明了我们正在山洞里躲避暴风雪，准确地描述了我们的处境。"}},{"option":"We are walking through the snowstorm to find help.","feedback":{"type":"npc","npcName":"Brainy","content":"这个选项不太合适，因为我们实际上是在山洞里躲避，而不是在暴风雪中行走。请再试一次！"}},{"option":"We are waiting inside the car for the storm to stop.","feedback":{"type":"npc","npcName":"Brainy","content":"这个选项不正确，因为背景中我们是在山洞里，而不是在车里。请选择描述我们实际藏身地的句子。"}}],"answer":[0],"write":{"desc":"We are hiding in a cave to escape the terrible snowstorm.","trans":"我们正在一个山洞里避开可怕的暴风雪。"},"feedback":{"type":"npc","npcName":"Brainy","content":"你写的很好！"}}]},{"leadIn":{"image":"9900007-01.png"},"learning":[{"question":{"type":"npc","npcName":"Brainy","content":"Otis 的情况不太好，他头疼得厉害。我们需要在求救报告中说明队友的健康问题和所需的药品。哪个选项能准确表达这个意思？"},"optionList":[{"option":"My friend is very hungry and needs some food.","feedback":{"type":"npc","npcName":"Brainy","content":"这个选项说的是饥饿，但我们需要的是表达头痛和需要药品的情况。请再试一次！"}},{"option":"My friend has a terrible headache, so please bring some medicine.","feedback":{"type":"npc","npcName":"Brainy","content":"太棒了！你正确地表达了队友头痛严重，并明确请求带来药品，这能帮助救援队了解我们的紧急需求。"}},{"option":"My friend is feeling cold and needs a blanket.","feedback":{"type":"npc","npcName":"Brainy","content":"这个选项提到了寒冷，但没有准确表达头痛和需要药品的具体问题。请选择更贴切的句子。"}}],"answer":[1],"write":{"desc":"My friend has a terrible headache, so please bring some medicine.","trans":"我的朋友头痛得厉害，请带些药来。"},"feedback":{"type":"npc","npcName":"Brainy","content":"你写的很好！"}}]}],"closing":{"type":"npc","npcName":"Brainy","content":"恭喜你，可以使用准确的短语 hiding in a cave、escape the terrible snowstorm、have a terrible headache、bring some medicine、dressed ourselves、not keeping us warm，描述了三张图中的各个细节!"}}

# 输入
{taskInfo}：
$taskInfo$

{学习流程配置}：
$学习流程配置$

{学习内容}：
$学习内容$

# 输出
现在基于输入字段和格式要求，生成***可以直接解析的单行json文本***，***注意前后不要输出任何额外符号！！！***直接以"{"开头，***learning中optionList中的feedback中的npcName必须是：Brainy，并且结构严格按照npcName:"Brainy"执行。***，输出一定保持单行！如果{学习流程配置}中没有有效文本，则输出"无"。"""


IMG_WRITE_STEP6 = r"""# 字段内容要求
{
    "title": {taskInfo}中的"title",
    "taskDesc": {taskInfo}中的"taskDesc",
    "sceneDesc": {taskInfo}中的"sceneDesc",
    "knowledge": {任务信息}中的知识，
    "passCondition": {textInfo}中的"passCondition",
    "textList": {textInfo}中的"textList"
}

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

样例:
{"title":"分析飞船坠毁信号来源","taskDesc":"根据收到的信号特征，用英语撰写一段报告，说明信号的方向、环境特征及你的判断。","sceneDesc":"Luisa 教授在分析卫星数据时，发现一个可能与飞船坠毁相关的电磁信号。你、Otis 和 Skylar 被派去分析这个信号的来源并撰写报告。","knowledge":"- 信号分析表达 I think the signal came from... 我认为信号来自…… It was near... 它位于……附近。 The sound was... 声音是……。","passCondition":"能正确描述所在位置与天气。能说明身体或衣物方面的困难。能清楚表达求助请求。","textList":[{"mode":"preset","desc":"Dear Professor Luisa,"},{"mode":"universalInput","answerText":"We found that the strange signal came from the north side of the mountain.","hint":"我们发现奇怪的信号来自山的北侧（We found that the strange signal came from the north side of the mountain.）"},{"mode":"fillingInput","desc":"The sound was very ___ and repeated every few seconds.","answerText":"weak","hint":"声音非常微弱（weak）并且每隔几秒重复一次。"}]}

# 输入
{taskInfo}:
$taskInfo$

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

{textInfo}:
$textInfo$

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


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

CORE_WRITING_IMG_MAKE_SENTENCE_STEPS = {
    "step1_learning_flow": {"template": IMG_MAKE_SENTENCE_STEP1, "description": "学习流程配置", "output_type": "text"},
    "step2_interaction_desc": {"template": IMG_MAKE_SENTENCE_STEP2, "description": "互动描述", "output_type": "text"},
    "step3_task_info": {"template": IMG_MAKE_SENTENCE_STEP3, "description": "taskInfo", "output_type": "json"},
    "step4_text_info": {"template": IMG_MAKE_SENTENCE_STEP4, "description": "textInfo", "output_type": "json"},
    "step5_study_info": {"template": IMG_MAKE_SENTENCE_STEP5, "description": "studyInfo", "output_type": "json"},
    "step6_eval_info": {"template": IMG_MAKE_SENTENCE_STEP6, "description": "evalInfo", "output_type": "json"},
}

CORE_WRITING_IMG_WRITE_STEPS = {
    "step1_learning_flow": {"template": IMG_WRITE_STEP1, "description": "学习流程配置", "output_type": "text"},
    "step2_interaction_desc": {"template": IMG_WRITE_STEP2, "description": "互动描述", "output_type": "text"},
    "step3_task_info": {"template": IMG_WRITE_STEP3, "description": "taskInfo", "output_type": "json"},
    "step4_text_info": {"template": IMG_WRITE_STEP4, "description": "textInfo", "output_type": "json"},
    "step5_study_info": {"template": IMG_WRITE_STEP5, "description": "studyInfo", "output_type": "json"},
    "step6_eval_info": {"template": IMG_WRITE_STEP6, "description": "evalInfo", "output_type": "json"},
}


def build_writing_img_prompt(ctype, step_key, replacements):
    """Build a prompt for a given step by replacing $placeholder$ tokens.

    Args:
        ctype: "core_writing_imgMakeSentence" or "core_writing_imgWrite"
        step_key: e.g. "step1_learning_flow"
        replacements: dict of placeholder -> value
    """
    if ctype == "core_writing_imgMakeSentence":
        steps = CORE_WRITING_IMG_MAKE_SENTENCE_STEPS
    else:
        steps = CORE_WRITING_IMG_WRITE_STEPS

    info = steps[step_key]
    prompt = info["template"]
    for key, val in replacements.items():
        prompt = prompt.replace(f"${key}$", str(val) if val else "")
    return prompt
