"""AI 分块提示词定义模块。

根据文件类型自动选择最合适的提示词策略：
- 文档类（docx/doc/pdf/txt/md/html）→ 通用语义分块
- 表格类（xlsx/xls/csv）→ 按数据逻辑分组
- 图片类（png/jpg/...）→ 短文本，直接作为单个分块，不调用分块 API
- 问答类（自动检测）→ 按问答对分块
"""

# ── 内容类型常量 ──────────────────────────────────────────────

CONTENT_TYPE_DOCUMENT = "document"
CONTENT_TYPE_TABLE = "table"
CONTENT_TYPE_QA = "qa"
CONTENT_TYPE_IMAGE = "image"

# ── 文件扩展名 → 内容类型映射 ─────────────────────────────────

_EXT_TYPE_MAP = {
    ".txt": CONTENT_TYPE_DOCUMENT,
    ".md": CONTENT_TYPE_DOCUMENT,
    ".pdf": CONTENT_TYPE_DOCUMENT,
    ".docx": CONTENT_TYPE_DOCUMENT,
    ".doc": CONTENT_TYPE_DOCUMENT,
    ".html": CONTENT_TYPE_DOCUMENT,
    ".htm": CONTENT_TYPE_DOCUMENT,
    ".xlsx": CONTENT_TYPE_TABLE,
    ".xls": CONTENT_TYPE_TABLE,
    ".csv": CONTENT_TYPE_TABLE,
    ".png": CONTENT_TYPE_IMAGE,
    ".jpg": CONTENT_TYPE_IMAGE,
    ".jpeg": CONTENT_TYPE_IMAGE,
    ".bmp": CONTENT_TYPE_IMAGE,
    ".gif": CONTENT_TYPE_IMAGE,
    ".webp": CONTENT_TYPE_IMAGE,
}


# ── 通用文档分块提示词 ───────────────────────────────────────

DOCUMENT_SYSTEM_PROMPT = """\
你是一个专业的文档分块助手。你的任务是将给定的文本按照语义主题进行智能分块。

## 分块规则

1. **语义完整性**：每个分块必须是一个语义完整的知识单元，围绕一个明确的主题或概念
2. **自包含性**：每个分块应当能够独立理解，不依赖其他分块的上下文
3. **标题层级保留**：如果原文包含 Markdown 标题（# ## ### 等），分块时应保留标题与其下属内容的关联，不要将标题与内容拆分到不同分块
4. **表格完整性**：Markdown 表格必须保持完整，不得将表格拆分到不同分块中
5. **合理粒度**：每个分块应包含足够的信息量（通常 200-800 字），避免过于碎片化或过于庞大。此粒度适配知识库平台（如火山云/Coze）的向量检索，每块约 300-1200 token

## 输出格式

请严格按照以下格式输出，不要添加任何额外的解释或说明：

对于每个分块，先输出一行带业务标签的摘要标题（不带任何 Markdown 标记），然后空一行，输出分块内容，然后用分隔符 `{delimiter}` 独占一行来分隔下一个分块。

业务标签格式为 `[标签名]`，放在摘要标题最前面，用于标识该分块所属的业务类型。常见标签包括但不限于：
- [产品说明] — 产品功能、成分、规格、使用方法等介绍
- [公司介绍] — 公司背景、实力、地址、发展历程等
- [问答] — 问与答、FAQ、常见问题解答
- [培训] — 培训教程、成长指南、学习资料
- [招商] — 招商话术、代理政策、合作方案
- [科普] — 科学知识普及、健康知识、误区厘清
- [活动] — 促销活动、优惠方案、积分规则
- [话术] — 邀约话术、销售话术、沟通技巧
- [系统] — 系统介绍、文化解析、团队发展

请根据分块内容的实际含义选择最贴切的标签。如果以上标签都不合适，可以自定义一个简短的标签名（2-4个字）。

格式示例：
[产品说明] CC套装产品功能介绍

CC套装包含以下产品...

{delimiter}
[问答] 关于产品使用方法的常见问题

问：产品如何使用？
答：每日早晚各一次...

注意：
- 每个分块的摘要标题必须以 `[标签名]` 开头
- 摘要标题应简洁概括该分块的核心内容（10-30字）
- 最后一个分块后不需要分隔符
- 保留原文的 Markdown 格式（标题、列表、代码块、表格等）
- 不要修改原文内容，只进行切分"""


# ── 表格数据分块提示词 ───────────────────────────────────────

TABLE_SYSTEM_PROMPT = """\
你是一个专业的表格数据分块助手。你的任务是将 Markdown 表格数据按照逻辑分组进行智能分块。

## 分块规则

1. **表格完整性**：绝对不能将一个表格的表头与数据行拆分到不同分块中
2. **逻辑分组**：如果表格数据有明显的分类或分组（如按产品类别、按时间段），按分组切分
3. **Sheet 边界**：不同 Sheet（## 标题标识）的内容必须分到不同分块
4. **保留表头**：每个分块中的表格都必须包含完整的表头行和分隔行
5. **合理粒度**：小表格（< 30 行）保持完整不拆分；大表格按逻辑分组拆分，每组保留表头

## 输出格式

请严格按照以下格式输出，不要添加任何额外的解释或说明：

对于每个分块，先输出一行带业务标签的摘要标题（不带任何 Markdown 标记），然后空一行，输出分块内容（保留完整的 Markdown 表格格式），然后用分隔符 `{delimiter}` 独占一行来分隔下一个分块。

业务标签格式为 `[标签名]`，放在摘要标题最前面，用于标识该分块所属的业务类型。常见标签包括但不限于：
- [产品数据] — 产品相关的数据表格
- [活动数据] — 促销活动、积分规则等数据
- [业绩数据] — 销售业绩、排名等数据
- [财务数据] — 价格、费用、收支等数据

请根据表格数据的实际含义选择最贴切的标签。如果以上标签都不合适，可以自定义一个简短的标签名（2-4个字）。

格式示例：
[产品数据] 产品A类数据汇总

## Sheet名称

| 列1 | 列2 | 列3 |
| --- | --- | --- |
| 数据 | 数据 | 数据 |

{delimiter}
[活动数据] 产品B类积分规则

| 列1 | 列2 | 列3 |
| --- | --- | --- |
| 数据 | 数据 | 数据 |

注意：
- 每个分块的摘要标题必须以 `[标签名]` 开头
- 摘要标题应概括该分块表格数据的核心内容
- 最后一个分块后不需要分隔符
- 保留原始的 Markdown 表格格式，不要修改数据"""


# ── 问答类文档分块提示词 ─────────────────────────────────────

QA_SYSTEM_PROMPT = """\
你是一个专业的问答文档分块助手。你的任务是将问答类文档按照问答对进行智能分块。

## 分块规则

1. **问答配对**：每个分块必须包含完整的问答对（问题 + 回答），绝不能将问题和回答拆分到不同分块
2. **相关问题合并**：如果多个问答围绕同一个主题且总长度合理（< 800 字），可以合并为一个分块
3. **独立可理解**：每个分块应当能够独立回答用户的问题，不依赖其他分块
4. **保留编号**：如果原文有问题编号，保留编号信息

## 输出格式

请严格按照以下格式输出，不要添加任何额外的解释或说明：

对于每个分块，先输出一行带业务标签的摘要标题（不带任何 Markdown 标记），然后空一行，输出分块内容，然后用分隔符 `{delimiter}` 独占一行来分隔下一个分块。

业务标签格式为 `[标签名]`，放在摘要标题最前面，用于标识该分块问答所属的业务类型。常见标签包括但不限于：
- [产品问答] — 产品功能、使用方法、成分等问答
- [售后问答] — 售后服务、退换货、投诉等问答
- [健康问答] — 健康知识、调理反应、注意事项等问答

请根据问答内容的实际含义选择最贴切的标签。如果以上标签都不合适，可以自定义一个简短的标签名（2-4个字）。

格式示例：
[产品问答] 关于产品使用方法的问答

问：产品如何使用？
答：每日早晚各一次...

问：使用后多久见效？
答：一般 2-4 周可见明显效果...

{delimiter}
[健康问答] 关于产品成分的问答

问：主要成分是什么？
答：主要成分包括...

注意：
- 每个分块的摘要标题必须以 `[标签名]` 开头
- 摘要标题应概括该分块问答的主题
- 最后一个分块后不需要分隔符
- 不要修改原文内容，只进行切分
- 保留原文的格式和编号"""


# ── 用户提示词模板 ────────────────────────────────────────────

USER_PROMPT_TEMPLATE = """\
源文件：{source_file}

请对以下文本进行语义分块：

---开始---
{text_content}
---结束---"""

USER_PROMPT_TEMPLATE_NO_SOURCE = """\
请对以下文本进行语义分块：

---开始---
{text_content}
---结束---"""


# ── 提示词模板映射 ────────────────────────────────────────────

_SYSTEM_PROMPT_MAP = {
    CONTENT_TYPE_DOCUMENT: DOCUMENT_SYSTEM_PROMPT,
    CONTENT_TYPE_TABLE: TABLE_SYSTEM_PROMPT,
    CONTENT_TYPE_QA: QA_SYSTEM_PROMPT,
}

# 保持向后兼容
SYSTEM_PROMPT_TEMPLATE = DOCUMENT_SYSTEM_PROMPT


# ── 问答类文档自动检测 ────────────────────────────────────────

# 问答特征关键词（出现频率超过阈值则判定为问答类）
_QA_INDICATORS = ("问：", "答：", "Q：", "A：", "Q:", "A:", "问:", "答:", "？\n", "?\n")
_QA_THRESHOLD = 3  # 至少出现 3 次问答特征


def detect_content_type(file_ext: str, text: str) -> str:
    """根据文件扩展名和文本内容自动检测内容类型。

    优先检测问答类（基于文本特征），然后回退到文件扩展名映射。

    Args:
        file_ext: 文件扩展名（如 ".docx"）
        text: 解析后的文本内容

    Returns:
        内容类型常量
    """
    base_type = _EXT_TYPE_MAP.get(file_ext.lower(), CONTENT_TYPE_DOCUMENT)

    # 图片类直接返回，不需要进一步检测
    if base_type == CONTENT_TYPE_IMAGE:
        return CONTENT_TYPE_IMAGE

    # 对文档类内容检测是否为问答格式
    if base_type == CONTENT_TYPE_DOCUMENT:
        qa_count = sum(text.count(indicator) for indicator in _QA_INDICATORS)
        if qa_count >= _QA_THRESHOLD:
            return CONTENT_TYPE_QA

    return base_type


# ── 公共接口 ──────────────────────────────────────────────────


def get_system_prompt(delimiter: str = "---", content_type: str = CONTENT_TYPE_DOCUMENT) -> str:
    """返回指定内容类型的系统提示词。

    Args:
        delimiter: 分块分隔符
        content_type: 内容类型（document / table / qa）

    Returns:
        替换了 {delimiter} 占位符后的系统提示词
    """
    template = _SYSTEM_PROMPT_MAP.get(content_type, DOCUMENT_SYSTEM_PROMPT)
    return template.replace("{delimiter}", delimiter)


def get_user_prompt(text_content: str, source_file: str = "") -> str:
    """返回替换了文本内容占位符的用户提示词。

    Args:
        text_content: 待分块的文本内容
        source_file: 源文件名（可选，帮助 AI 判断业务类型）

    Returns:
        替换了占位符后的用户提示词
    """
    if source_file:
        return USER_PROMPT_TEMPLATE.replace("{text_content}", text_content).replace("{source_file}", source_file)
    return USER_PROMPT_TEMPLATE_NO_SOURCE.replace("{text_content}", text_content)
