#!/usr/bin/env python3
"""
Per-component-type prompt templates registry.
Each prompt follows the PRD v2 spec: exact field definitions, extraction rules, output format, and sample.

Usage:
    from prompts.prompt_registry import get_prompt_template, get_input_fields
    tpl = get_prompt_template("mid_dialog_repeat")
    fields = get_input_fields("mid_dialog_repeat")
"""

# ============================================================
# 教研配置文本 → 结构化字段 解析
# ============================================================

# 所有可能的教研配置 section 标记
SECTION_MARKERS = [
    "任务标题", "标题",
    "资源配置",
    "情境引入",
    "互动内容",
    "互动反馈",
    "后置对话",
    "互动描述",
    "学习意义构建",
    "语音识别热词",
]

import re

def parse_teaching_config_fields(teaching_config):
    """
    从教研配置文本中提取结构化字段。

    教研配置格式:
        【任务标题】
        表示大家一起上学

        【资源配置】
        图片时机：互动内容

        【情境引入】
        User: Great!

        【互动内容】
        User: Let's go to school now. (朗读)

        【后置对话】
        无

    Returns:
        dict: {
            "标题": "表示大家一起上学",
            "资源配置": "图片时机：\n互动内容",
            "情境引入": "User: Great!",
            "互动内容": "User: Let's go to school now. (朗读)",
            "后置对话": "无",
            ...
        }
    """
    fields = {}
    # Build regex to split on 【xxx】 markers
    pattern = re.compile(r'【([^】]+)】')
    parts = pattern.split(teaching_config)

    # parts = [before_first_marker, marker1, content1, marker2, content2, ...]
    i = 1  # skip content before first marker
    while i < len(parts) - 1:
        key = parts[i].strip()
        value = parts[i + 1].strip()
        # Normalize key names — 同时保留原名和别名
        if key in ("任务标题", "标题"):
            fields["标题"] = value
            fields["任务标题"] = value
        else:
            fields[key] = value
        i += 2

    return fields


# ============================================================
# Input field definitions per component type
# ============================================================

# Maps cType → list of input field names that should be extracted
# and passed as {field} placeholders in the prompt
INPUT_FIELDS = {
    "mid_dialog_repeat": ["ID", "标题", "情境引入", "互动内容", "后置对话", "角色配置", "资源配置"],
    "mid_dialog_express": ["ID", "标题", "情境引入", "互动内容", "后置对话", "角色配置", "互动反馈", "语音识别热词", "资源配置"],
    "mid_dialog_choose": ["ID", "标题", "情境引入", "互动内容", "后置对话", "角色配置", "资源配置"],
    "mid_dialog_select": ["ID", "标题", "情境引入", "互动内容", "后置对话", "角色配置", "资源配置"],
    "mid_dialog_fillin": ["ID", "标题", "情境引入", "互动内容", "后置对话", "角色配置", "资源配置", "互动反馈"],
    "mid_dialog_sentence": ["ID", "标题", "情境引入", "互动内容", "后置对话", "角色配置", "互动反馈", "资源配置"],
    "mid_message_trace": ["ID", "标题", "互动内容", "互动描述", "角色配置"],
    "mid_message_spell": ["ID", "标题", "互动内容", "互动描述", "角色配置"],
    "mid_message_combine": ["ID", "标题", "互动内容", "互动描述", "角色配置"],
    "mid_message_fillin": ["ID", "标题", "互动内容", "互动描述", "角色配置"],
    "mid_message_word": ["ID", "标题", "互动内容", "互动描述", "角色配置"],
    "mid_message_sentence": ["ID", "标题", "互动内容", "互动描述", "角色配置"],
    "mid_image_choose": ["ID", "标题", "情境引入", "互动内容", "互动反馈", "后置对话", "学习意义构建", "角色配置", "互动描述"],
    "mid_image_multiple": ["ID", "标题", "情境引入", "互动内容", "互动反馈", "后置对话", "学习意义构建", "角色配置", "互动描述"],
    "mid_image_sequence": ["ID", "标题", "情境引入", "互动内容", "互动反馈", "后置对话", "学习意义构建", "角色配置", "互动描述"],
    "mid_image_drag": ["ID", "标题", "情境引入", "互动内容", "互动反馈", "后置对话", "学习意义构建", "角色配置", "互动描述"],
}


def get_input_fields(cType):
    """Get the list of input field names for a given cType."""
    return INPUT_FIELDS.get(cType, ["ID", "标题", "互动内容"])


def build_input_section(cType, cId, parsed_fields, resource_mapping_str=""):
    """
    Build the # 输入 section text for the prompt.

    Args:
        cType: component type
        cId: component ID
        parsed_fields: dict from parse_teaching_config_fields()
        resource_mapping_str: pre-formatted角色配置 string like "663-EVA, 653-peter, 658-Vicky"

    Returns:
        str: formatted input section
    """
    field_names = get_input_fields(cType)
    parts = []
    for field_name in field_names:
        if field_name == "ID":
            parts.append(f"{{ID}}: {cId}")
        elif field_name == "角色配置":
            parts.append(f"{{角色配置}}: {resource_mapping_str}")
        else:
            value = parsed_fields.get(field_name, "无")
            if not value:
                value = "无"
            parts.append(f"{{{field_name}}}: {value}")
    return "\n\n".join(parts)


# ============================================================
# Prompt templates — one per component type
# ============================================================

PROMPT_TEMPLATES = {}

# ---------- 对话朗读 ----------
PROMPT_TEMPLATES["mid_dialog_repeat"] = r"""# 字段内容要求
{
    "cType": "mid_dialog_repeat", //固定
    "cId": "{ID}", // 字符串类型
    "title": {标题}, 
    "resourceMapping"(抽取出{角色配置}中的全部 name:id映射，id必须为int类型。如果{角色配置}为空，则该字段为空): {"name":id, "name":id} // 样例：{"Ben":465, "Otis":234}
    "preDialog"(基于{情境引入}抽取，可为空): [
        {
            "type": "npc",
            "npcName": "xxx",
            "content": "xxx"
        },
        {
            "type": "user",
            "content": "xxx"
        },
        ...
    ],
    "imgShowTimingList"(从{资源配置}中抽取，对应关系为：preDialog:情境引入、content:互动内容、feedback:互动反馈、postDialog:后置对话，如果为无则为空[]):["preDialog", "content", "feedback", "postDialog"],
    "img"({资源配置}中存在图片时机时才有该字段): "{ID}.png", 
    "audioFile"({资源配置}中存在音频载体时才有该字段): "{ID}.mp3",     
    "itemName"({资源配置}中存在音频载体时才有该字段，内容从音频载体中抽取): "xxxxx",
    "question"(基于{互动内容}抽取，"(朗读)"这两个字不用抽取): {        
        "type": "user",
        "content": "xxx"
    },
    "postDialog"(基于{后置对话}抽取，可为空): [
        {
            "type": "npc",
            "npcName": "xxx",
            "content": "xxx"
        },
        ...
    ]
}

# 输出格式:
- 整个输出必须在一行内完成，**不要换行**。
- **不要使用 markdown 代码块**（如 ```json）包裹输出。
- 输出内容必须是合法的 JSON 格式，可直接用于 JSON.parse

样例:
{"cType":"mid_dialog_repeat","cId":"0000037","title":"表达感谢","resourceMapping":{"Ben":465,"Otis":234},"preDialog":[{"type":"user","content":"And now, I've got a question ready for you."},{"type":"npc","npcName":"Otis","content":"What's that?"},{"type":"user","content":"It's about pirates."}],"imgShowTimingList":["content","feedback"],"img":"0000037.png","question":{"type":"user","content":"Thanks for helping me."},"postDialog":[{"type":"npc","npcName":"Otis","content":"I guess there is something on this spaceship."},{"type":"user","content":"I'm not sure. Maybe?"}]}

# 输入
{input_section}

# 输出
现在基于输入字段和格式要求，生成***可以直接解析的单行json文本***，***注意前后不要输出任何额外符号！！！***"""

# ---------- 对话表达 ----------
PROMPT_TEMPLATES["mid_dialog_express"] = r"""# 字段内容要求
{
    "cType": "mid_dialog_express", //固定
    "cId": {ID},
    "title": {标题}, 
    "asrPrompt": {语音识别热词}  # 如果内容为"无"，则返回""
    "resourceMapping"(抽取出{角色配置}中的全部 name:id映射，id必须为int类型。如果{角色配置}为空，则该字段为空): {"name":id, "name":id} // 样例：{"Ben":465, "Otis":234}
    "preDialog"(基于{情境引入}抽取，可为空): [
        {
            "type": "npc",
            "npcName": "xxx",
            "content": "xxx"
        },
        {
            "type": "user",
            "content": "xxx"
        },
        ...
    ],
    "imgShowTimingList"(从{资源配置}中抽取，对应关系为：preDialog:情境引入、content:互动内容、feedback:互动反馈、postDialog:后置对话，如果为无则为空[]):["preDialog", "content", "feedback", "postDialog"],
    "img"({资源配置}中存在图片时机时才有该字段): "{ID}.png", 
    "audioFile"({资源配置}中存在音频载体时才有该字段): "{ID}.mp3", 
    "itemName"({资源配置}中存在音频载体时才有该字段，内容从音频载体中抽取): "xxxxx",
    "tip"({互动内容}中的辅助信息): "xxx",   //保留内容中的标点符号  
     "corFeedback"(基于{互动反馈}的正确抽取，如果没有则为空，即{}): {
        "type": "npc",
        "npcName": "xxx",
        "content": "xxx"
    },
    "errFeedback"(基于{互动反馈}的错误抽取): 
        {
            "type": "npc",
            "npcName": "xxx",
            "content": "xxx."
        },
    "question"(基于{互动内容}中的表达抽取): {        
        "desc": "xxxxx"
    },
    "example"(基于{互动内容}中的示例回答抽取): {
        "type": "npc",
        "npcName": "xxx",
        "content": "xxx"
    },
    "postDialog"(基于{后置对话}抽取，可为空): [
        {
            "type": "npc",
            "npcName": "xxx",
            "content": "xxx"
        },
        ...
    ]
}

# 输出格式:
- 整个输出必须在一行内完成，**不要换行**。
- **不要使用 markdown 代码块**（如 ```json）包裹输出。
- 输出内容必须是合法的 JSON 格式，可直接用于 JSON.parse

样例:
{"cType":"mid_dialog_express","cId":"12132","title":"表达感谢","asrPrompt":"thanks,help,door","resourceMapping":{"Ben":465,"Otis":234},"preDialog":[{"type":"npc","npcName":"Sarah","content":"We've seen something. Let's go and have a look right away."},{"type":"user","content":"It seems to be a slogan."}],"imgShowTimingList":["preDialog","conent","feedback","postDialog"],"img":"0000037.png","tip":"key 意思为 \"钥匙\"","corFeedback":{"type":"npc","npcName":"Tom","content":"You got it right."},"errFeedback":{"type":"npc","npcName":"Tom","content":"Wrong！Please continue to make a selection. Look for $key$ in the picture sent by Rebecca and click on it."},"question":{"desc":"对 Boss 表达感谢，比如：\"谢谢你帮我打开门\""},"example":{"type":"user","content":"Thanks for helping me with my luggage. That's true, thanks for helping me with my luggage."},"postDialog":[{"type":"npc","npcName":"Sarah","content":"Let's do as the slogan says."},{"type":"user","content":"It seems to be a slogan."}]}

# 输入
{input_section}

# 输出
现在基于输入字段和格式要求，生成***可以直接解析的单行json文本***，***注意前后不要输出任何额外符号！！！***"""

# ---------- 对话选择 ----------
PROMPT_TEMPLATES["mid_dialog_choose"] = r"""# 字段内容要求
{
    "cType": "mid_dialog_choose", //固定
    "cId": {ID},
    "title": {标题}, 
    "resourceMapping"(抽取出{角色配置}中的全部 name:id映射，id必须为int类型。如果{角色配置}为空，则该字段为空): {"name":id, "name":id} // 样例：{"Ben":465, "Otis":234}
    "preDialog"(基于{情境引入}抽取，可为空): [
        {
            "type": "npc",
            "npcName": "xxx",
            "content": "xxx"
        },
        {
            "type": "user",
            "content": "xxx"
        },
        ...
    ],
    "imgShowTimingList"(从{资源配置}中抽取，对应关系为：preDialog:情境引入、content:互动内容、feedback:互动反馈、postDialog:后置对话，如果为无则为空[]):["preDialog", "content", "feedback", "postDialog"],
    "img"({资源配置}中存在图片时机时才有该字段): "{ID}.png", 
    "audioFile"({资源配置}中存在音频载体时才有该字段): "{ID}.mp3", 
    "itemName"({资源配置}中存在音频载体时才有该字段，内容从音频载体中抽取): "xxxxx",
    "optionList"(基于{互动内容}中的选项抽取): [ 
            {
                "option": "My seat number is 3.",
                "needAudio":true, // 如果选项后有"（音频）"字样，则为true，否则为false
            },
            {
                "option": "My seat number is 4.",
                "needAudio":true, // 如果选项后有"（音频）"字样，则为true，否则为false
            }
        ],
    "answer"(基于{互动内容}中的选项抽取，正确选项后有（正确）进行标识): [0],
    "corFeedback"(基于{互动内容}中选项的反馈抽取，注意是正确选项的反馈，如果反馈为无则为空，即{}): {
        "type": "npc",
        "npcName": "xxx",
        "content": "xxx"
    },
    "errFeedback"(基于{互动内容}中选项的反馈抽取，注意是错误选项的反馈，如果反馈为无则为空，即{}): 
        {
            "type": "npc",
            "npcName": "xxx",
            "content": "xxx."
        },
    "postDialog"(基于{后置对话}抽取，可为空): [
        {
            "type": "npc",
            "npcName": "xxx",
            "content": "xxx"
        },
        ...
    ]
}

# 输出格式:
- 整个输出必须在一行内完成，**不要换行**。
- **不要使用 markdown 代码块**（如 ```json）包裹输出。
- 输出内容必须是合法的 JSON 格式，可直接用于 JSON.parse

样例:
{"cType":"mid_dialog_choose","cId":"0000037","title":"分析声音来源","resourceMapping":{"Ben":465,"Otis":234},"preDialog":[{"type":"user","content":"And now, I've got a question ready for you."},{"type":"npc","npcName":"Otis","content":"What's that?"},{"type":"user","content":"It's about pirates."}],"imgShowTimingList":["content","feedback"],"img":"0000037.png","optionList":[{"option":"My seat number is 3."},{"option":"My seat number is 4."}],"answer":[0],"corFeedback":{"type":"npc","npcName":"Tom","content":"You got it right."},"errFeedback":{"type":"npc","npcName":"Tom","content":"Wrong！Please continue to make a selection."},"postDialog":[{"type":"npc","npcName":"Otis","content":"I guess there is something on this spaceship."},{"type":"user","content":"I'm not sure. Maybe?"}]}

# 输入
{input_section}

# 输出
现在基于输入字段和格式要求，生成***可以直接解析的单行json文本***，***注意前后不要输出任何额外符号！！！***"""

# ---------- 对话选读 ----------
PROMPT_TEMPLATES["mid_dialog_select"] = r"""# 字段内容要求
{
    "cType": "mid_dialog_select", //固定
    "cId": {ID},
    "title": {标题}, 
    "resourceMapping"(抽取出{角色配置}中的全部 name:id映射，id必须为int类型。如果{角色配置}为空，则该字段为空): {"name":id, "name":id} // 样例：{"Ben":465, "Otis":234}
    "preDialog"(基于{情境引入}抽取，可为空): [
        {
            "type": "npc",
            "npcName": "xxx",
            "content": "xxx"
        },
        {
            "type": "user",
            "content": "xxx"
        },
        ...
    ],
    "imgShowTimingList"(从{资源配置}中抽取，对应关系为：preDialog:情境引入、content:互动内容、feedback:互动反馈、postDialog:后置对话，如果为无则为空[]):["preDialog", "content", "feedback", "postDialog"],
    "img"({资源配置}中存在图片时机时才有该字段): "{ID}.png", 
    "audioFile"({资源配置}中存在音频载体时才有该字段): "{ID}.mp3", 
    "itemName"({资源配置}中存在音频载体时才有该字段，内容从音频载体中抽取): "xxxxx",
    "optionList"(基于{互动内容}中的选项抽取，如果选项下反馈为无，则feedback为空，即{}；如果选项后有"（音频）"，则每个选项的"needAudio"为true，否则为false): [ 
        {
            "option": "xxxxxx",
            "needAudio":xxx, 
            "feedback": {
                    "type": "xxx",
                    "npcName": "xxx",
                    "content": "xxxxxxxxxxx"
                }
        },
        {
            "option": "xxxxxx",
            "needAudio":xxx, 
            "feedback": {
                    "type": "xxx",
                    "npcName": "xxx",
                    "content": "xxxxxxxxxxx"
                }
        },
    ......
    ],
    "postDialog"(基于{后置对话}抽取，可为空): [
        {
            "type": "npc",
            "npcName": "xxx",
            "content": "xxx"
        },
        ...
    ]
}

# 输出格式:
- 整个输出必须在一行内完成，**不要换行**。
- **不要使用 markdown 代码块**（如 ```json）包裹输出。
- 输出内容必须是合法的 JSON 格式，可直接用于 JSON.parse

样例:
{"cType":"mid_dialog_select","cId":"0000037","title":"分析声音来源","resourceMapping":{"Ben":465,"Otis":234},"preDialog":[{"type":"user","content":"And now, I've got a question ready for you."},{"type":"npc","npcName":"Otis","content":"What's that?"},{"type":"user","content":"It's about pirates."}],"imgShowTimingList":["content","feedback"],"img":"0000037.png","optionList":[{"option":"That's great! I'm going to ask Otis and Skely to go together!","needAudio":false,"feedback":{"type":"npc","npcName":"Skylar","content":"Huh? You talk big too!"}},{"option":"Interesting! I can go on this trip alone.","needAudio":false,"feedback":{"type":"npc","npcName":"Skylar","content":"wrong!"}},{"option":"It's no fun. I'd better not participate.","needAudio":false,"feedback":{"type":"npc","npcName":"Skylar","content":"ok!"}}],"postDialog":[{"type":"npc","npcName":"Otis","content":"I guess there is something on this spaceship."},{"type":"user","content":"I'm not sure. Maybe?"}]}

# 输入
{input_section}

# 输出
现在基于输入字段和格式要求，生成***可以直接解析的单行json文本***，***注意前后不要输出任何额外符号！！！***"""

# ---------- 对话挖空 ----------
PROMPT_TEMPLATES["mid_dialog_fillin"] = r"""# 字段内容要求
{
    "cType": "mid_dialog_fillin", //固定
    "cId": "{ID}", // 字符串类型
    "title": {标题}, 
    "resourceMapping"(抽取出{角色配置}中的全部 name:id映射，id必须为int类型。如果{角色配置}为空，则该字段为空): {"name":id, "name":id} // 样例：{"Ben":465, "Otis":234}
    "preDialog"(基于{情境引入}抽取，可为空): [
        {
            "type": "npc",
            "npcName": "xxx",
            "content": "xxx"
        },
        {
            "type": "user",
            "content": "xxx"
        },
        ...
    ],
    "imgShowTimingList"(从{资源配置}中抽取，对应关系为：preDialog:情境引入、content:互动内容、feedback:互动反馈、postDialog:后置对话，如果为无则为空[]):["preDialog", "content", "feedback", "postDialog"],
    "img"({资源配置}中存在图片时机时才有该字段): "{ID}.png", 
    "audioFile"({资源配置}中存在音频载体时才有该字段): "{ID}.mp3", 
    "itemName"({资源配置}中存在音频载体时才有该字段，内容从音频载体中抽取): "xxxxx",
    "question"(从{互动内容}中抽取): {
        "type": "user",
        "desc": "This is my picture,It's ___, ___ and ___. ",
        "content": "This is my picture,It's blue, gray and orange." // 将{互动内容}中各个内容组的正确选项填入到句子中组成的完整句子
    },
    "optionGroupList"(从{互动内容}中的内容组抽取，正确选项使用（正确）进行标识，抽取时不要将"（正确）"也抽取出来): [
            {
                "optionList": [{
                            "option": "bule",
                            "needAudio":true, // {互动内容}题干后如果有"（音频）"字样，则为true，否则为false
                    },
                    {
                            "option": "black",
                            "needAudio":true, //  {互动内容}题干后如果有"（音频）"字样，则为true，否则为false
                    }
                ],
                "answer": [1]
            },
            {
                "optionList": [{
                            "option": "gray",
                            "needAudio":true, //  {互动内容}题干后如果有"（音频）"字样，则为true，否则为false
                    },
                    {
                            "option": "green",
                            "needAudio":true, //  {互动内容}题干后如果有"（音频）"字样，则为true，否则为false
                    }
                ],
                "answer": [0]
            }
    ],
    "corFeedback"(基于{互动反馈}的正确反馈抽取，如果为无则为空，即{}): { 
        "type": "npc",
        "npcName": "Tom",
        "content": "You got it right."
    },
    "errFeedback"(基于{互动反馈}的错误反馈抽取，如果为无则为空，即{}): { 
        "type": "npc",
        "npcName": "Tom",
        "content": "Wrong！Please continue to make a selection."
    },
    "postDialog"(基于{后置对话}抽取，可为空): [
        {
            "type": "npc",
            "npcName": "xxx",
            "content": "xxx"
        },
        ...
    ]
}

# 输出格式:
- 整个输出必须在一行内完成，**不要换行**。
- **不要使用 markdown 代码块**（如 ```json）包裹输出。
- 输出内容必须是合法的 JSON 格式，可直接用于 JSON.parse

样例:
{"cType":"mid_dialog_fillin","cId":"0000037","title":"分析声音来源","resourceMapping":{"Ben":465,"Otis":234},"preDialog":[{"type":"user","content":"And now, I've got a question ready for you."},{"type":"npc","npcName":"Otis","content":"What's that?"},{"type":"user","content":"It's about pirates."}],"imgShowTimingList":["content","feedback"],"img":"0000037.png","question":{"type":"user","content":"This is my picture,It's blue, gray and orange.","desc":"This is my picture,It's ___,___ and orange"},"optionGroupList":[{"optionList":[{"option":"bule"},{"option":"black"}],"answer":[1]},{"optionList":[{"option":"gray"},{"option":"green"}],"answer":[0]}],"corFeedback":{"type":"npc","npcName":"Tom","content":"You got it right."},"errFeedback":{"type":"npc","npcName":"Tom","content":"Wrong！Please continue to make a selection."},"postDialog":[{"type":"npc","npcName":"Otis","content":"I guess there is something on this spaceship."},{"type":"user","content":"I'm not sure. Maybe?"}]}

# 输入
{input_section}

# 输出
现在基于输入字段和格式要求，生成***可以直接解析的单行json文本***，***注意前后不要输出任何额外符号！！！***"""

# ---------- 对话组句 ----------
PROMPT_TEMPLATES["mid_dialog_sentence"] = r"""# 字段内容要求
{
    "cType": "mid_dialog_sentence", //固定
    "cId": {ID}, // 字符串类型
    "title": {标题}, 
    "resourceMapping"(抽取出{角色配置}中的全部 name:id映射，id必须为int类型。如果{角色配置}为空，则该字段为空): {"name":id, "name":id} // 样例：{"Ben":465, "Otis":234}
    "preDialog"(基于{情境引入}抽取，可为空): [
        {
            "type": "npc",
            "npcName": "xxx",
            "content": "xxx"
        },
        {
            "type": "user",
            "content": "xxx"
        },
        ...
    ],
    "imgShowTimingList"(从{资源配置}中抽取，对应关系为：preDialog:情境引入、content:互动内容、feedback:互动反馈、postDialog:后置对话，如果为无则为空[]):["preDialog", "content", "feedback", "postDialog"],
    "img"({资源配置}中存在图片时机时才有该字段): "{ID}.png", 
    "audioFile"({资源配置}中存在音频载体时才有该字段): "{ID}.mp3", 
    "itemName"({资源配置}中存在音频载体时才有该字段，内容从音频载体中抽取): "xxxxx",
    "question"(基于{互动内容}抽取): {        
        "desc": "xxxxx", // {互动内容}中的题目
        "content": "xxxxxxxxxxxx" // {互动内容}中的答案
    },
    "optionList"(基于{互动内容}的选项抽取): [
        {
                "option": "me",
                "needAudio":true, // {互动内容}题目后如果有"（音频）"字样，则为true，否则为false
        },
        {
                "option": "let",
                "needAudio":true,
        },
        {
                "option": "some trouble",
                "needAudio":true,
        },
        {
                "option": "make",
                "needAudio":true,
        }
]
    "answer"(基于{互动内容}的答案抽取): [1,0,3,2], // 根据答案生成正确option的索引
    "tip"({互动内容}中的辅助信息): "xxx",   //保留内容中的标点符号  
    "corFeedback"(基于{互动反馈}的正确抽取，如果没有则为空，即{}): {
        "type": "npc",
        "npcName": "xxx",
        "content": "xxx"
    },
    "errFeedback"(基于{互动反馈}的错误抽取): 
        {
            "type": "npc",
            "npcName": "xxx",
            "content": "xxx."
        },
    "postDialog"(基于{后置对话}抽取，可为空): [
        {
            "type": "npc",
            "npcName": "xxx",
            "content": "xxx"
        },
        ...
    ]
}

# 输出格式:
- 整个输出必须在一行内完成，**不要换行**。
- **不要使用 markdown 代码块**（如 ```json）包裹输出。
- 输出内容必须是合法的 JSON 格式，可直接用于 JSON.parse

样例:
{"cType":"mid_dialog_sentence","cId":"0000002","title":"向 Rebecca 说明方法","resourceMapping":{"Ben":465,"Otis":234},"preDialog":[{"content":"So? Did you figure it out?","npcName":"Rebecca","type":"npc"},{"content":"These words are all over the place...","npcName":"Rebecca","type":"npc"}],"imgShowTimingList":["content","feedback"],"img":"0000002.png","question":{"content":"Let me make some trouble.","desc":"解析秘密指令"},"optionList":[{"option":"me"},{"option":"let"},{"option":"some trouble"},{"option":"make"}],"answer":[1,0,3,2],"tip":"句子是 let 引导的祈使句","corFeedback":{"content":"Got it.","npcName":"Rebecca","type":"npc"},"errFeedback":{"content":"I'm still not sure what this means.","npcName":"Rebecca","type":"npc"},"postDialog":[]}

# 输入
{input_section}

# 输出
现在基于输入字段和格式要求，生成***可以直接解析的单行json文本***，***注意前后不要输出任何额外符号！！！***"""

# ---------- 信息描写 ----------
PROMPT_TEMPLATES["mid_message_trace"] = r"""# 字段内容要求
{
    "cType": "mid_message_trace", //固定
    "cId": {ID},
    "title": {标题},
    "resourceMapping"(抽取出{角色配置}中的全部 name:id映射，id必须为int类型。如果{角色配置}为空，则该字段为空): {"name":id, "name":id} // 样例：{"Ben":465, "Otis":234}
    "cDesc"(基于{互动描述}抽取): "xxx",
    "question"(基于{互动内容}抽取): {        
        "desc": "xxxxx", // {互动内容}中的任务描述
    },
   "trace"(基于{互动内容}中的答案抽取): "xxx",
    "img": "{ID}.png", 
    "inputSet": [] //固定
}

# 输出格式:
- 整个输出必须在一行内完成，**不要换行**。
- **不要使用 markdown 代码块**（如 ```json）包裹输出。
- 输出内容必须是合法的 JSON 格式，可直接用于 JSON.parse

样例:
{"cType":"mid_message_trace","cId":"0000001","title":"填写菜单","cDesc":"You filled in the menu with the chosen fruits. (你在菜单上填好了选中的水果。)","question":{"desc":"在菜单上描写出需要选择的水果"},"trace":"help","img":"0000001.png","inputSet":[]}

# 输入
{input_section}

# 输出
现在基于输入字段和格式要求，生成***可以直接解析的单行json文本***，***注意前后不要输出任何额外符号！！！***"""

# ---------- 信息拼词 ----------
PROMPT_TEMPLATES["mid_message_spell"] = r"""# 字段内容要求
{
    "cType": "mid_message_spell", //固定
    "cId": {ID},
    "title": {标题},
    "resourceMapping"(抽取出{角色配置}中的全部 name:id映射，id必须为int类型。如果{角色配置}为空，则该字段为空): {"name":id, "name":id} // 样例：{"Ben":465, "Otis":234}
    "cDesc"(基于{互动描述}抽取): "xxx",
    "question"(基于{互动内容}抽取): {        
        "desc": "xxxxx", // {互动内容}中的任务描述
    },
    "tip"(基于{互动内容}中的辅助信息抽取): "xxx",
    "inputConfig": [
        {
            "stem"(基于{互动内容}中的题干抽取): "xxxx",
            "value"(基于{互动内容}中的答案抽取): "xxxx"
         }
    ],
    "stemList"((基于{互动内容}中的选项抽取)): [xxxxx],
    "img": "{ID}.png", 
    "inputSet": [] //固定
}

# 输出格式:
- 整个输出必须在一行内完成，**不要换行**。
- **不要使用 markdown 代码块**（如 ```json）包裹输出。
- 输出内容必须是合法的 JSON 格式，可直接用于 JSON.parse

样例:
{"cType":"mid_message_spell","cId":"0000001","title":"填写菜单","cDesc":"You spelled the fruit name correctly on the menu. (你在菜单上正确拼出了水果的名字。)","question":{"desc":"选择合适的字母拼出想要的水果"},"tip":"第二个字母是 r 哦，再想想最后一个空应该填什么吧","inputConfig":[{"stem":"G(2)pe","value":"ra"}],"stemList":["h","a","r","l","e"],"img":"0000001.png","inputSet":[]}

# 输入
{input_section}

# 输出
现在基于输入字段和格式要求，生成***可以直接解析的单行json文本***，***注意前后不要输出任何额外符号！！！***"""

# ---------- 信息组句 ----------
PROMPT_TEMPLATES["mid_message_combine"] = r"""# 字段内容要求
{
    "cType": "mid_message_combine", //固定
    "cId": {ID},
    "title": {标题},
    "resourceMapping"(抽取出{角色配置}中的全部 name:id映射，id必须为int类型。如果{角色配置}为空，则该字段为空): {"name":id, "name":id} // 样例：{"Ben":465, "Otis":234}
    "cDesc"(基于{互动描述}抽取): "xxx",
    "question"(基于{互动内容}抽取): {        
        "desc": "xxxxx", // {互动内容}中的任务描述
    },
    "tip"(基于{互动内容}中的辅助信息抽取): "xxx",
    "optionList"(基于{互动内容}中的选项抽取): [
        {
            "option": "xxxx"
         },
        {
            "option": "xxxx"
         }
         ...
    ],
    "answer"(基于{互动内容}中的答案生成，根据答案抽取出optionList中对应选项的索引): [xxxxx],
    "img": "{ID}.png", 
    "inputSet": [] //固定
}

# 输出格式:
- 整个输出必须在一行内完成，**不要换行**。
- **不要使用 markdown 代码块**（如 ```json）包裹输出。
- 输出内容必须是合法的 JSON 格式，可直接用于 JSON.parse

样例:
{"cType":"mid_message_combine","cId":"0000001","title":"提交身份证件","cDesc":"You submitted the required ID details successfully online. (你成功提交了所需的身份证件信息。)","question":{"desc":"选择正确的选项组合出必要的填写内容"},"tip":" ","optionList":[{"option":"I am"},{"option":"a Pioneer!"},{"option":"going to be"}],"answer":[0,2,1],"img":"0000001.png","inputSet":[]}

# 输入
{input_section}

# 输出
现在基于输入字段和格式要求，生成***可以直接解析的单行json文本***，***注意前后不要输出任何额外符号！！！***"""

# ---------- 信息补词 ----------
PROMPT_TEMPLATES["mid_message_fillin"] = r"""# 字段内容要求
{
    "cType": "mid_message_fillin", //固定
    "cId": {ID},
    "title": {标题},
    "resourceMapping"(抽取出{角色配置}中的全部 name:id映射，id必须为int类型。如果{角色配置}为空，则该字段为空): {"name":id, "name":id} // 样例：{"Ben":465, "Otis":234}
    "cDesc"(基于{互动描述}抽取): "xxx",
    "question"(基于{互动内容}抽取): {        
        "desc": "xxxxx", // {互动内容}中的任务描述
    },
    "tip"(基于{互动内容}中的辅助信息抽取): "xxx",
    "inputConfig": [
        {
            "stem"(基于{互动内容}中的题干抽取): "xxxx",
            "value"(基于{互动内容}中的答案抽取): "xxxx"
         }
    ],
    "img": "{ID}.png", 
    "inputSet": [] //固定
}

# 输出格式:
- 整个输出必须在一行内完成，**不要换行**。
- **不要使用 markdown 代码块**（如 ```json）包裹输出。
- 输出内容必须是合法的 JSON 格式，可直接用于 JSON.parse

样例:
{"cType":"mid_message_fillin","cId":"0000001","title":"填写学习旅行申请单","cDesc":"You filled in the study trip application with needed words. (你在学习旅行申请单上填好了必要的单词。)","question":{"desc":"在申请单上填上必要的单词"},"tip":"需要填写的是\"知识\"的单词","inputConfig":[{"stem":"K(3)ledge","value":"new"}],"img":"0000001.png","inputSet":[]}

# 输入
{input_section}

# 输出
现在基于输入字段和格式要求，生成***可以直接解析的单行json文本***，***注意前后不要输出任何额外符号！！！***"""

# ---------- 信息填词 ----------
PROMPT_TEMPLATES["mid_message_word"] = r"""# 字段内容要求
{
    "cType": "mid_message_word", //固定
    "cId": {ID},
    "title": {标题},
    "resourceMapping"(抽取出{角色配置}中的全部 name:id映射，id必须为int类型。如果{角色配置}为空，则该字段为空): {"name":id, "name":id} // 样例：{"Ben":465, "Otis":234}
    "cDesc"(基于{互动描述}抽取): "xxx",
    "question"(基于{互动内容}抽取): {        
        "desc": "xxxxx", // {互动内容}中的任务描述
    },
    "tip"(基于{互动内容}中的辅助信息抽取): "xxx",
    "answer"(基于{互动内容}中的答案抽取): [xxxxx],
    "img": "{ID}.png", 
    "inputSet": [] //固定
}

# 输出格式:
- 整个输出必须在一行内完成，**不要换行**。
- **不要使用 markdown 代码块**（如 ```json）包裹输出。
- 输出内容必须是合法的 JSON 格式，可直接用于 JSON.parse

样例:
{"cType":"mid_message_word","cId":"0000001","title":"填写学习旅行申请单","cDesc":"You filled in the study trip application with the needed words. (你在学习旅行申请单上填好了必要的单词。)","question":{"desc":"在申请单上填上必要的单词"},"tip":"需要填写的是\"知识\"的单词","answer":["knowledge","information","understanding"],"img":"0000001.png","inputSet":[]}

# 输入
{input_section}

# 输出
现在基于输入字段和格式要求，生成***可以直接解析的单行json文本***，***注意前后不要输出任何额外符号！！！***"""

# ---------- 信息填句 ----------
PROMPT_TEMPLATES["mid_message_sentence"] = r"""# 字段内容要求
{
    "cType": "mid_message_sentence", //固定
    "cId": {ID},
    "title": {标题},
    "resourceMapping"(抽取出{角色配置}中的全部 name:id映射，id必须为int类型。如果{角色配置}为空，则该字段为空): {"name":id, "name":id} // 样例：{"Ben":465, "Otis":234}
    "cDesc"(基于{互动描述}抽取): "xxx",
    "question"(基于{互动内容}抽取): {        
        "desc": "xxxxx", // {互动内容}中的任务描述
    },
    "tip"(基于{互动内容}中的辅助信息抽取): "xxx",
    "answerHint"(基于{互动内容}中的推荐答案抽取): "xxxxx",
    "img": "{ID}.png", 
    "inputSet": [] //固定
}

# 输出格式:
- 整个输出必须在一行内完成，**不要换行**。
- **不要使用 markdown 代码块**（如 ```json）包裹输出。
- 输出内容必须是合法的 JSON 格式，可直接用于 JSON.parse

样例:
{"cType":"mid_message_sentence","cId":"0000001","title":"填写学习旅行申请单","cDesc":"You copied \"The main purpose of this tour\" onto the application form. (你把\"The main purpose of this tour\"抄写到了申请单上。)","question":{"desc":"请抄写 The main purpose of this tour"},"tip":"你可以使用 The main purpose of this tour is...","answerHint":"The main purpose of this tour is to learn knowledge about local traditional crafts.","img":"0000001.png","inputSet":[]}

# 输入
{input_section}

# 输出
现在基于输入字段和格式要求，生成***可以直接解析的单行json文本***，***注意前后不要输出任何额外符号！！！***"""

# ---------- 图片单选 ----------
PROMPT_TEMPLATES["mid_image_choose"] = r"""# 字段内容要求
{
    "cType": "mid_image_choose",//固定值
    "cId": "{ID}",
    "title": {标题},
    "meaning": {学习意义构建}, // 如果为"无"则为空字符串""
    "resourceMapping"(抽取出{角色配置}中的全部 name:id映射 可为空。id必须为int类型): {"name":id, "name":id}
    "question"(基于{互动内容}抽取):{
        "desc":"xxx",
        "content":"xxx" // 如果有"（音频）"字样，则有该字段，内容和"desc"相同；如果没有"（音频）"字样，则没有该字段！注意"（音频）"不要提取出来！
    },
    "imageInfo": {
        "questionImg": "{ID}_question.png",
        "answerImg": "{ID}_answer.png",
    },
    "optionList"(基于{互动内容}中的选项抽取): [
        {
            "option": "{ID}_option_00.png",
        },
        {
            "option": "{ID}_option_01.png",
        },
        ......
    ],
    "answer"(基于{互动内容}中的答案抽取):[xx],
    "preDialog"(基于{情境引入}抽取): [...],
    "tip"(基于{互动内容}中的辅助信息抽取): "xxx",
    "corFeedback"(基于{互动反馈}中的正确抽取，如果为无则该字段整体为空，即{}): {
        "type": "npc",
        "npcName": "xxx",
        "content": "xxx"
    }, 
    "errFeedback"(基于{互动反馈}的错误抽取): {
        "type": "npc",
        "npcName": "xxx",
        "content": "xxx"
    },
    "postDialog"(基于{后置对话}抽取): [...],
    "cDesc": "xxx", // {互动描述}的全部内容
}

# 输出格式:
单行json。
样例:
{"cType":"mid_image_choose","cId":"12132","title":"猜Chloe的意图","meaning":"","resourceMapping":{"Ben":465,"Otis":234},"question":{"desc":"Look for $key$ in the picture sent by Rebecca and click on it."},"imageInfo":{"questionImg":"0000001_question.png","answerImg":"0000001_answer.png"},"optionList":[{"option":"00000001_option_00.png"},{"option":"00000001_option_01.png"}],"answer":[1],"preDialog":[{"type":"npc","npcName":"Sarah","content":"We've seen something. Let's go and have a look right away."},{"type":"user","content":"It seems to be a slogan."}],"tip":"key 意思为 \"钥匙\"。","corFeedback":{"type":"npc","npcName":"Tom","content":"You got it right."},"errFeedback":{"type":"npc","npcName":"Tom","content":"Wrong！Look for $key$ in the picture sent by Rebecca and click on it."},"postDialog":[{"type":"npc","npcName":"Sarah","content":"Let's do as the slogan says."},{"type":"user","content":"It seems to be a slogan."}],"cDesc":"You pressed the clean button on the drone. (你按下了无人机的清理按键。)"}

# 输入
{input_section}

# 输出
现在基于输入字段和格式要求，生成***可以直接解析的单行json文本***，***注意前后不要输出任何额外符号！！！***"""

# ---------- 图片多选 ----------
PROMPT_TEMPLATES["mid_image_multiple"] = r"""# 字段内容要求
{
    "cType": "mid_image_multiple",//固定值
    "cId": "{ID}", // 类型为字符串
    "title": {标题},
    "meaning": {学习意义构建}, // 如果为"无"则为空字符串""
    "resourceMapping"(抽取出{角色配置}中的全部 name:id映射 可为空。id必须为int类型): {"name":id, "name":id}
    "question"(基于{互动内容}抽取):{
        "desc":"xxx",
        "content":"xxx" // 如果有"（音频）"字样，则有该字段，内容和"desc"相同；如果没有"（音频）"字样，则没有该字段！
    },
    "imageInfo": {
        "questionImg": "{ID}_question.png",
        "answerImg": "{ID}_answer.png",
    },
    "optionList"(基于{互动内容}中的选项抽取): [
        {"option": "{ID}_option_00.png"},
        {"option": "{ID}_option_01.png"},
        ......
    ],
    "answer"(基于{互动内容}中的答案抽取):[xx,xx,...],
    "preDialog"(基于{情境引入}抽取): [...],
    "tip"(基于{互动内容}中的辅助信息抽取): "xxx",
    "corFeedback"(基于{互动反馈}抽取，如果没有正确反馈则为空，即{}): {...}, 
    "errFeedback"(基于{互动反馈}抽取): {...},
    "postDialog"(基于{后置对话}抽取): [...],
    "cDesc": "xxx", // {互动描述}的全部内容
}

# 输出格式:
单行json。
样例:
{"cType":"mid_image_multiple","cId":"12132","title":"猜Chloe的意图","meaning":"","resourceMapping":{"Ben":465,"Otis":234},"question":{"desc":"Look for $key$ in the picture sent by Rebecca and click on it."},"imageInfo":{"questionImg":"0000001_question.png","answerImg":"0000001_answer.png"},"optionList":[{"option":"00000001_option_00.png"},{"option":"00000001_option_01.png"},{"option":"00000001_option_02.png"},{"option":"00000001_option_03.png"},{"option":"00000001_option_04.png"}],"answer":[1,3,4],"preDialog":[{"type":"npc","npcName":"Sarah","content":"We've seen something. Let's go and have a look right away."},{"type":"user","content":"It seems to be a slogan."}],"tip":"key 意思为 \"钥匙\"","corFeedback":{"type":"npc","npcName":"Tom","content":"You got it right."},"errFeedback":{"type":"npc","npcName":"Tom","content":"Wrong！Look for $key$ in the picture sent by Rebecca and click on it."},"postDialog":[{"type":"npc","npcName":"Sarah","content":"Let's do as the slogan says."},{"type":"user","content":"It seems to be a slogan."}],"cDesc":"You pressed the clean button on the drone. (你按下了无人机的清理按键。)"}

# 输入
{input_section}

# 输出
现在基于输入字段和格式要求，生成***可以直接解析的单行json文本***，***注意前后不要输出任何额外符号！！！***"""

# ---------- 图片有序 ----------
PROMPT_TEMPLATES["mid_image_sequence"] = r"""# 字段内容要求
{
    "cType": "mid_image_sequence",//固定值
    "cId": {ID},
    "title": {标题},
    "meaning": {学习意义构建}, // 如果为"无"则为空字符串""
    "resourceMapping"(抽取出{角色配置}中的全部 name:id映射 可为空。id必须为int类型): {"name":id, "name":id}
    "question"(基于{互动内容}抽取):{
        "desc":"xxx"
    },
    "imageInfo": {
        "questionImg": "{ID}_question.png",
        "answerImg": "{ID}_answer.png",
    },
    "optionList"(请严格基于{互动内容}中给出的选项进行抽取，生成的结果数量必须与选项数量**完全一致**，**不得遗漏**任何选项。): [
        {"option": "{ID}_option_00.png"},
        {"option": "{ID}_option_01.png"},
        ......
    ],
    "answer"(基于{互动内容}中的答案抽取):[xx,xx...],
    "preDialog"(基于{情境引入}抽取): [...],
    "tip"(基于{互动内容}中的辅助信息抽取): "xxx",
    "corFeedback"(基于{互动反馈}抽取"正确"，如果没有正确反馈则为空，即{}): {...}, 
    "errFeedback"(基于{互动反馈}抽取"错误"): {...},
    "postDialog"(基于{后置对话}抽取): [...],
    "cDesc": "xxx", // {互动描述}的全部内容
}

# 输出格式:
单行json。
样例:
{"cType":"mid_image_sequence","cId":"12132","title":"猜Chloe的意图","meaning":"","resourceMapping":{"Ben":465,"Otis":234},"question":{"desc":"Look for $key$ in the picture."},"imageInfo":{"questionImg":"0000001_question.png","answerImg":"0000001_answer.png"},"optionList":[{"option":"00000001_option_00.png"},{"option":"00000001_option_01.png"},{"option":"00000001_option_02.png"},{"option":"00000001_option_03.png"},{"option":"00000001_option_04.png"}],"answer":[1,3,4],"preDialog":[{"type":"npc","npcName":"Sarah","content":"We've seen something."},{"type":"user","content":"It seems to be a slogan."}],"tip":"key 意思为 \"钥匙\"","corFeedback":{"type":"npc","npcName":"Tom","content":"You got it right."},"errFeedback":{"type":"npc","npcName":"Tom","content":"Wrong！"},"postDialog":[{"type":"npc","npcName":"Sarah","content":"Let's do as the slogan says."}],"cDesc":"You found the ruler, hammer and screwdriver in order. (你依次找到了尺子、锤子和螺丝刀。)"}

# 输入
{input_section}

# 输出
现在基于输入字段和格式要求，生成***可以直接解析的单行json文本***，***注意前后不要输出任何额外符号！！！***"""

# ---------- 图片拖拽 ----------
PROMPT_TEMPLATES["mid_image_drag"] = r"""# 字段内容要求
{
    "cType": "mid_image_drag",//固定值
    "cId": "{ID}", // 类型为字符串
    "title": {标题},
    "meaning": {学习意义构建}, // 如果为"无"则为空字符串""
    "resourceMapping"(抽取出{角色配置}中的全部 name:id映射 可为空。id必须为int类型): {"name":id, "name":id}
    "question"(基于{互动内容}抽取):{
        "desc":"xxx", // 如果有"（音频）"字样，在抽取时略过"（音频）"
        "content":"xxx" // 如果有"（音频）"字样，则有该字段，内容和"desc"相同；如果没有"（音频）"字样，则没有该字段！
    },
    "imageInfo": {
        "questionImg": "{ID}_question.png",
        "answerImg": "{ID}_answer.png",
    },
    "optionList"(基于{互动内容}中的选项抽取): [
        {"option": "{ID}_option_00.png"},
        {"option": "{ID}_option_01.png"},
        ......
    ],
    "answer"(基于{互动内容}中的答案抽取):[xx,xx,...],
    "preDialog"(基于{情境引入}抽取): [...],
    "tip"(基于{互动内容}中的辅助信息抽取): "xxx",
    "corFeedback"(基于{互动反馈}抽取，如果没有正确反馈则为空，即{}): {...}, 
    "errFeedback"(基于{互动反馈}抽取): {...},
    "postDialog"(基于{后置对话}抽取): [...],
    "cDesc": "xxx", // {互动描述}的全部内容
}

# 输出格式:
单行json。
样例:
{"cType":"mid_image_drag","cId":"12132","title":"猜Chloe的意图","meaning":"","resourceMapping":{"Ben":465,"Otis":234},"question":{"desc":"Look for $key$ in the picture sent by Rebecca and click on it."},"imageInfo":{"questionImg":"0000001_question.png","answerImg":"0000001_answer.png"},"optionList":[{"option":"00000001_option_00.png"},{"option":"00000001_option_01.png"},{"option":"00000001_option_02.png"},{"option":"00000001_option_03.png"},{"option":"00000001_option_04.png"}],"answer":[1,3,4],"preDialog":[{"type":"npc","npcName":"Sarah","content":"We've seen something."},{"type":"user","content":"It seems to be a slogan."}],"tip":"key 意思为 \"钥匙\"","corFeedback":{"type":"npc","npcName":"Tom","content":"You got it right."},"errFeedback":{"type":"npc","npcName":"Tom","content":"Wrong！"},"postDialog":[{"type":"npc","npcName":"Sarah","content":"Let's do as the slogan says."}],"cDesc":"You pressed the clean button on the drone. (你按下了无人机的清理按键。)"}

# 输入
{input_section}

# 输出
现在基于输入字段和格式要求，生成***可以直接解析的单行json文本***，***注意前后不要输出任何额外符号！！！***"""


# ============================================================
# cDesc 互动描述生成 prompt 模板
# ============================================================

CDESC_MESSAGE_TYPES = {
    "mid_message_trace", "mid_message_spell", "mid_message_combine",
    "mid_message_fillin", "mid_message_word", "mid_message_sentence",
}

CDESC_IMAGE_TYPES = {
    "mid_image_choose", "mid_image_multiple", "mid_image_sequence", "mid_image_drag",
}

CDESC_TYPES = CDESC_MESSAGE_TYPES | CDESC_IMAGE_TYPES

CDESC_PROMPT_MESSAGE = """# 任务目标
你是一个儿童英语学习内容生成助手。现在有一个物品互动配置，需要将其转写为对话记录中的一句叙事化描述，用于回顾剧情。

# 输入信息
- 互动名称：{互动名称}
- 互动内容：{互动内容}

# 生成要求
1. **输出一句自然叙事**，表现为角色完成了物品操作或选择。
2. **以英文为主，中文放在括号中**，英文和中文必须在一句话里。
   - 示例：You picked up the drone. (你捡起了无人机。)
3. **必须使用正确答案的词汇**来生成叙事，不要出现错误选项。
4. **避免教学感**，不能出现"题目""选项""正确答案"等表述。
5. **动作简洁、贴近剧情**，长度控制在 8–15 个英文词。
6. 输出时只返回最终的一句话结果，不要解释。

# 输出示例
输入：
- 互动名称：捡起地上的无人机
- 互动题目：I need to "拾起" the drone on the ground.
- 互动选项：A.pick out  B.pick up
- 正确答案：B
- 选项描述：A.phr. v. 挑选  B.phr. v.捡起

输出：
You picked up the drone on the ground. (你捡起了地上的无人机。)"""

CDESC_PROMPT_IMAGE = """# 任务目标
你是一个儿童英语学习内容生成助手。现在有一个图片互动配置，需要将其转写为对话记录中的一句叙事化描述，用于回顾剧情。

# 背景知识
图片互动组件的定义：
- 图片互动要求孩子在一张图像中点击特定位置完成任务。
- 任务通常以英文给出一个目标单词，孩子需通过理解该词的含义，在图中找出其对应位置。
- 交互方式是直接点击图片中对应区域，不提供文字选项。
- 重点训练孩子对词义的理解与视觉对应判断能力，强调中英词汇的实际配对与应用判断。

在对话记录中：
- 情境引入对话、互动反馈、后置对话会原样保留。
- 互动内容（即孩子在图中找到目标物品的过程）需要转写为一句自然的叙事描述。

# 输入信息
- 互动名称：{互动名称}
- 情境引入对话：{情境引入对话}
- 互动内容：{互动内容}
- 互动反馈：{互动反馈}
- 后置对话：{后置对话}

# 输出要求
1. 输出一句自然叙事，放在情境引入对话之后、互动反馈之前。
2. 以英文为主，中文放在括号中，必须在一句话里。
   - 示例：You packed your clothes into the suitcase. (你把衣服装进了行李箱。)
3. 必须使用互动目标的关键词（如 $clothes$），强化学习点。
4. 避免教学感，不能出现"点击""选项""正确答案"等字眼。
5. 动作简洁、贴近剧情，长度控制在 8–15 个英文词。
6. 输出时只返回最终的一句话结果，不要解释。

# 输出示例
输入：
- 互动名称：把衣服装进行李箱
- 情境引入对话：
  User: Let me check the list… What do I need?
  User: Most importantly, enough clothes!
- 互动内容：
  User: So let me pack all my $clothes$.
- 答案：{{-0.53,0.32,0.15,0.66}}
- 辅助信息：clothes 意思为 "衣服"
- 互动反馈：
  正确：User：Nice! Clothes packed!
  错误：User: Oops, I picked the wrong one.
- 后置对话：无

输出：
You packed your clothes into the suitcase. (你把衣服装进了行李箱。)"""


def build_cdesc_prompt(cType, parsed_fields):
    """为中互动构建互动描述生成 prompt。

    Args:
        cType: 组件类型
        parsed_fields: parse_teaching_config_fields() 的返回值

    Returns:
        str: 完整的互动描述生成 prompt
    """
    互动名称 = parsed_fields.get("标题", "无")
    互动内容 = parsed_fields.get("互动内容", "无")

    if cType in CDESC_MESSAGE_TYPES:
        return CDESC_PROMPT_MESSAGE.format(
            互动名称=互动名称,
            互动内容=互动内容,
        )
    elif cType in CDESC_IMAGE_TYPES:
        情境引入 = parsed_fields.get("情境引入", "无")
        互动反馈 = parsed_fields.get("互动反馈", "无")
        后置对话 = parsed_fields.get("后置对话", "无")
        return CDESC_PROMPT_IMAGE.format(
            互动名称=互动名称,
            情境引入对话=情境引入,
            互动内容=互动内容,
            互动反馈=互动反馈,
            后置对话=后置对话,
        )
    return None


# ============================================================
# Public API
# ============================================================

def get_prompt_template(cType):
    """Get the prompt template for a given cType. Returns None if not found."""
    return PROMPT_TEMPLATES.get(cType)


def get_supported_types():
    """Return list of cTypes that have prompt templates."""
    return list(PROMPT_TEMPLATES.keys())


def build_full_prompt(cType, cId, parsed_fields, resource_mapping_str=""):
    """
    Build the complete prompt by filling in the input section.

    Args:
        cType: component type (e.g. "mid_dialog_repeat")
        cId: component ID
        parsed_fields: dict from parse_teaching_config_fields()
        resource_mapping_str: formatted角色配置 string

    Returns:
        str: complete prompt ready for LLM, or None if cType not supported
    """
    template = get_prompt_template(cType)
    if template is None:
        return None

    input_section = build_input_section(cType, cId, parsed_fields, resource_mapping_str)
    return template.replace("{input_section}", input_section)
