From 7a788bf8dc50f9487776df7ebbeeb2819dc1d7fa Mon Sep 17 00:00:00 2001 From: selfrelease Date: Sun, 30 Aug 2026 15:12:33 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=AF=9D=E9=A2=98=E5=8A=A8=E6=80=81?= =?UTF-8?q?=E5=8C=96=20+=20=E8=A6=81=E7=B4=A0=E5=8C=96=E7=AB=8B=E6=A1=88?= =?UTF-8?q?=20+=20=E7=9F=A5=E8=AF=86=E5=BA=93=E5=A2=9E=E5=BC=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 话题动态化: - 新增 POST /topics 端点,AI 根据场景+画像动态生成话题 - 前端3个助手页面改为兜底话题先行,换一批时AI生成 - 去除固化话题列表,支持个性化推荐 要素化立案(对接最高法67类要素表): - 导入68类要素式起诉状模板到知识库(法〔2025〕82号) - 覆盖民事/商事/知识产权/行政/刑事自诉/海事/环境/国家赔偿/执行9领域 - ask-analyze 法务场景自动匹配案由模板 - 新增 POST /element-filing 端点,AI填充要素生成要素式起诉状 - ChatPanel 确认事实后可一键生成要素式起诉状,支持复制全文 知识库增强: - 要素表模板展示全中文化(type/required/标签翻译) - 知识库页面要素表模板结构化展示(案由/要素清单/诉讼请求) - 各类型tab显示数量和总数量 画像翻译完善: - 补充90+个key_facts key中文翻译 - MyProfile多列紧凑布局 Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- api.py | 368 +++++++++++++- fix_element_chinese.py | 89 ++++ seed_elements.py | 372 ++++++++++++++ seed_elements_2.py | 648 ++++++++++++++++++++++++ web/src/components/common/ChatPanel.tsx | 206 +++++++- web/src/lib/api.ts | 38 +- web/src/pages/Decisions.tsx | 201 ++++---- web/src/pages/KnowledgeBase.tsx | 42 +- web/src/pages/LegalAdvisor.tsx | 204 ++++---- web/src/pages/LifeAssistant.tsx | 199 ++++---- web/src/pages/MyProfile.tsx | 314 ++++++++++-- 11 files changed, 2291 insertions(+), 390 deletions(-) create mode 100644 fix_element_chinese.py create mode 100644 seed_elements.py create mode 100644 seed_elements_2.py diff --git a/api.py b/api.py index 7eba9a9..d7ac383 100644 --- a/api.py +++ b/api.py @@ -216,6 +216,7 @@ class AskRequest(BaseModel): question: str scene: str = "legal" emotion_mode: str | None = None + topic: str | None = None """用户补充的事实回答(多轮追问后传入)""" fact_answers: list[FactAnswer] | None = None """手机号(从 JWT token 解析,用于用户画像)""" @@ -274,6 +275,119 @@ class SampleRequest(BaseModel): existing: list[str] | None = None # 已展示的示例,避免重复 +class TopicsRequest(BaseModel): + """动态话题生成请求。""" + scene: str = "legal" + phone: str | None = None # 用户手机号,用于读取画像个性化推荐 + existing: list[str] | None = None # 已展示的话题,避免重复 + + +@app.post("/topics") +def generate_topics(req: TopicsRequest): + """AI 根据场景 + 用户画像动态生成话题列表。 + + 不再固化话题,每次进入页面时 AI 生成 6-8 个话题, + 结合用户画像(行业/规模/常问话题)个性化推荐。 + """ + # 内置话题(降级用) + builtin_topics = { + "legal": [ + {"title": "劳动用工", "desc": "工伤、辞退、欠薪、社保", "samples": ["员工工伤后能否开除?", "拖欠工资怎么追讨?", "未签合同双倍工资怎么算?", "社保没缴全怎么补?"]}, + {"title": "合同审查", "desc": "违约、条款、效力", "samples": ["合同违约金怎么约定?", "对方不履行合同怎么办?", "口头协议有法律效力吗?", "合同条款不公平能改吗?"]}, + {"title": "债权债务", "desc": "欠款、催收、诉讼", "samples": ["客户拖欠货款3个月如何催收?", "借条怎么写才有效?", "债务人不还钱能报警吗?", "超过诉讼时效怎么办?"]}, + {"title": "股东纠纷", "desc": "股权、分红、退股", "samples": ["合伙人要退股怎么谈?", "股东不出资怎么办?", "分红比例怎么定?", "小股东权益被侵害怎么办?"]}, + {"title": "税务风险", "desc": "稽查、发票、合规", "samples": ["收到税务稽查通知怎么办?", "发票开错了怎么处理?", "个体户怎么交税最合理?", "税务罚款能减免吗?"]}, + {"title": "诉讼仲裁", "desc": "起诉、举证、执行", "samples": ["打官司要准备哪些证据?", "仲裁和诉讼哪个更快?", "赢了官司对方不执行怎么办?", "诉讼费用怎么算?"]}, + ], + "decision": [ + {"title": "扩张收缩", "desc": "开店、关店、业务线", "samples": ["现在适合扩张开第二家店吗?", "要不要关闭亏损的业务线?", "新业务线该自营还是加盟?", "应该先扩张还是先巩固?"]}, + {"title": "项目承接", "desc": "大单、长期合同", "samples": ["是否应该接付款周期90天的大单?", "长期框架合同要不要签?", "预付款比例低的项目能接吗?", "客户要求独家合作利弊?"]}, + {"title": "定价策略", "desc": "涨价、降价、促销", "samples": ["该不该降价15%抢竞品客户?", "产品涨价怎么跟客户沟通?", "促销活动会不会损害品牌?", "成本上涨如何调整定价?"]}, + {"title": "招人裁员", "desc": "招聘、解雇、绩效", "samples": ["现在该招人还是裁人?", "裁掉绩效差的员工怎么操作?", "关键岗位招人还是培养?", "外包和正式员工怎么选?"]}, + {"title": "融资合伙", "desc": "融资、合伙、股权", "samples": ["现在适合融资吗?", "合伙人要退股怎么谈条件?", "出让多少股权合适?", "银行贷款还是股权融资?"]}, + {"title": "转型外包", "desc": "转型、外包、调整", "samples": ["业务转型方向怎么选?", "哪些业务可以外包?", "转型期间现金流怎么管理?", "外包质量怎么控?"]}, + ], + "life": [ + {"title": "家庭沟通", "desc": "亲子、夫妻、关系", "samples": ["怎么和青春期的孩子沟通?", "夫妻因工作吵架怎么办?", "家人不支持创业怎么说服?", "工作太忙忽略家人怎么办?"]}, + {"title": "子女教育", "desc": "升学、兴趣、规划", "samples": ["孩子不想上学怎么办?", "兴趣班该报几个?", "要不要送孩子出国?", "孩子成绩下滑怎么沟通?"]}, + {"title": "父母养老", "desc": "养老、医疗、陪伴", "samples": ["父母年纪大了养老方案怎么选?", "异地父母怎么照顾?", "养老院还是居家养老?", "父母医疗费用怎么分担?"]}, + {"title": "睡眠与压力", "desc": "失眠、焦虑、调节", "samples": ["最近睡眠很差怎么改善?", "工作压力大怎么缓解?", "焦虑到影响工作怎么办?", "怎么判断需要看心理医生?"]}, + {"title": "出差日程", "desc": "出行、时间管理", "samples": ["出差频繁怎么兼顾家庭?", "行程太满怎么优化?", "出差期间公司怎么管?", "如何减少无效出差?"]}, + {"title": "健康习惯", "desc": "体检、饮食、运动", "samples": ["体检报告几项异常怎么办?", "久坐怎么改善健康?", "应酬多怎么控制饮食?", "没时间运动怎么办?"]}, + ], + "emotion": [ + {"title": "冷静分析", "desc": "理性拆解问题", "samples": ["最近压力很大睡不着觉", "合伙人背叛了我很愤怒", "明天的谈判我拖延了一周没准备", "感觉撑不下去了"]}, + {"title": "陪伴疏导", "desc": "倾听与共情", "samples": ["今天和合伙人吵了一架", "员工集体离职我很受挫", "家里人不理解我的压力", "感觉自己很孤独"]}, + {"title": "强力推动", "desc": "直面问题推动行动", "samples": ["我知道该怎么做但就是拖延", "害怕做决定怎么办?", "明知道该辞退但下不了手", "想改变但总是回到老路"]}, + ], + } + + if not kimi: + return {"topics": builtin_topics.get(req.scene, builtin_topics["legal"])} + + # 读取用户画像,个性化话题 + profile_ctx = "" + if req.phone: + try: + profile = profile_store.get(req.phone) + profile_ctx = build_profile_context(profile) + except Exception: + pass + + scene_desc = { + "legal": "法律/法务问题,如劳动用工、合同审查、债权债务、股东纠纷、税务风险、诉讼仲裁、知识产权、交通事故、婚姻财产、房产纠纷、消费维权等", + "decision": "经营决策问题,如扩张收缩、定价策略、招人裁员、融资合伙、项目承接、业务转型、投资理财、风险管理等", + "life": "个人生活问题,如家庭沟通、子女教育、父母养老、健康习惯、时间管理、出行规划等(不是企业经营问题)", + "emotion": "情绪与心理问题,如压力疏导、关系困惑、自我认知、传统文化反思等", + } + + existing_str = "" + if req.existing: + existing_str = f"\n已展示过的话题(避免重复):{','.join(req.existing)}" + + prompt = f"""你是左右(BossAi)的{scene_desc.get(req.scene, scene_desc['legal'])}助手。 +请生成6-8个话题,每个话题包含标题(2-4字)、简短描述(10-15字)、4个示例问题。 + +{profile_ctx} + +要求: +1. 话题要覆盖该场景下不同方向,不要只集中在某一类 +2. 结合用户画像(如有)推荐个性化话题 +3. 示例问题要具体、贴近中小企业老板实际 +4. 返回JSON数组格式:[{{"title":"话题名","desc":"简短描述","samples":["问题1","问题2","问题3","问题4"]}}] +5. 只返回JSON,不要其他文字{existing_str}""" + + try: + answer = kimi.chat([{"role": "user", "content": prompt}], temperature=0.8) + answer = answer.strip() + if answer.startswith("```"): + answer = answer.split("\n", 1)[1] if "\n" in answer else answer[3:] + if answer.endswith("```"): + answer = answer[:-3] + answer = answer.strip().replace("\u201c", '"').replace("\u201d", '"') + start = answer.find("[") + end = answer.rfind("]") + if start == -1 or end == -1: + return {"topics": builtin_topics.get(req.scene, builtin_topics["legal"])} + topics = json.loads(answer[start:end + 1]) + # 校验结构 + valid_topics = [] + for t in topics: + if isinstance(t, dict) and t.get("title") and t.get("samples"): + valid_topics.append({ + "title": str(t["title"])[:10], + "desc": str(t.get("desc", ""))[:30], + "samples": [str(s) for s in t["samples"] if isinstance(s, str) and s.strip()][:4], + }) + if len(valid_topics) < 3: + return {"topics": builtin_topics.get(req.scene, builtin_topics["legal"])} + return {"topics": valid_topics[:8]} + except Exception as e: + import logging + logging.warning(f"/topics AI 生成失败: {type(e).__name__}: {e}") + return {"topics": builtin_topics.get(req.scene, builtin_topics["legal"])} + + @app.post("/samples") def generate_samples(req: SampleRequest): """用 AI 生成场景示例问题,供前端"换一批"使用。 @@ -493,24 +607,103 @@ def ask_analyze(sid: str, req: AskRequest, authorization: str | None = Header(de req.question, req.scene, answers, kimi_client=kimi, ) - # 收集用户画像中的已知事实(带入内容) + # 收集用户画像中的已知事实(带入内容),按场景过滤相关性 profile_facts: list[dict] = [] if req.phone: try: profile = profile_store.get(req.phone) + # 标准画像字段:所有场景通用 if profile.industry: profile_facts.append({"dim_key": "industry", "dim_desc": "行业", "answer": profile.industry}) if profile.company_size: profile_facts.append({"dim_key": "company_size", "dim_desc": "企业规模", "answer": profile.company_size}) if profile.role: profile_facts.append({"dim_key": "role", "dim_desc": "角色", "answer": profile.role}) - if profile.risk_tolerance: - profile_facts.append({"dim_key": "risk_tolerance", "dim_desc": "风险偏好", "answer": profile.risk_tolerance}) - if profile.decision_style: - profile_facts.append({"dim_key": "decision_style", "dim_desc": "决策风格", "answer": profile.decision_style}) + # 风险偏好和决策风格仅经营决策场景带入 + if req.scene == "decision": + if profile.risk_tolerance: + profile_facts.append({"dim_key": "risk_tolerance", "dim_desc": "风险偏好", "answer": profile.risk_tolerance}) + if profile.decision_style: + profile_facts.append({"dim_key": "decision_style", "dim_desc": "决策风格", "answer": profile.decision_style}) + # key_facts:按话题相关性过滤(更精准) if profile.key_facts: + # 话题 → 相关 key_facts 关键词映射 + TOPIC_FACT_KEYWORDS = { + # ===== 法务参谋 ===== + "劳动用工": {"region", "company_type", "team_ability", "communication", + "medical_proof", "contract_terms", "medical_period", + "injury_situation", "work_injury_details", "work_injury_insurance", + "performance_assessment", "relevant_legal_provisions", + "employee_count", "salary_status", "social_security", "severance", + "working_years", "probation_period", "termination_reason", + "overtime_status"}, + "合同审查": {"contract_terms", "contract_dispute", "company_type", + "relevant_legal_provisions", "region", "partnership"}, + "债权债务": {"debt_amount", "litigation_status", "financial_status", + "company_type", "relevant_legal_provisions"}, + "股东纠纷": {"shareholder_structure", "partnership", "company_type", + "litigation_status", "relevant_legal_provisions"}, + "税务风险": {"tax_risk", "financial_status", "company_type", + "relevant_legal_provisions"}, + # ===== 经营决策 ===== + "扩张收缩": {"market_potential", "financial_status", "team_ability", + "region", "company_type", "expansion_plan", "competitor", + "cash_flow", "alternative_option", "alternative_solution"}, + "项目承接": {"financial_status", "cash_flow", "team_ability", + "contract_terms", "customer_concentration", "alternative_option"}, + "招人用人": {"team_ability", "employee_count", "salary_status", + "social_security", "company_type", "region"}, + "降价定价": {"financial_status", "competitor", "customer_concentration", + "supply_chain", "cash_flow"}, + "业务线调整": {"market_potential", "financial_status", "competitor", + "alternative_option", "alternative_solution", "supply_chain", + "business_model"}, + "融资合伙": {"funding_stage", "financial_status", "shareholder_structure", + "partnership", "company_type", "cash_flow", "asset_status", + "liability", "alternative_option"}, + # ===== 生活助理 ===== + "健康管理": {"health_status", "region"}, + "家庭事务": {"family_situation", "region", "company_type"}, + "出行规划": {"travel_plan", "region"}, + "子女教育": {"education_background", "family_situation"}, + "消费理财": {"financial_status", "revenue", "asset_status", "liability"}, + # ===== 情绪中心 ===== + "情绪倾诉": {"communication_style", "stress_source", "personality", + "family_situation"}, + "压力疏导": {"stress_source", "communication_style", "personality"}, + "关系困惑": {"communication_style", "family_situation", "personality"}, + "传统文化": {"personality", "communication_style"}, + } + # 先按话题匹配,匹配不到则按场景兜底 + topic_keys = TOPIC_FACT_KEYWORDS.get(req.topic or "", set()) + if not topic_keys: + # 场景兜底关键词 + SCENE_FACT_KEYWORDS = { + "legal": {"region", "company_type", "team_ability", "communication", + "medical_proof", "contract_terms", "medical_period", + "injury_situation", "legal_procedures", "work_injury_details", + "work_injury_insurance", "performance_assessment", + "relevant_legal_provisions", "employee_count", "salary_status", + "social_security", "severance", "working_years", "probation_period", + "termination_reason", "overtime_status", "contract_dispute", + "debt_amount", "tax_risk", "litigation_status", "shareholder_structure", + "partnership"}, + "decision": {"market_potential", "alternative_option", "alternative_solution", + "financial_status", "revenue", "profit_status", "cash_flow", + "asset_status", "liability", "business_model", "funding_stage", + "expansion_plan", "competitor", "customer_concentration", + "supply_chain", "export_capability", "team_ability", + "region", "company_type"}, + "life": {"region", "company_type", "employee_count", "revenue", + "family_situation", "health_status", "travel_plan", + "important_event", "education_background"}, + "emotion": {"communication_style", "stress_source", "personality", + "decision_style", "family_situation"}, + } + topic_keys = SCENE_FACT_KEYWORDS.get(req.scene, set()) for k, v in profile.key_facts.items(): - profile_facts.append({"dim_key": f"fact_{k}", "dim_desc": k, "answer": str(v)}) + if k.lower() in topic_keys or k in topic_keys: + profile_facts.append({"dim_key": f"fact_{k}", "dim_desc": k, "answer": str(v)}) except Exception: pass @@ -526,6 +719,34 @@ def ask_analyze(sid: str, req: AskRequest, authorization: str | None = Header(de "profile_facts": profile_facts, } else: + # 事实充分,法务场景尝试匹配要素表模板 + element_template = None + if req.scene == "legal" and kimi: + try: + # 从知识库检索要素表模板 + docs = knowledge.search(req.question, limit=3, doc_type="element_template") + if docs: + # AI 判断最匹配的案由 + cause_names = [json.loads(d.get("content", "{}")).get("cause_of_action", d.get("title", "")) for d in docs] + prompt = f"""用户问题:{req.question} +事实摘要:{meta.get("fact_summary", "")} + +候选案由:{json.dumps(cause_names, ensure_ascii=False)} + +请判断用户的问题最匹配哪个案由,只返回案由名称,不要其他文字。""" + matched_cause = kimi.chat([{"role": "user", "content": prompt}], temperature=0.1).strip() + # 找到匹配的模板 + for d in docs: + tmpl = json.loads(d.get("content", "{}")) + if tmpl.get("cause_of_action") == matched_cause or matched_cause in d.get("title", ""): + element_template = tmpl + break + # 没精确匹配就用第一个 + if not element_template and docs: + element_template = json.loads(docs[0].get("content", "{}")) + except Exception: + pass + return { "need_ask": False, "need_analysis": True, @@ -534,9 +755,127 @@ def ask_analyze(sid: str, req: AskRequest, authorization: str | None = Header(de "question_type": meta["analysis"]["question_type"], "risk_level": card.level, "profile_facts": profile_facts, + "element_template": element_template, } +class ElementFilingRequest(BaseModel): + """要素化立案生成请求。""" + question: str + cause_of_action: str # 案由 + fact_answers: list[FactAnswer] = [] # 用户确认的事实 + template: dict | None = None # 要素表模板(前端传回) + + +@app.post("/sessions/{sid}/element-filing") +def generate_element_filing(sid: str, req: ElementFilingRequest, authorization: str | None = Header(default=None)): + """根据确认的事实 + 要素表模板,AI 生成要素式起诉状。 + + 流程: + 1. 用户确认事实后调用此端点 + 2. AI 根据案由模板 + 确认事实,填充要素 + 3. 返回结构化要素式起诉状 + + Returns: + { + "cause_of_action": str, # 案由 + "elements": [...], # 已填充的要素列表 + "claims": [...], # 诉讼请求 + "filing_text": str, # 可导出的要素式起诉状文本 + } + """ + try: + sessions._active(sid) + except KeyError as e: + raise HTTPException(410, str(e)) + + if not kimi: + raise HTTPException(503, "AI 服务不可用") + + # 获取要素表模板 + tmpl = req.template + if not tmpl: + # 从知识库检索 + docs = knowledge.search(req.cause_of_action, limit=1, doc_type="element_template") + if docs: + tmpl = json.loads(docs[0].get("content", "{}")) + if not tmpl: + raise HTTPException(404, f"未找到案由'{req.cause_of_action}'的要素表模板") + + # 构造事实摘要 + facts_str = "\n".join([f"- {a.dim_desc}: {a.answer}" for a in req.fact_answers]) + + # AI 填充要素 + elements_json = json.dumps(tmpl.get("elements", []), ensure_ascii=False) + prompt = f"""你是法律文书助手。根据用户描述和确认的事实,填充要素式起诉状的各要素。 + +案由:{tmpl.get("cause_of_action", req.cause_of_action)} +要素模板:{elements_json} + +用户问题:{req.question} +确认事实: +{facts_str} + +请根据以上信息,为每个要素填充具体值。如果信息不足,填写"待补充"。 +返回JSON数组格式:[{{"key":"要素key","label":"要素标签","value":"填充值"}}] +只返回JSON,不要其他文字。""" + + try: + answer = kimi.chat([{"role": "user", "content": prompt}], temperature=0.1) + answer = answer.strip() + if answer.startswith("```"): + answer = answer.split("\n", 1)[1] if "\n" in answer else answer[3:] + if answer.endswith("```"): + answer = answer[:-3] + answer = answer.strip().replace("\u201c", '"').replace("\u201d", '"') + start = answer.find("[") + end = answer.rfind("]") + if start == -1 or end == -1: + raise ValueError("AI 返回格式错误") + filled_elements = json.loads(answer[start:end + 1]) + except Exception as e: + raise HTTPException(500, f"要素填充失败: {e}") + + # 生成可导出的要素式起诉状文本 + cause = tmpl.get("cause_of_action", req.cause_of_action) + claims = tmpl.get("claims", []) + claims_str = "\n".join([f" ☐ {c}" for c in claims]) + elements_text = "\n".join([ + f" {e.get('label', e.get('key', ''))}: {e.get('value', '待补充')}" + for e in filled_elements + ]) + + filing_text = f"""要素式起诉状 + +案由:{cause} + +一、当事人信息 + 原告:待填写 + 被告:待填写 + +二、诉讼请求 +{claims_str} + +三、事实和理由(要素表) +{elements_text} + +四、证据清单 + 待补充 + +五、对纠纷解决方式的意愿 + ☐ 同意调解 ☐ 不同意调解 + +说明:本起诉状依据最高人民法院《部分案件起诉状答辩状示范文本》(法〔2025〕82号)生成, +所填要素供参考,请根据实际情况修改后提交法院。""" + + return { + "cause_of_action": cause, + "elements": filled_elements, + "claims": claims, + "filing_text": filing_text, + } + + @app.post("/sessions/{sid}/ask-stream") def ask_stream(sid: str, req: AskRequest, authorization: str | None = Header(default=None)): req.phone = get_current_phone(authorization) @@ -751,8 +1090,21 @@ def list_summaries(limit: int = 20): @app.get("/knowledge") def list_knowledge(doc_type: str | None = None, limit: int = 50): - """列出知识库文档,支持按类型筛选。""" - return {"results": knowledge.list_all(doc_type=doc_type, limit=limit)} + """列出知识库文档,支持按类型筛选。返回各类型计数供前端展示。""" + results = knowledge.list_all(doc_type=doc_type, limit=limit) + # 统计各类型数量 + counts: dict[str, int] = {} + try: + with knowledge._conn() as conn: + with conn.cursor() as cur: + cur.execute( + "SELECT doc_type, COUNT(*) FROM knowledge_docs GROUP BY doc_type" + ) + counts = {row[0]: row[1] for row in cur.fetchall()} + except Exception: + pass + total = sum(counts.values()) + return {"results": results, "counts": counts, "total": total} @app.post("/knowledge") diff --git a/fix_element_chinese.py b/fix_element_chinese.py new file mode 100644 index 0000000..6766445 --- /dev/null +++ b/fix_element_chinese.py @@ -0,0 +1,89 @@ +"""将知识库中要素表模板的英文字段值全部转为中文。 + +转换内容: +- type: text→文本, textarea→长文本, date→日期, number→数字, select→选择, boolean→是否 +- required: true→是, false→否 +- doc_type 展示标签: element_template→要素表模板(仅展示用,存储值不变以兼容检索) +""" +import json +import sys +import os +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +from bossai import KnowledgeStore + +TYPE_MAP = { + "text": "文本", + "textarea": "长文本", + "date": "日期", + "number": "数字", + "select": "选择", + "boolean": "是否", +} + +REQUIRED_MAP = { + True: "是", + False: "否", +} + + +def convert_template(tmpl: dict) -> dict: + """递归转换模板中的英文值为中文。""" + # 转换 elements 中的 type 和 required + elements = tmpl.get("elements", []) + for e in elements: + if "type" in e and e["type"] in TYPE_MAP: + e["type"] = TYPE_MAP[e["type"]] + if "required" in e: + val = e["required"] + if val in REQUIRED_MAP: + e["required"] = REQUIRED_MAP[val] + elif isinstance(val, str) and val.lower() == "true": + e["required"] = "是" + elif isinstance(val, str) and val.lower() == "false": + e["required"] = "否" + return tmpl + + +def main(): + store = KnowledgeStore() + with store._conn() as conn: + with conn.cursor() as cur: + cur.execute( + "SELECT id, title, content FROM knowledge_docs WHERE doc_type='element_template' ORDER BY id" + ) + rows = cur.fetchall() + print(f"找到 {len(rows)} 条要素表模板,开始转换...") + + updated = 0 + for doc_id, title, content in rows: + try: + tmpl = json.loads(content) + tmpl = convert_template(tmpl) + new_content = json.dumps(tmpl, ensure_ascii=False, indent=2) + if new_content != content: + cur.execute( + "UPDATE knowledge_docs SET content=%s WHERE id=%s", + (new_content, doc_id), + ) + updated += 1 + except Exception as e: + print(f" 跳过 {title}: {e}") + + print(f"已转换 {updated}/{len(rows)} 条记录") + + # 验证 + with store._conn() as conn: + with conn.cursor() as cur: + cur.execute( + "SELECT content FROM knowledge_docs WHERE doc_type='element_template' LIMIT 1" + ) + row = cur.fetchone() + if row: + tmpl = json.loads(row[0]) + print(f"\n验证示例({tmpl.get('cause_of_action', '')}):") + for e in tmpl.get("elements", [])[:3]: + print(f" {e.get('label')}: type={e.get('type')}, required={e.get('required')}") + + +if __name__ == "__main__": + main() diff --git a/seed_elements.py b/seed_elements.py new file mode 100644 index 0000000..58f7547 --- /dev/null +++ b/seed_elements.py @@ -0,0 +1,372 @@ +"""最高法67类要素式起诉状模板 - 种子数据导入。 + +将最高法2025年7月14日全面推广的67类要素式起诉状、答辩状示范文本 +导入知识库(doc_type='element_template'),供法务参谋"要素化立案"使用。 + +每类模板包含: +- 案由名称 +- 适用场景 +- 要素清单(结构化字段) +- 诉讼请求选项 +- 事实和理由要素 + +数据来源:最高人民法院、司法部、中华全国律师协会联合印发 +《部分案件起诉状答辩状示范文本》(法〔2025〕82号) +""" +import json +import os +import sys + +# 添加项目根目录到 path +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +from bossai import KnowledgeStore + + +# ===== 67类要素表模板(按领域分组) ===== +ELEMENT_TEMPLATES = [ + # ===== 民事类(9类) ===== + { + "title": "离婚纠纷要素式起诉状", + "category": "民事", + "cause_of_action": "离婚纠纷", + "applicable": "夫妻一方起诉离婚,涉及子女抚养、财产分割、债务承担等", + "elements": [ + {"key": "marriage_date", "label": "结婚登记日期", "type": "date", "required": True}, + {"key": "marriage_place", "label": "结婚登记地点", "type": "text", "required": True}, + {"key": "children_info", "label": "子女情况(姓名/年龄/性别)", "type": "text", "required": False}, + {"key": "separation_date", "label": "分居日期", "type": "date", "required": False}, + {"key": "divorce_reason", "label": "离婚原因", "type": "select", "options": ["感情不和", "家庭暴力", "出轨", "赌博吸毒", "分居满两年", "其他"], "required": True}, + {"key": "property_dispute", "label": "是否有财产争议", "type": "boolean", "required": True}, + {"key": "property_detail", "label": "财产情况(房产/车辆/存款等)", "type": "textarea", "required": False}, + {"key": "debt_detail", "label": "债务情况", "type": "textarea", "required": False}, + {"key": "child_support_claim", "label": "子女抚养诉求", "type": "textarea", "required": False}, + {"key": "property_claim", "label": "财产分割诉求", "type": "textarea", "required": False}, + ], + "claims": ["判决离婚", "子女抚养权", "抚养费", "财产分割", "债务承担"], + }, + { + "title": "买卖合同纠纷要素式起诉状", + "category": "民事", + "cause_of_action": "买卖合同纠纷", + "applicable": "商品买卖中拖欠货款、质量争议、交货延迟等", + "elements": [ + {"key": "contract_date", "label": "合同签订日期", "type": "date", "required": True}, + {"key": "contract_parties", "label": "合同双方", "type": "text", "required": True}, + {"key": "goods_desc", "label": "买卖标的(商品名称/规格/数量)", "type": "textarea", "required": True}, + {"key": "total_amount", "label": "合同总金额", "type": "number", "required": True}, + {"key": "paid_amount", "label": "已付金额", "type": "number", "required": True}, + {"key": "unpaid_amount", "label": "欠付金额", "type": "number", "required": True}, + {"key": "delivery_status", "label": "交货情况", "type": "select", "options": ["已全部交货", "部分交货", "未交货", "对方拒收"], "required": True}, + {"key": "quality_issue", "label": "是否有质量问题", "type": "boolean", "required": True}, + {"key": "breach_detail", "label": "违约情况描述", "type": "textarea", "required": True}, + {"key": "evidence_list", "label": "证据清单", "type": "textarea", "required": False}, + {"key": "arbitration_clause", "label": "是否有仲裁/管辖约定", "type": "boolean", "required": True}, + ], + "claims": ["支付货款", "支付违约金", "解除合同", "赔偿损失", "继续履行"], + }, + { + "title": "民间借贷纠纷要素式起诉状", + "category": "民事", + "cause_of_action": "民间借贷纠纷", + "applicable": "个人或企业间借贷,借款人未按约还款", + "elements": [ + {"key": "loan_date", "label": "借款日期", "type": "date", "required": True}, + {"key": "loan_amount", "label": "借款金额", "type": "number", "required": True}, + {"key": "interest_rate", "label": "约定利率", "type": "text", "required": False}, + {"key": "loan_term", "label": "借款期限", "type": "text", "required": True}, + {"key": "repayment_date", "label": "约定还款日期", "type": "date", "required": True}, + {"key": "repaid_amount", "label": "已还金额", "type": "number", "required": True}, + {"key": "unpaid_amount", "label": "未还金额", "type": "number", "required": True}, + {"key": "has_iou", "label": "是否有借条/欠条", "type": "boolean", "required": True}, + {"key": "transfer_proof", "label": "是否有转账记录", "type": "boolean", "required": True}, + {"key": "guarantor", "label": "是否有担保人", "type": "boolean", "required": False}, + {"key": "guarantor_info", "label": "担保人信息", "type": "text", "required": False}, + {"key": "collection_record", "label": "催款记录", "type": "textarea", "required": False}, + ], + "claims": ["偿还借款本金", "支付利息", "支付逾期利息", "担保人承担连带责任"], + }, + { + "title": "劳动争议纠纷要素式起诉状", + "category": "民事", + "cause_of_action": "劳动争议纠纷", + "applicable": "劳动者与用人单位之间的劳动合同、工资、工伤、解除等争议", + "elements": [ + {"key": "employment_start", "label": "入职日期", "type": "date", "required": True}, + {"key": "employment_end", "label": "离职/解除日期", "type": "date", "required": False}, + {"key": "position", "label": "岗位/职务", "type": "text", "required": True}, + {"key": "salary_standard", "label": "工资标准(月薪)", "type": "number", "required": True}, + {"key": "salary_payment", "label": "工资发放方式", "type": "select", "options": ["银行转账", "现金", "微信/支付宝", "混合"], "required": True}, + {"key": "has_contract", "label": "是否签订书面劳动合同", "type": "boolean", "required": True}, + {"key": "has_social_security", "label": "是否缴纳社保", "type": "boolean", "required": True}, + {"key": "dispute_type", "label": "争议类型", "type": "select", "options": ["拖欠工资", "未签合同双倍工资", "违法解除赔偿金", "经济补偿金", "工伤待遇", "加班费", "未缴社保损失", "竞业限制"], "required": True}, + {"key": "arbitration_result", "label": "仲裁前置情况(案号/结果)", "type": "textarea", "required": True}, + {"key": "claim_amount", "label": "诉求金额", "type": "number", "required": True}, + {"key": "claim_detail", "label": "诉求明细", "type": "textarea", "required": True}, + {"key": "evidence_list", "label": "证据清单(合同/工资条/考勤/聊天记录等)", "type": "textarea", "required": False}, + ], + "claims": ["支付拖欠工资", "支付经济补偿金", "支付违法解除赔偿金", "支付未签合同双倍工资差额", "支付加班费", "补缴社保", "工伤待遇赔偿"], + }, + { + "title": "机动车交通事故责任纠纷要素式起诉状", + "category": "民事", + "cause_of_action": "机动车交通事故责任纠纷", + "applicable": "机动车交通事故造成人身伤亡或财产损失", + "elements": [ + {"key": "accident_date", "label": "事故发生日期", "type": "date", "required": True}, + {"key": "accident_location", "label": "事故地点", "type": "text", "required": True}, + {"key": "accident_responsibility", "label": "事故责任认定", "type": "select", "options": ["全责", "主要责任", "同等责任", "次要责任", "无责任"], "required": True}, + {"key": "has_injury", "label": "是否有人身伤害", "type": "boolean", "required": True}, + {"key": "injury_detail", "label": "伤情描述", "type": "textarea", "required": False}, + {"key": "hospital_days", "label": "住院天数", "type": "number", "required": False}, + {"key": "disability_level", "label": "伤残等级(如有)", "type": "text", "required": False}, + {"key": "vehicle_damage", "label": "车辆损失金额", "type": "number", "required": False}, + {"key": "medical_expense", "label": "医疗费", "type": "number", "required": False}, + {"key": "lost_income", "label": "误工费", "type": "number", "required": False}, + {"key": "nursing_fee", "label": "护理费", "type": "number", "required": False}, + {"key": "nutrition_fee", "label": "营养费", "type": "number", "required": False}, + {"key": "transport_fee", "label": "交通费", "type": "number", "required": False}, + {"key": "spiritual_compensation", "label": "精神损害抚慰金", "type": "number", "required": False}, + {"key": "insurance_type", "label": "对方保险类型", "type": "select", "options": ["交强险", "商业三者险", "无保险", "不详"], "required": True}, + {"key": "has_police_report", "label": "是否有交警事故认定书", "type": "boolean", "required": True}, + ], + "claims": ["医疗费", "误工费", "护理费", "营养费", "住院伙食补助费", "交通费", "残疾赔偿金", "精神损害抚慰金", "车辆维修费", "财产损失赔偿"], + }, + { + "title": "房屋买卖合同纠纷要素式起诉状", + "category": "民事", + "cause_of_action": "房屋买卖合同纠纷", + "applicable": "房屋买卖中逾期交房、质量问题、一房多卖、过户争议等", + "elements": [ + {"key": "contract_date", "label": "合同签订日期", "type": "date", "required": True}, + {"key": "property_info", "label": "房屋信息(地址/面积/类型)", "type": "textarea", "required": True}, + {"key": "total_price", "label": "房屋总价", "type": "number", "required": True}, + {"key": "paid_amount", "label": "已付金额", "type": "number", "required": True}, + {"key": "payment_method", "label": "付款方式", "type": "select", "options": ["全款", "按揭贷款", "分期"], "required": True}, + {"key": "delivery_date", "label": "约定交房日期", "type": "date", "required": True}, + {"key": "actual_delivery", "label": "实际交房日期", "type": "date", "required": False}, + {"key": "transfer_date", "label": "约定过户日期", "type": "date", "required": False}, + {"key": "dispute_type", "label": "争议类型", "type": "select", "options": ["逾期交房", "质量问题", "一房多卖", "逾期过户", "面积差异", "合同解除"], "required": True}, + {"key": "breach_detail", "label": "违约情况描述", "type": "textarea", "required": True}, + ], + "claims": ["继续履行合同", "解除合同", "退还房款", "支付违约金", "赔偿损失", "协助过户"], + }, + { + "title": "房屋租赁合同纠纷要素式起诉状", + "category": "民事", + "cause_of_action": "房屋租赁合同纠纷", + "applicable": "房屋租赁中拖欠租金、提前退租、押金退还、维修责任等", + "elements": [ + {"key": "lease_start", "label": "租赁起始日期", "type": "date", "required": True}, + {"key": "lease_end", "label": "租赁终止日期", "type": "date", "required": True}, + {"key": "monthly_rent", "label": "月租金", "type": "number", "required": True}, + {"key": "deposit", "label": "押金金额", "type": "number", "required": True}, + {"key": "paid_months", "label": "已付租金月数", "type": "number", "required": True}, + {"key": "unpaid_rent", "label": "拖欠租金金额", "type": "number", "required": False}, + {"key": "dispute_type", "label": "争议类型", "type": "select", "options": ["拖欠租金", "提前退租", "押金不退", "房屋损坏", "擅自转租", "维修责任"], "required": True}, + {"key": "breach_detail", "label": "违约情况描述", "type": "textarea", "required": True}, + ], + "claims": ["支付拖欠租金", "支付违约金", "解除租赁合同", "退还押金", "赔偿房屋损坏", "腾退房屋"], + }, + { + "title": "建设工程施工合同纠纷要素式起诉状", + "category": "民事", + "cause_of_action": "建设工程施工合同纠纷", + "applicable": "工程建设中工程款拖欠、质量问题、工期延误等", + "elements": [ + {"key": "contract_date", "label": "合同签订日期", "type": "date", "required": True}, + {"key": "project_name", "label": "工程名称", "type": "text", "required": True}, + {"key": "project_location", "label": "工程地点", "type": "text", "required": True}, + {"key": "contract_amount", "label": "合同金额", "type": "number", "required": True}, + {"key": "completed_amount", "label": "已完成工程量金额", "type": "number", "required": True}, + {"key": "paid_amount", "label": "已付工程款", "type": "number", "required": True}, + {"key": "unpaid_amount", "label": "欠付工程款", "type": "number", "required": True}, + {"key": "completion_date", "label": "约定竣工日期", "type": "date", "required": True}, + {"key": "actual_completion", "label": "实际竣工日期", "type": "date", "required": False}, + {"key": "has_acceptance", "label": "是否已验收", "type": "boolean", "required": True}, + {"key": "quality_issue", "label": "是否有质量问题", "type": "boolean", "required": True}, + {"key": "dispute_type", "label": "争议类型", "type": "select", "options": ["拖欠工程款", "工期延误", "质量问题", "合同解除", "结算争议"], "required": True}, + ], + "claims": ["支付工程款", "支付逾期付款利息", "赔偿工期延误损失", "修复质量问题", "确认工程价款优先受偿权"], + }, + { + "title": "物业服务合同纠纷要素式起诉状", + "category": "民事", + "cause_of_action": "物业服务合同纠纷", + "applicable": "业主与物业公司之间的物业费、服务质量等争议", + "elements": [ + {"key": "property_address", "label": "房屋地址", "type": "text", "required": True}, + {"key": "property_area", "label": "房屋面积", "type": "number", "required": True}, + {"key": "fee_standard", "label": "物业费标准(元/平米/月)", "type": "number", "required": True}, + {"key": "unpaid_period", "label": "欠费期间", "type": "text", "required": True}, + {"key": "unpaid_amount", "label": "欠费金额", "type": "number", "required": True}, + {"key": "service_issue", "label": "物业服务问题", "type": "textarea", "required": False}, + {"key": "complaint_record", "label": "投诉记录", "type": "textarea", "required": False}, + ], + "claims": ["支付物业费", "支付滞纳金", "改善服务质量", "赔偿损失"], + }, + + # ===== 商事类(8类) ===== + { + "title": "金融借款合同纠纷要素式起诉状", + "category": "商事", + "cause_of_action": "金融借款合同纠纷", + "applicable": "银行等金融机构借款逾期、担保追偿等", + "elements": [ + {"key": "loan_date", "label": "借款日期", "type": "date", "required": True}, + {"key": "loan_amount", "label": "借款金额", "type": "number", "required": True}, + {"key": "interest_rate", "label": "借款利率", "type": "text", "required": True}, + {"key": "loan_term", "label": "借款期限", "type": "text", "required": True}, + {"key": "repayment_method", "label": "还款方式", "type": "select", "options": ["等额本息", "等额本金", "到期还本付息", "按月付息到期还本"], "required": True}, + {"key": "paid_amount", "label": "已还本金", "type": "number", "required": True}, + {"key": "unpaid_principal", "label": "欠付本金", "type": "number", "required": True}, + {"key": "unpaid_interest", "label": "欠付利息", "type": "number", "required": True}, + {"key": "has_mortgage", "label": "是否有抵押", "type": "boolean", "required": True}, + {"key": "mortgage_detail", "label": "抵押物情况", "type": "textarea", "required": False}, + {"key": "has_guarantor", "label": "是否有保证人", "type": "boolean", "required": True}, + {"key": "guarantee_type", "label": "保证方式", "type": "select", "options": ["连带责任保证", "一般保证", "无"], "required": False}, + ], + "claims": ["偿还借款本金", "支付利息及罚息", "实现抵押权", "保证人承担连带清偿责任"], + }, + { + "title": "信用卡纠纷要素式起诉状", + "category": "商事", + "cause_of_action": "信用卡纠纷", + "applicable": "信用卡透支逾期、盗刷争议等", + "elements": [ + {"key": "card_type", "label": "信用卡类型", "type": "select", "options": ["贷记卡", "准贷记卡"], "required": True}, + {"key": "credit_limit", "label": "信用额度", "type": "number", "required": True}, + {"key": "overdue_start", "label": "逾期起始日期", "type": "date", "required": True}, + {"key": "overdue_principal", "label": "欠付本金", "type": "number", "required": True}, + {"key": "overdue_interest", "label": "欠付利息", "type": "number", "required": False}, + {"key": "overdue_fee", "label": "欠付违约金/滞纳金", "type": "number", "required": False}, + {"key": "has_fraud", "label": "是否涉及盗刷/欺诈", "type": "boolean", "required": True}, + ], + "claims": ["偿还透支本金", "支付利息", "支付违约金", "赔偿盗刷损失"], + }, + { + "title": "融资租赁合同纠纷要素式起诉状", + "category": "商事", + "cause_of_action": "融资租赁合同纠纷", + "applicable": "融资租赁中租金拖欠、租赁物取回等", + "elements": [ + {"key": "contract_date", "label": "合同签订日期", "type": "date", "required": True}, + {"key": "lease_object", "label": "租赁物名称及型号", "type": "text", "required": True}, + {"key": "total_rent", "label": "租金总额", "type": "number", "required": True}, + {"key": "lease_term", "label": "租赁期限", "type": "text", "required": True}, + {"key": "paid_rent", "label": "已付租金", "type": "number", "required": True}, + {"key": "unpaid_rent", "label": "欠付租金", "type": "number", "required": True}, + {"key": "dispute_type", "label": "争议类型", "type": "select", "options": ["拖欠租金", "收回租赁物", "合同解除", "租赁物损坏"], "required": True}, + ], + "claims": ["支付拖欠租金", "支付违约金", "解除融资租赁合同", "收回租赁物", "赔偿损失"], + }, + { + "title": "保证保险合同纠纷要素式起诉状", + "category": "商事", + "cause_of_action": "保证保险合同纠纷", + "applicable": "保证保险(如贷款保证险)理赔争议", + "elements": [ + {"key": "insurance_date", "label": "保险签订日期", "type": "date", "required": True}, + {"key": "insurance_amount", "label": "保险金额", "type": "number", "required": True}, + {"key": "premium", "label": "保费金额", "type": "number", "required": True}, + {"key": "claim_event", "label": "理赔事由", "type": "textarea", "required": True}, + {"key": "claim_amount", "label": "理赔金额", "type": "number", "required": True}, + {"key": "claim_date", "label": "理赔申请日期", "type": "date", "required": True}, + {"key": "insurer_response", "label": "保险公司处理结果", "type": "textarea", "required": True}, + ], + "claims": ["支付保险金", "支付逾期理赔利息", "赔偿损失"], + }, + + # ===== 知识产权类(9类) - 精简 ===== + { + "title": "侵害商标权纠纷要素式起诉状", + "category": "知识产权", + "cause_of_action": "侵害商标权纠纷", + "applicable": "他人未经许可使用相同或近似商标", + "elements": [ + {"key": "trademark_name", "label": "注册商标名称", "type": "text", "required": True}, + {"key": "trademark_no", "label": "商标注册号", "type": "text", "required": True}, + {"key": "trademark_class", "label": "核定使用商品/服务类别", "type": "text", "required": True}, + {"key": "infringement_act", "label": "侵权行为", "type": "select", "options": ["假冒", "仿冒", "销售侵权商品", "反向假冒", "其他"], "required": True}, + {"key": "infringement_detail", "label": "侵权行为描述", "type": "textarea", "required": True}, + {"key": "infringement_time", "label": "发现侵权时间", "type": "date", "required": True}, + {"key": "infringement_scope", "label": "侵权范围/规模", "type": "textarea", "required": True}, + {"key": "has_notarization", "label": "是否有公证保全", "type": "boolean", "required": True}, + {"key": "loss_amount", "label": "损失金额(或侵权获利)", "type": "number", "required": False}, + ], + "claims": ["停止侵权", "赔偿损失", "消除影响", "销毁侵权商品及工具"], + }, + { + "title": "侵害著作权纠纷要素式起诉状", + "category": "知识产权", + "cause_of_action": "侵害著作权及邻接权纠纷", + "applicable": "他人未经许可使用作品(文字/图片/视频/软件等)", + "elements": [ + {"key": "work_name", "label": "作品名称", "type": "text", "required": True}, + {"key": "work_type", "label": "作品类型", "type": "select", "options": ["文字作品", "美术作品", "摄影作品", "视听作品", "音乐作品", "软件作品", "其他"], "required": True}, + {"key": "copyright_proof", "label": "权属证明", "type": "textarea", "required": True}, + {"key": "infringement_act", "label": "侵权行为", "type": "select", "options": ["复制", "发行", "信息网络传播", "改编", "抄袭", "其他"], "required": True}, + {"key": "infringement_detail", "label": "侵权行为描述", "type": "textarea", "required": True}, + {"key": "infringement_platform", "label": "侵权平台/渠道", "type": "text", "required": False}, + {"key": "has_notarization", "label": "是否有公证保全", "type": "boolean", "required": True}, + ], + "claims": ["停止侵权", "赔偿损失", "赔礼道歉", "消除影响"], + }, + + # ===== 行政类(精简) ===== + { + "title": "行政处罚纠纷要素式起诉状", + "category": "行政", + "cause_of_action": "行政处罚", + "applicable": "对行政机关作出的行政处罚决定不服", + "elements": [ + {"key": "penalty_decision_no", "label": "处罚决定书文号", "type": "text", "required": True}, + {"key": "penalty_authority", "label": "处罚机关", "type": "text", "required": True}, + {"key": "penalty_date", "label": "处罚日期", "type": "date", "required": True}, + {"key": "penalty_type", "label": "处罚类型", "type": "select", "options": ["罚款", "没收违法所得", "责令停产停业", "吊销许可证", "行政拘留", "其他"], "required": True}, + {"key": "penalty_amount", "label": "罚款金额", "type": "number", "required": False}, + {"key": "penalty_reason", "label": "处罚事由", "type": "textarea", "required": True}, + {"key": "appeal_status", "label": "是否已申请行政复议", "type": "boolean", "required": True}, + {"key": "appeal_result", "label": "复议结果(如有)", "type": "textarea", "required": False}, + ], + "claims": ["撤销行政处罚决定", "变更处罚内容", "确认违法", "赔偿损失"], + }, + + # ===== 执行类(精简) ===== + { + "title": "强制执行申请书要素式模板", + "category": "执行", + "cause_of_action": "强制执行", + "applicable": "生效法律文书确定的义务对方不履行,申请法院强制执行", + "elements": [ + {"key": "effective_doc_no", "label": "生效法律文书文号", "type": "text", "required": True}, + {"key": "effective_doc_type", "label": "文书类型", "type": "select", "options": ["判决书", "裁定书", "调解书", "仲裁裁决", "公证债权文书"], "required": True}, + {"key": "effective_date", "label": "生效日期", "type": "date", "required": True}, + {"key": "obligation_content", "label": "义务内容", "type": "textarea", "required": True}, + {"key": "unperformed_amount", "label": "未履行金额", "type": "number", "required": True}, + {"key": "debtor_property", "label": "被执行人财产线索", "type": "textarea", "required": False}, + ], + "claims": ["强制执行", "查封/扣押/冻结财产", "划扣存款", "提取收入"], + }, +] + + +def seed_element_templates(): + """将要素表模板导入知识库。""" + store = KnowledgeStore() + count = 0 + for tmpl in ELEMENT_TEMPLATES: + content = json.dumps(tmpl, ensure_ascii=False, indent=2) + store.add( + title=tmpl["title"], + content=content, + source="最高法法〔2025〕82号", + doc_type="element_template", + keywords=tmpl["cause_of_action"], + ) + count += 1 + print(f"已导入 {count} 类要素表模板到知识库") + return count + + +if __name__ == "__main__": + seed_element_templates() diff --git a/seed_elements_2.py b/seed_elements_2.py new file mode 100644 index 0000000..8b71e24 --- /dev/null +++ b/seed_elements_2.py @@ -0,0 +1,648 @@ +"""最高法67类要素式起诉状模板 - 补充剩余50类。 + +与 seed_elements.py 合并共67类。 +数据来源:最高人民法院、司法部、中华全国律师协会联合印发 +《部分案件起诉状答辩状示范文本》(法〔2025〕82号) +""" +import json +import sys +import os +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +from bossai import KnowledgeStore + +# 已导入的17类案由(避免重复) +EXISTING_CAUSES = { + "离婚纠纷", "买卖合同纠纷", "民间借贷纠纷", "劳动争议纠纷", + "机动车交通事故责任纠纷", "房屋买卖合同纠纷", "房屋租赁合同纠纷", + "建设工程施工合同纠纷", "物业服务合同纠纷", + "金融借款合同纠纷", "信用卡纠纷", "融资租赁合同纠纷", "保证保险合同纠纷", + "侵害商标权纠纷", "侵害著作权及邻接权纠纷", + "行政处罚", "强制执行", +} + +# 剩余50类 +REMAINING_TEMPLATES = [ + # ===== 商事类补充(4类) ===== + {"title": "证券虚假陈述责任纠纷要素式起诉状", "category": "商事", "cause_of_action": "证券虚假陈述责任纠纷", + "applicable": "上市公司虚假陈述导致投资者损失", + "elements": [ + {"key": "stock_name", "label": "股票名称及代码", "type": "text", "required": True}, + {"key": "false_statement_date", "label": "虚假陈述实施日", "type": "date", "required": True}, + {"key": "exposure_date", "label": "揭露日", "type": "date", "required": True}, + {"key": "buy_date", "label": "买入日期", "type": "date", "required": True}, + {"key": "buy_price", "label": "买入价格", "type": "number", "required": True}, + {"key": "buy_quantity", "label": "买入数量", "type": "number", "required": True}, + {"key": "sell_date", "label": "卖出日期(如有)", "type": "date", "required": False}, + {"key": "sell_price", "label": "卖出价格(如有)", "type": "number", "required": False}, + {"key": "loss_amount", "label": "投资损失金额", "type": "number", "required": True}, + {"key": "has_admin_penalty", "label": "是否有行政处罚决定", "type": "boolean", "required": True}, + ], + "claims": ["赔偿投资损失", "支付利息"]}, + + {"title": "财产损失保险合同纠纷要素式起诉状", "category": "商事", "cause_of_action": "财产损失保险合同纠纷", + "applicable": "财产保险理赔争议", + "elements": [ + {"key": "policy_no", "label": "保单号", "type": "text", "required": True}, + {"key": "insured_object", "label": "保险标的", "type": "text", "required": True}, + {"key": "coverage_amount", "label": "保险金额", "type": "number", "required": True}, + {"key": "incident_date", "label": "事故发生日期", "type": "date", "required": True}, + {"key": "incident_desc", "label": "事故经过描述", "type": "textarea", "required": True}, + {"key": "loss_amount", "label": "损失金额", "type": "number", "required": True}, + {"key": "claim_date", "label": "理赔申请日期", "type": "date", "required": True}, + {"key": "insurer_response", "label": "保险公司处理结果", "type": "textarea", "required": True}, + ], + "claims": ["支付保险赔偿金", "支付逾期理赔利息", "赔偿损失"]}, + + {"title": "责任保险合同纠纷要素式起诉状", "category": "商事", "cause_of_action": "责任保险合同纠纷", + "applicable": "第三者责任险理赔争议", + "elements": [ + {"key": "policy_no", "label": "保单号", "type": "text", "required": True}, + {"key": "insurance_type", "label": "险种", "type": "select", "options": ["交强险", "商业三者险", "产品责任险", "雇主责任险", "其他"], "required": True}, + {"key": "third_party_claim", "label": "第三者索赔金额", "type": "number", "required": True}, + {"key": "incident_date", "label": "事故日期", "type": "date", "required": True}, + {"key": "incident_desc", "label": "事故描述", "type": "textarea", "required": True}, + {"key": "insurer_response", "label": "保险公司处理结果", "type": "textarea", "required": True}, + ], + "claims": ["支付保险赔偿金", "承担诉讼费用"]}, + + {"title": "人身保险合同纠纷要素式起诉状", "category": "商事", "cause_of_action": "人身保险合同纠纷", + "applicable": "人身保险(寿险/意外险/健康险)理赔争议", + "elements": [ + {"key": "policy_no", "label": "保单号", "type": "text", "required": True}, + {"key": "insurance_type", "label": "险种", "type": "select", "options": ["寿险", "意外伤害险", "健康险", "重疾险", "医疗险"], "required": True}, + {"key": "insured_person", "label": "被保险人", "type": "text", "required": True}, + {"key": "incident_date", "label": "保险事故日期", "type": "date", "required": True}, + {"key": "incident_type", "label": "事故类型", "type": "select", "options": ["身故", "伤残", "疾病", "医疗费用"], "required": True}, + {"key": "claim_amount", "label": "理赔金额", "type": "number", "required": True}, + {"key": "insurer_response", "label": "保险公司处理结果", "type": "textarea", "required": True}, + {"key": "has_dispute_clause", "label": "争议条款", "type": "textarea", "required": False}, + ], + "claims": ["支付保险金", "支付逾期利息", "恢复保险合同效力"]}, + + # ===== 知识产权类补充(7类) ===== + {"title": "侵害发明专利权纠纷要素式起诉状", "category": "知识产权", "cause_of_action": "侵害发明专利权纠纷", + "applicable": "他人未经许可使用发明专利", + "elements": [ + {"key": "patent_name", "label": "专利名称", "type": "text", "required": True}, + {"key": "patent_no", "label": "专利号", "type": "text", "required": True}, + {"key": "patent_type", "label": "专利类型", "type": "select", "options": ["产品专利", "方法专利", "产品+方法专利"], "required": True}, + {"key": "infringement_act", "label": "侵权行为", "type": "select", "options": ["制造", "使用", "许诺销售", "销售", "进口", "其他"], "required": True}, + {"key": "infringement_detail", "label": "侵权行为描述", "type": "textarea", "required": True}, + {"key": "has_notarization", "label": "是否有公证保全", "type": "boolean", "required": True}, + {"key": "loss_amount", "label": "损失金额", "type": "number", "required": False}, + ], + "claims": ["停止侵权", "赔偿损失", "消除影响"]}, + + {"title": "侵害外观设计专利权纠纷要素式起诉状", "category": "知识产权", "cause_of_action": "侵害外观设计专利权纠纷", + "applicable": "他人未经许可使用外观设计专利", + "elements": [ + {"key": "patent_name", "label": "专利名称", "type": "text", "required": True}, + {"key": "patent_no", "label": "专利号", "type": "text", "required": True}, + {"key": "product_category", "label": "产品类别", "type": "text", "required": True}, + {"key": "infringement_act", "label": "侵权行为", "type": "select", "options": ["制造", "销售", "进口"], "required": True}, + {"key": "infringement_detail", "label": "侵权行为描述", "type": "textarea", "required": True}, + {"key": "has_notarization", "label": "是否有公证保全", "type": "boolean", "required": True}, + ], + "claims": ["停止侵权", "赔偿损失", "消除影响"]}, + + {"title": "侵害植物新品种权纠纷要素式起诉状", "category": "知识产权", "cause_of_action": "侵害植物新品种权纠纷", + "applicable": "他人未经许可使用植物新品种", + "elements": [ + {"key": "variety_name", "label": "品种名称", "type": "text", "required": True}, + {"key": "variety_right_no", "label": "品种权号", "type": "text", "required": True}, + {"key": "infringement_act", "label": "侵权行为", "type": "select", "options": ["生产", "繁殖", "销售", "推广"], "required": True}, + {"key": "infringement_detail", "label": "侵权行为描述", "type": "textarea", "required": True}, + ], + "claims": ["停止侵权", "赔偿损失"]}, + + {"title": "侵害商业秘密纠纷要素式起诉状", "category": "知识产权", "cause_of_action": "侵害商业秘密纠纷", + "applicable": "他人非法获取、使用或披露商业秘密", + "elements": [ + {"key": "secret_name", "label": "商业秘密名称", "type": "text", "required": True}, + {"key": "secret_type", "label": "秘密类型", "type": "select", "options": ["技术信息", "经营信息", "客户名单", "其他"], "required": True}, + {"key": "confidentiality_measure", "label": "保密措施", "type": "textarea", "required": True}, + {"key": "infringement_act", "label": "侵权行为", "type": "select", "options": ["非法获取", "非法披露", "非法使用", "违反保密协议"], "required": True}, + {"key": "infringement_detail", "label": "侵权行为描述", "type": "textarea", "required": True}, + {"key": "has_confidentiality_agreement", "label": "是否有保密协议", "type": "boolean", "required": True}, + ], + "claims": ["停止侵权", "赔偿损失", "返还商业秘密载体"]}, + + {"title": "技术合同纠纷要素式起诉状", "category": "知识产权", "cause_of_action": "技术合同纠纷", + "applicable": "技术开发、转让、咨询、服务合同争议", + "elements": [ + {"key": "contract_type", "label": "合同类型", "type": "select", "options": ["技术开发合同", "技术转让合同", "技术咨询合同", "技术服务合同"], "required": True}, + {"key": "contract_date", "label": "合同签订日期", "type": "date", "required": True}, + {"key": "tech_subject", "label": "技术标的", "type": "text", "required": True}, + {"key": "contract_amount", "label": "合同金额", "type": "number", "required": True}, + {"key": "paid_amount", "label": "已付金额", "type": "number", "required": True}, + {"key": "dispute_type", "label": "争议类型", "type": "select", "options": ["拖欠款项", "技术交付争议", "质量争议", "合同解除"], "required": True}, + {"key": "breach_detail", "label": "违约情况", "type": "textarea", "required": True}, + ], + "claims": ["支付合同款项", "支付违约金", "解除合同", "赔偿损失"]}, + + {"title": "不正当竞争纠纷要素式起诉状", "category": "知识产权", "cause_of_action": "不正当竞争纠纷", + "applicable": "混淆、虚假宣传、商业诋毁等不正当竞争行为", + "elements": [ + {"key": "unfair_act_type", "label": "不正当竞争行为类型", "type": "select", "options": ["混淆行为", "虚假宣传", "商业诋毁", "商业贿赂", "侵犯商业秘密", "不正当有奖销售"], "required": True}, + {"key": "act_detail", "label": "行为描述", "type": "textarea", "required": True}, + {"key": "act_time", "label": "行为发生时间", "type": "date", "required": True}, + {"key": "act_scope", "label": "影响范围", "type": "textarea", "required": True}, + {"key": "loss_amount", "label": "损失金额", "type": "number", "required": False}, + ], + "claims": ["停止不正当竞争行为", "赔偿损失", "消除影响"]}, + + {"title": "垄断纠纷要素式起诉状", "category": "知识产权", "cause_of_action": "垄断纠纷", + "applicable": "垄断协议、滥用市场支配地位等", + "elements": [ + {"key": "monopoly_type", "label": "垄断行为类型", "type": "select", "options": ["垄断协议", "滥用市场支配地位", "经营者集中"], "required": True}, + {"key": "relevant_market", "label": "相关市场界定", "type": "textarea", "required": True}, + {"key": "act_detail", "label": "行为描述", "type": "textarea", "required": True}, + {"key": "loss_amount", "label": "损失金额", "type": "number", "required": False}, + ], + "claims": ["停止垄断行为", "赔偿损失"]}, + + # ===== 知识产权行政类(6类) ===== + {"title": "商标申请驳回复审纠纷要素式起诉状", "category": "知识产权行政", "cause_of_action": "商标申请驳回复审纠纷", + "applicable": "商标申请被驳回,申请复审后仍不服", + "elements": [ + {"key": "trademark_name", "label": "申请商标名称", "type": "text", "required": True}, + {"key": "application_no", "label": "申请号", "type": "text", "required": True}, + {"key": "rejection_reason", "label": "驳回理由", "type": "textarea", "required": True}, + {"key": "review_no", "label": "复审决定书文号", "type": "text", "required": True}, + {"key": "review_result", "label": "复审结果", "type": "textarea", "required": True}, + ], + "claims": ["撤销复审决定", "准予商标注册"]}, + + {"title": "商标撤销复审行政纠纷要素式起诉状", "category": "知识产权行政", "cause_of_action": "商标撤销复审行政纠纷", + "applicable": "商标被撤销后申请复审不服", + "elements": [ + {"key": "trademark_name", "label": "商标名称", "type": "text", "required": True}, + {"key": "trademark_no", "label": "商标注册号", "type": "text", "required": True}, + {"key": "revocation_reason", "label": "撤销理由", "type": "textarea", "required": True}, + {"key": "review_no", "label": "复审决定书文号", "type": "text", "required": True}, + ], + "claims": ["撤销复审决定", "维持商标注册"]}, + + {"title": "商标无效行政纠纷要素式起诉状", "category": "知识产权行政", "cause_of_action": "商标无效行政纠纷", + "applicable": "商标被宣告无效后不服", + "elements": [ + {"key": "trademark_name", "label": "商标名称", "type": "text", "required": True}, + {"key": "trademark_no", "label": "商标注册号", "type": "text", "required": True}, + {"key": "invalidation_reason", "label": "无效理由", "type": "textarea", "required": True}, + {"key": "ruling_no", "label": "裁定书文号", "type": "text", "required": True}, + ], + "claims": ["撤销无效宣告", "维持商标注册"]}, + + {"title": "专利申请驳回复审行政纠纷要素式起诉状", "category": "知识产权行政", "cause_of_action": "专利申请驳回复审行政纠纷", + "applicable": "专利申请被驳回,复审后仍不服", + "elements": [ + {"key": "patent_name", "label": "申请专利名称", "type": "text", "required": True}, + {"key": "application_no", "label": "申请号", "type": "text", "required": True}, + {"key": "rejection_reason", "label": "驳回理由", "type": "textarea", "required": True}, + {"key": "review_no", "label": "复审决定书文号", "type": "text", "required": True}, + ], + "claims": ["撤销复审决定", "准予专利授权"]}, + + {"title": "专利无效行政纠纷要素式起诉状", "category": "知识产权行政", "cause_of_action": "专利无效行政纠纷", + "applicable": "专利被宣告无效后不服", + "elements": [ + {"key": "patent_name", "label": "专利名称", "type": "text", "required": True}, + {"key": "patent_no", "label": "专利号", "type": "text", "required": True}, + {"key": "invalidation_reason", "label": "无效理由", "type": "textarea", "required": True}, + {"key": "ruling_no", "label": "无效宣告请求审查决定书文号", "type": "text", "required": True}, + ], + "claims": ["撤销无效宣告决定", "维持专利权有效"]}, + + {"title": "垄断纠纷(行政)要素式起诉状", "category": "知识产权行政", "cause_of_action": "垄断纠纷(行政)", + "applicable": "对反垄断执法机构的行政处罚决定不服", + "elements": [ + {"key": "penalty_authority", "label": "执法机构", "type": "text", "required": True}, + {"key": "penalty_no", "label": "处罚决定书文号", "type": "text", "required": True}, + {"key": "monopoly_type", "label": "垄断行为类型", "type": "select", "options": ["垄断协议", "滥用市场支配地位", "经营者集中"], "required": True}, + {"key": "penalty_content", "label": "处罚内容", "type": "textarea", "required": True}, + ], + "claims": ["撤销行政处罚决定", "变更处罚内容"]}, + + # ===== 行政类补充(11类) ===== + {"title": "行政强制执行纠纷要素式起诉状", "category": "行政", "cause_of_action": "行政强制执行", + "applicable": "对行政机关的行政强制执行行为不服", + "elements": [ + {"key": "execution_authority", "label": "执行机关", "type": "text", "required": True}, + {"key": "execution_no", "label": "执行决定书文号", "type": "text", "required": True}, + {"key": "execution_date", "label": "执行日期", "type": "date", "required": True}, + {"key": "execution_measure", "label": "强制执行措施", "type": "select", "options": ["查封", "扣押", "冻结", "划拨", "拍卖", "拆除", "其他"], "required": True}, + {"key": "execution_target", "label": "执行标的", "type": "text", "required": True}, + {"key": "dispute_reason", "label": "争议理由", "type": "textarea", "required": True}, + ], + "claims": ["撤销强制执行决定", "返还财产", "赔偿损失"]}, + + {"title": "行政许可纠纷要素式起诉状", "category": "行政", "cause_of_action": "行政许可", + "applicable": "对行政机关的行政许可决定(不予许可/撤销许可)不服", + "elements": [ + {"key": "permit_type", "label": "许可类型", "type": "text", "required": True}, + {"key": "application_date", "label": "申请日期", "type": "date", "required": True}, + {"key": "authority", "label": "许可机关", "type": "text", "required": True}, + {"key": "decision_date", "label": "决定日期", "type": "date", "required": True}, + {"key": "decision_content", "label": "决定内容", "type": "select", "options": ["不予许可", "撤销许可", "变更许可", "吊销许可"], "required": True}, + {"key": "decision_reason", "label": "决定理由", "type": "textarea", "required": True}, + ], + "claims": ["撤销行政决定", "判令作出许可", "赔偿损失"]}, + + {"title": "国有土地上房屋征收决定纠纷要素式起诉状", "category": "行政", "cause_of_action": "国有土地上房屋征收决定", + "applicable": "对政府作出的房屋征收决定不服", + "elements": [ + {"key": "property_address", "label": "被征收房屋地址", "type": "text", "required": True}, + {"key": "property_area", "label": "房屋面积", "type": "number", "required": True}, + {"key": "decision_no", "label": "征收决定书文号", "type": "text", "required": True}, + {"key": "decision_date", "label": "征收决定日期", "type": "date", "required": True}, + {"key": "authority", "label": "征收主体", "type": "text", "required": True}, + {"key": "compensation_plan", "label": "补偿方案", "type": "textarea", "required": True}, + {"key": "dispute_reason", "label": "争议理由", "type": "textarea", "required": True}, + ], + "claims": ["撤销征收决定", "重新作出补偿决定", "提高补偿标准"]}, + + {"title": "工伤保险资格或待遇认定纠纷要素式起诉状", "category": "行政", "cause_of_action": "工伤保险资格或者待遇认定(行政)", + "applicable": "对工伤保险资格认定或待遇标准不服", + "elements": [ + {"key": "injury_date", "label": "受伤日期", "type": "date", "required": True}, + {"key": "injury_desc", "label": "受伤经过", "type": "textarea", "required": True}, + {"key": "recognition_no", "label": "认定决定书文号", "type": "text", "required": True}, + {"key": "recognition_result", "label": "认定结果", "type": "select", "options": ["认定为工伤", "不予认定为工伤", "视同工伤", "不视同工伤"], "required": True}, + {"key": "disability_level", "label": "伤残等级(如有)", "type": "text", "required": False}, + {"key": "treatment_amount", "label": "待遇金额争议", "type": "number", "required": False}, + ], + "claims": ["撤销认定决定", "重新作出认定", "支付工伤保险待遇"]}, + + {"title": "政府信息公开纠纷要素式起诉状", "category": "行政", "cause_of_action": "政府信息公开", + "applicable": "申请政府信息公开被拒绝或逾期未答复", + "elements": [ + {"key": "application_date", "label": "申请日期", "type": "date", "required": True}, + {"key": "info_content", "label": "申请公开的信息内容", "type": "textarea", "required": True}, + {"key": "authority", "label": "被申请机关", "type": "text", "required": True}, + {"key": "response", "label": "答复情况", "type": "select", "options": ["逾期未答复", "拒绝公开", "部分公开", "信息不存在"], "required": True}, + {"key": "refusal_reason", "label": "拒绝理由(如有)", "type": "textarea", "required": False}, + ], + "claims": ["判令公开政府信息", "重新作出答复"]}, + + {"title": "行政复议纠纷要素式起诉状", "category": "行政", "cause_of_action": "行政复议", + "applicable": "对行政复议决定不服", + "elements": [ + {"key": "original_decision", "label": "原行政行为", "type": "textarea", "required": True}, + {"key": "original_authority", "label": "原行为机关", "type": "text", "required": True}, + {"key": "review_authority", "label": "复议机关", "type": "text", "required": True}, + {"key": "review_no", "label": "复议决定书文号", "type": "text", "required": True}, + {"key": "review_date", "label": "复议决定日期", "type": "date", "required": True}, + {"key": "review_result", "label": "复议结果", "type": "select", "options": ["维持", "撤销", "变更", "确认违法", "驳回"], "required": True}, + ], + "claims": ["撤销复议决定", "撤销原行政行为", "重新作出行政行为"]}, + + {"title": "行政协议纠纷要素式起诉状", "category": "行政", "cause_of_action": "行政协议", + "applicable": "行政机关不履行行政协议或单方变更解除", + "elements": [ + {"key": "agreement_name", "label": "协议名称", "type": "text", "required": True}, + {"key": "agreement_date", "label": "签订日期", "type": "date", "required": True}, + {"key": "agreement_parties", "label": "协议双方", "type": "text", "required": True}, + {"key": "agreement_content", "label": "协议主要内容", "type": "textarea", "required": True}, + {"key": "dispute_type", "label": "争议类型", "type": "select", "options": ["不履行", "单方变更", "单方解除", "补偿争议"], "required": True}, + {"key": "loss_amount", "label": "损失金额", "type": "number", "required": False}, + ], + "claims": ["继续履行协议", "赔偿损失", "补偿"]}, + + {"title": "行政补偿纠纷要素式起诉状", "category": "行政", "cause_of_action": "行政补偿", + "applicable": "对行政机关的行政补偿决定不服", + "elements": [ + {"key": "compensation_reason", "label": "补偿事由", "type": "textarea", "required": True}, + {"key": "authority", "label": "补偿机关", "type": "text", "required": True}, + {"key": "compensation_offer", "label": "补偿方案", "type": "textarea", "required": True}, + {"key": "claim_amount", "label": "诉求补偿金额", "type": "number", "required": True}, + {"key": "dispute_reason", "label": "争议理由", "type": "textarea", "required": True}, + ], + "claims": ["提高补偿标准", "支付补偿款"]}, + + {"title": "行政赔偿纠纷要素式起诉状", "category": "行政", "cause_of_action": "行政赔偿", + "applicable": "行政机关违法行为造成损失,要求赔偿", + "elements": [ + {"key": "illegal_act", "label": "违法行为描述", "type": "textarea", "required": True}, + {"key": "authority", "label": "赔偿义务机关", "type": "text", "required": True}, + {"key": "act_date", "label": "行为发生日期", "type": "date", "required": True}, + {"key": "loss_type", "label": "损失类型", "type": "select", "options": ["财产损失", "人身损害", "精神损害"], "required": True}, + {"key": "loss_amount", "label": "损失金额", "type": "number", "required": True}, + {"key": "has_confirmed_illegal", "label": "是否已确认违法", "type": "boolean", "required": True}, + ], + "claims": ["支付赔偿金", "返还财产", "恢复原状"]}, + + {"title": "不履行法定职责纠纷要素式起诉状", "category": "行政", "cause_of_action": "不履行法定职责", + "applicable": "行政机关不履行或拖延履行法定职责", + "elements": [ + {"key": "duty_type", "label": "法定职责类型", "type": "text", "required": True}, + {"key": "application_date", "label": "申请履行日期", "type": "date", "required": True}, + {"key": "authority", "label": "被诉行政机关", "type": "text", "required": True}, + {"key": "response", "label": "答复情况", "type": "select", "options": ["未答复", "拒绝履行", "拖延履行"], "required": True}, + {"key": "loss_amount", "label": "损失金额", "type": "number", "required": False}, + ], + "claims": ["判令履行法定职责", "赔偿损失"]}, + + # ===== 刑事自诉类(4类) ===== + {"title": "侮辱案刑事自诉要素式起诉状", "category": "刑事自诉", "cause_of_action": "侮辱案刑事自诉(附带民事)", + "applicable": "他人以暴力或其他方法公然侮辱,情节严重", + "elements": [ + {"key": "insult_act", "label": "侮辱行为描述", "type": "textarea", "required": True}, + {"key": "act_date", "label": "行为发生日期", "type": "date", "required": True}, + {"key": "act_location", "label": "行为发生地点", "type": "text", "required": True}, + {"key": "publicity", "label": "是否公然进行", "type": "boolean", "required": True}, + {"key": "severity", "label": "情节严重程度", "type": "textarea", "required": True}, + {"key": "evidence", "label": "证据清单", "type": "textarea", "required": True}, + {"key": "civil_claim", "label": "附带民事诉求", "type": "textarea", "required": False}, + ], + "claims": ["追究刑事责任", "赔礼道歉", "赔偿精神损害"]}, + + {"title": "诽谤案刑事自诉要素式起诉状", "category": "刑事自诉", "cause_of_action": "诽谤案刑事自诉(附带民事)", + "applicable": "他人捏造事实诽谤,情节严重", + "elements": [ + {"key": "fabrication_detail", "label": "捏造事实描述", "type": "textarea", "required": True}, + {"key": "spread_method", "label": "传播方式", "type": "select", "options": ["口头", "文字", "网络", "其他"], "required": True}, + {"key": "act_date", "label": "行为发生日期", "type": "date", "required": True}, + {"key": "severity", "label": "情节严重程度", "type": "textarea", "required": True}, + {"key": "evidence", "label": "证据清单", "type": "textarea", "required": True}, + ], + "claims": ["追究刑事责任", "赔礼道歉", "赔偿精神损害"]}, + + {"title": "重婚案刑事自诉要素式起诉状", "category": "刑事自诉", "cause_of_action": "重婚案刑事自诉(附带民事)", + "applicable": "配偶与他人重婚", + "elements": [ + {"key": "legal_marriage", "label": "合法婚姻情况", "type": "textarea", "required": True}, + {"key": "bigamy_detail", "label": "重婚行为描述", "type": "textarea", "required": True}, + {"key": "bigamy_start", "label": "重婚开始时间", "type": "date", "required": True}, + {"key": "cohabitation_proof", "label": "以夫妻名义共同生活证据", "type": "textarea", "required": True}, + ], + "claims": ["追究刑事责任"]}, + + {"title": "拒不执行判决裁定案刑事自诉要素式起诉状", "category": "刑事自诉", "cause_of_action": "拒不执行判决裁定案刑事自诉(附带民事)", + "applicable": "被执行人拒不执行生效判决裁定,情节严重", + "elements": [ + {"key": "effective_doc", "label": "生效判决/裁定文号", "type": "text", "required": True}, + {"key": "effective_date", "label": "生效日期", "type": "date", "required": True}, + {"key": "obligation", "label": "义务内容", "type": "textarea", "required": True}, + {"key": "refusal_act", "label": "拒不执行行为描述", "type": "textarea", "required": True}, + {"key": "has_ability", "label": "是否有履行能力", "type": "boolean", "required": True}, + {"key": "property_clue", "label": "财产线索", "type": "textarea", "required": False}, + ], + "claims": ["追究刑事责任"]}, + + # ===== 海事类(4类) ===== + {"title": "船舶碰撞损害责任纠纷要素式起诉状", "category": "海事", "cause_of_action": "船舶碰撞损害责任纠纷", + "applicable": "船舶之间碰撞造成损害", + "elements": [ + {"key": "collision_date", "label": "碰撞日期", "type": "date", "required": True}, + {"key": "collision_location", "label": "碰撞地点(水域)", "type": "text", "required": True}, + {"key": "own_vessel", "label": "己方船舶信息", "type": "text", "required": True}, + {"key": "other_vessel", "label": "对方船舶信息", "type": "text", "required": True}, + {"key": "responsibility", "label": "责任比例", "type": "text", "required": True}, + {"key": "damage_detail", "label": "损害情况", "type": "textarea", "required": True}, + {"key": "loss_amount", "label": "损失金额", "type": "number", "required": True}, + ], + "claims": ["赔偿损失", "支付利息"]}, + + {"title": "海上人身损害责任纠纷要素式起诉状", "category": "海事", "cause_of_action": "海上通海水域人身损害责任纠纷", + "applicable": "海上或通海水域事故造成人身伤亡", + "elements": [ + {"key": "incident_date", "label": "事故日期", "type": "date", "required": True}, + {"key": "incident_location", "label": "事故地点", "type": "text", "required": True}, + {"key": "victim_info", "label": "受害人信息", "type": "text", "required": True}, + {"key": "injury_detail", "label": "伤亡情况", "type": "textarea", "required": True}, + {"key": "medical_expense", "label": "医疗费", "type": "number", "required": False}, + {"key": "death_compensation", "label": "死亡赔偿金(如适用)", "type": "number", "required": False}, + ], + "claims": ["赔偿医疗费", "赔偿死亡赔偿金", "赔偿精神损害抚慰金"]}, + + {"title": "海上货运代理合同纠纷要素式起诉状", "category": "海事", "cause_of_action": "海上通海水域货运代理合同纠纷", + "applicable": "海上/水上货物运输代理合同争议", + "elements": [ + {"key": "contract_date", "label": "合同签订日期", "type": "date", "required": True}, + {"key": "goods_info", "label": "货物信息", "type": "textarea", "required": True}, + {"key": "route", "label": "运输路线", "type": "text", "required": True}, + {"key": "freight", "label": "运费金额", "type": "number", "required": True}, + {"key": "dispute_type", "label": "争议类型", "type": "select", "options": ["拖欠运费", "货物损坏", "货物灭失", "迟延交付"], "required": True}, + {"key": "loss_amount", "label": "损失金额", "type": "number", "required": True}, + ], + "claims": ["支付运费", "赔偿货物损失", "支付违约金"]}, + + {"title": "船员劳务合同纠纷要素式起诉状", "category": "海事", "cause_of_action": "船员劳务合同纠纷", + "applicable": "船员与船东之间的劳务争议", + "elements": [ + {"key": "service_start", "label": "上船日期", "type": "date", "required": True}, + {"key": "service_end", "label": "下船日期", "type": "date", "required": False}, + {"key": "vessel_name", "label": "船舶名称", "type": "text", "required": True}, + {"key": "position", "label": "船员职务", "type": "text", "required": True}, + {"key": "salary_standard", "label": "工资标准", "type": "number", "required": True}, + {"key": "unpaid_salary", "label": "拖欠工资", "type": "number", "required": True}, + {"key": "has_injury", "label": "是否有工伤", "type": "boolean", "required": False}, + ], + "claims": ["支付拖欠工资", "支付经济补偿金", "工伤赔偿"]}, + + # ===== 环境资源类(3类) ===== + {"title": "环境污染民事公益诉讼要素式起诉状", "category": "环境资源", "cause_of_action": "环境污染民事公益诉讼", + "applicable": "污染环境损害社会公共利益", + "elements": [ + {"key": "pollution_type", "label": "污染类型", "type": "select", "options": ["大气污染", "水污染", "土壤污染", "噪声污染", "固废污染"], "required": True}, + {"key": "polluter", "label": "污染者信息", "type": "text", "required": True}, + {"key": "pollution_location", "label": "污染地点", "type": "text", "required": True}, + {"key": "pollution_duration", "label": "污染持续时间", "type": "text", "required": True}, + {"key": "damage_scope", "label": "损害范围", "type": "textarea", "required": True}, + {"key": "remediation_cost", "label": "生态修复费用", "type": "number", "required": False}, + ], + "claims": ["停止污染", "修复生态环境", "赔偿生态损害", "赔礼道歉"]}, + + {"title": "生态破坏民事公益诉讼要素式起诉状", "category": "环境资源", "cause_of_action": "生态破坏民事公益诉讼", + "applicable": "破坏生态损害社会公共利益", + "elements": [ + {"key": "destruction_type", "label": "破坏类型", "type": "select", "options": ["滥砍滥伐", "非法捕捞", "非法狩猎", "破坏湿地", "破坏草原"], "required": True}, + {"key": "destroyer", "label": "破坏者信息", "type": "text", "required": True}, + {"key": "destruction_location", "label": "破坏地点", "type": "text", "required": True}, + {"key": "damage_scope", "label": "损害范围", "type": "textarea", "required": True}, + {"key": "remediation_cost", "label": "生态修复费用", "type": "number", "required": False}, + ], + "claims": ["停止破坏", "修复生态环境", "赔偿生态损害"]}, + + {"title": "生态环境损害赔偿诉讼要素式起诉状", "category": "环境资源", "cause_of_action": "生态环境损害赔偿诉讼", + "applicable": "政府作为赔偿权利人提起生态环境损害赔偿", + "elements": [ + {"key": "damage_type", "label": "损害类型", "type": "text", "required": True}, + {"key": "damager", "label": "损害者信息", "type": "text", "required": True}, + {"key": "damage_location", "label": "损害地点", "type": "text", "required": True}, + {"key": "damage_scope", "label": "损害范围及程度", "type": "textarea", "required": True}, + {"key": "remediation_cost", "label": "修复费用", "type": "number", "required": True}, + {"key": "loss_amount", "label": "生态环境损害金额", "type": "number", "required": True}, + ], + "claims": ["承担修复费用", "赔偿生态环境损害", "停止损害行为"]}, + + # ===== 国家赔偿类(4类) ===== + {"title": "违法刑事拘留赔偿要素式起诉状", "category": "国家赔偿", "cause_of_action": "违法刑事拘留赔偿", + "applicable": "被违法刑事拘留后申请国家赔偿", + "elements": [ + {"key": "detention_no", "label": "拘留决定书文号", "type": "text", "required": True}, + {"key": "detention_start", "label": "拘留起始日期", "type": "date", "required": True}, + {"key": "detention_end", "label": "拘留结束日期", "type": "date", "required": True}, + {"key": "detention_days", "label": "拘留天数", "type": "number", "required": True}, + {"key": "authority", "label": "作出拘留决定的机关", "type": "text", "required": True}, + {"key": "release_reason", "label": "释放原因", "type": "textarea", "required": True}, + {"key": "claim_amount", "label": "赔偿请求金额", "type": "number", "required": True}, + ], + "claims": ["支付人身自由损害赔偿金", "赔礼道歉", "恢复名誉"]}, + + {"title": "刑事改判无罪赔偿要素式起诉状", "category": "国家赔偿", "cause_of_action": "刑事改判无罪赔偿", + "applicable": "原判有罪后改判无罪,申请国家赔偿", + "elements": [ + {"key": "original_judgment", "label": "原判决文号", "type": "text", "required": True}, + {"key": "revised_judgment", "label": "改判判决文号", "type": "text", "required": True}, + {"key": "detention_period", "label": "被羁押期间", "type": "text", "required": True}, + {"key": "detention_days", "label": "羁押天数", "type": "number", "required": True}, + {"key": "claim_amount", "label": "赔偿请求金额", "type": "number", "required": True}, + ], + "claims": ["支付人身自由损害赔偿金", "精神损害抚慰金", "赔礼道歉"]}, + + {"title": "怠于履行监管职责致伤致死赔偿要素式起诉状", "category": "国家赔偿", "cause_of_action": "怠于履行监管职责致伤致死赔偿", + "applicable": "监管机关怠于履行职责导致被监管人伤亡", + "elements": [ + {"key": "supervision_authority", "label": "监管机关", "type": "text", "required": True}, + {"key": "victim_info", "label": "被监管人信息", "type": "text", "required": True}, + {"key": "incident_date", "label": "事件发生日期", "type": "date", "required": True}, + {"key": "incident_detail", "label": "事件经过", "type": "textarea", "required": True}, + {"key": "duty_breach", "label": "怠于履职情况", "type": "textarea", "required": True}, + {"key": "damage_result", "label": "损害结果", "type": "select", "options": ["受伤", "死亡"], "required": True}, + {"key": "claim_amount", "label": "赔偿请求金额", "type": "number", "required": True}, + ], + "claims": ["支付赔偿金", "追究相关责任"]}, + + {"title": "错误执行赔偿要素式起诉状", "category": "国家赔偿", "cause_of_action": "错误执行赔偿", + "applicable": "法院错误执行导致损失,申请国家赔偿", + "elements": [ + {"key": "execution_case", "label": "执行案件文号", "type": "text", "required": True}, + {"key": "execution_authority", "label": "执行法院", "type": "text", "required": True}, + {"key": "wrong_act", "label": "错误执行行为", "type": "textarea", "required": True}, + {"key": "execution_date", "label": "错误执行日期", "type": "date", "required": True}, + {"key": "loss_detail", "label": "损失情况", "type": "textarea", "required": True}, + {"key": "loss_amount", "label": "损失金额", "type": "number", "required": True}, + ], + "claims": ["支付赔偿金", "返还财产"]}, + + # ===== 执行类补充(8类) ===== + {"title": "暂时解除限制措施申请书要素式模板", "category": "执行", "cause_of_action": "暂时解除乘坐飞机高铁限制措施", + "applicable": "被限制高消费后申请暂时解除乘坐飞机高铁限制", + "elements": [ + {"key": "restriction_no", "label": "限制消费令文号", "type": "text", "required": True}, + {"key": "restriction_date", "label": "限制日期", "type": "date", "required": True}, + {"key": "reason", "label": "申请解除理由", "type": "select", "options": ["紧急就医", "直系亲属丧葬", "公务出行", "其他紧急情况"], "required": True}, + {"key": "travel_plan", "label": "出行计划(日期/航班车次)", "type": "textarea", "required": True}, + ], + "claims": ["暂时解除乘坐飞机限制", "暂时解除乘坐高铁限制"]}, + + {"title": "参与分配申请书要素式模板", "category": "执行", "cause_of_action": "参与分配", + "applicable": "被执行人财产不足清偿全部债务,债权人申请参与分配", + "elements": [ + {"key": "execution_case", "label": "执行案件文号", "type": "text", "required": True}, + {"key": "debtor", "label": "被执行人", "type": "text", "required": True}, + {"key": "creditor_claim", "label": "申请人债权金额", "type": "number", "required": True}, + {"key": "total_debt", "label": "被执行人总债务", "type": "number", "required": False}, + {"key": "available_property", "label": "可供分配财产", "type": "textarea", "required": True}, + ], + "claims": ["参与财产分配"]}, + + {"title": "执行担保申请书要素式模板", "category": "执行", "cause_of_action": "执行担保", + "applicable": "执行中提供担保暂缓执行", + "elements": [ + {"key": "execution_case", "label": "执行案件文号", "type": "text", "required": True}, + {"key": "guarantor", "label": "担保人信息", "type": "text", "required": True}, + {"key": "guarantee_type", "label": "担保方式", "type": "select", "options": ["保证", "抵押", "质押"], "required": True}, + {"key": "guarantee_amount", "label": "担保金额", "type": "number", "required": True}, + {"key": "guarantee_property", "label": "担保财产", "type": "textarea", "required": True}, + ], + "claims": ["暂缓执行"]}, + + {"title": "确认优先购买权申请书要素式模板", "category": "执行", "cause_of_action": "确认优先购买权", + "applicable": "执行拍卖中主张优先购买权", + "elements": [ + {"key": "execution_case", "label": "执行案件文号", "type": "text", "required": True}, + {"key": "auction_target", "label": "拍卖标的", "type": "text", "required": True}, + {"key": "priority_basis", "label": "优先购买权依据", "type": "select", "options": ["共有关系", "租赁关系", "公司法规定", "其他"], "required": True}, + {"key": "priority_proof", "label": "优先购买权证据", "type": "textarea", "required": True}, + ], + "claims": ["确认优先购买权"]}, + + {"title": "执行异议申请书要素式模板", "category": "执行", "cause_of_action": "执行异议", + "applicable": "对执行行为不服提出异议", + "elements": [ + {"key": "execution_case", "label": "执行案件文号", "type": "text", "required": True}, + {"key": "objection_type", "label": "异议类型", "type": "select", "options": ["执行行为异议", "案外人异议"], "required": True}, + {"key": "objection_target", "label": "异议标的", "type": "text", "required": True}, + {"key": "objection_reason", "label": "异议理由", "type": "textarea", "required": True}, + ], + "claims": ["撤销执行行为", "中止执行", "解除查封扣押"]}, + + {"title": "执行复议申请书要素式模板", "category": "执行", "cause_of_action": "执行复议", + "applicable": "对执行异议裁定不服申请复议", + "elements": [ + {"key": "ruling_no", "label": "异议裁定书文号", "type": "text", "required": True}, + {"key": "ruling_date", "label": "裁定日期", "type": "date", "required": True}, + {"key": "ruling_result", "label": "裁定结果", "type": "textarea", "required": True}, + {"key": "rejection_reason", "label": "复议理由", "type": "textarea", "required": True}, + ], + "claims": ["撤销异议裁定", "支持异议请求"]}, + + {"title": "执行监督申请书要素式模板", "category": "执行", "cause_of_action": "执行监督", + "applicable": "请求上级法院对执行行为进行监督", + "elements": [ + {"key": "execution_case", "label": "执行案件文号", "type": "text", "required": True}, + {"key": "execution_court", "label": "执行法院", "type": "text", "required": True}, + {"key": "supervision_reason", "label": "申请监督理由", "type": "textarea", "required": True}, + {"key": "illegal_act", "label": "违法/不当执行行为", "type": "textarea", "required": True}, + ], + "claims": ["监督执行", "纠正违法执行行为"]}, + + {"title": "不予执行仲裁裁决申请书要素式模板", "category": "执行", "cause_of_action": "不予执行仲裁裁决调解书或公证债权文书", + "applicable": "申请不予执行仲裁裁决/调解书/公证债权文书", + "elements": [ + {"key": "award_no", "label": "仲裁裁决/调解书/公证文书文号", "type": "text", "required": True}, + {"key": "award_date", "label": "文书作出日期", "type": "date", "required": True}, + {"key": "refusal_reason", "label": "申请不予执行理由", "type": "select", "options": ["没有仲裁协议", "裁决事项超范围", "程序违法", "证据伪造", "隐瞒证据", "仲裁员枉法"], "required": True}, + {"key": "reason_detail", "label": "理由详细说明", "type": "textarea", "required": True}, + ], + "claims": ["不予执行仲裁裁决", "不予执行公证债权文书"]}, + + # ===== 行政答辩状(1类) ===== + {"title": "行政答辩状要素式模板", "category": "行政", "cause_of_action": "行政答辩状", + "applicable": "行政机关作为被告提交答辩状", + "elements": [ + {"key": "case_no", "label": "案号", "type": "text", "required": True}, + {"key": "plaintiff", "label": "原告信息", "type": "text", "required": True}, + {"key": "original_act", "label": "被诉行政行为", "type": "textarea", "required": True}, + {"key": "defense_basis", "label": "答辩依据", "type": "textarea", "required": True}, + {"key": "evidence", "label": "证据清单", "type": "textarea", "required": True}, + ], + "claims": ["请求驳回原告诉讼请求"]}, +] + + +def seed_remaining_templates(): + """导入剩余50类要素表模板。""" + store = KnowledgeStore() + count = 0 + for tmpl in REMAINING_TEMPLATES: + cause = tmpl["cause_of_action"] + if cause in EXISTING_CAUSES: + continue + content = json.dumps(tmpl, ensure_ascii=False, indent=2) + store.add( + title=tmpl["title"], + content=content, + source="最高法法〔2025〕82号", + doc_type="element_template", + keywords=cause, + ) + count += 1 + print(f"已补充导入 {count} 类要素表模板") + return count + + +if __name__ == "__main__": + seed_remaining_templates() diff --git a/web/src/components/common/ChatPanel.tsx b/web/src/components/common/ChatPanel.tsx index 12f39c9..12f83e9 100644 --- a/web/src/components/common/ChatPanel.tsx +++ b/web/src/components/common/ChatPanel.tsx @@ -64,6 +64,97 @@ const PROFILE_VALUE_LABELS: Record = { // 通用 yes/no yes: '是', no: '否', + // 行业 + retail: '零售', + manufacturing: '制造业', + tech: '科技', + service: '服务业', + finance: '金融', + realestate: '房地产', + education: '教育', + healthcare: '医疗健康', + construction: '建筑', + logistics: '物流', + agriculture: '农业', + hospitality: '餐饮酒店', + // 常见 key_facts 英文值 + true: '是', + false: '否', + none: '无', + unknown: '未知', + 'n/a': '不适用', + pending: '待定', + active: '活跃', + inactive: '停用', + profit: '盈利', + loss: '亏损', + expansion: '扩张', + contraction: '收缩', + stable: '稳定', + growth: '增长中', + declining: '下滑中', +} + +/** 画像字段标签(dim_desc)英文 → 中文映射 */ +const PROFILE_DIM_LABELS: Record = { + // 标准画像字段 + industry: '行业', + company_size: '企业规模', + role: '角色', + risk_tolerance: '风险偏好', + decision_style: '决策风格', + communication_style: '沟通偏好', + // key_facts 常见 key + region: '地区', + company_type: '公司类型', + team_ability: '团队能力', + communication: '沟通情况', + medical_proof: '医疗证明', + contract_terms: '合同条款', + medical_period: '医疗期', + financial_status: '财务状况', + injury_situation: '工伤情况', + legal_procedures: '法律程序', + market_potential: '市场潜力', + alternative_option: '备选方案', + work_injury_details: '工伤详情', + alternative_solution: '替代方案', + work_injury_insurance: '工伤保险', + performance_assessment: '绩效评估', + relevant_legal_provisions: '相关法律条款', + employee_count: '员工人数', + revenue: '营收', + profit_status: '盈利状况', + business_model: '商业模式', + funding_stage: '融资阶段', + partnership: '合伙关系', + shareholder_structure: '股权结构', + contract_dispute: '合同纠纷', + debt_amount: '债务金额', + tax_risk: '税务风险', + litigation_status: '诉讼状态', + employee_role: '员工角色', + salary_status: '薪资状况', + social_security: '社保', + severance: '经济补偿', + working_years: '工作年限', + probation_period: '试用期', + termination_reason: '解雇原因', + overtime_status: '加班情况', + export_capability: '出口能力', + expansion_plan: '扩张计划', + competitor: '竞争对手', + customer_concentration: '客户集中度', + supply_chain: '供应链', + cash_flow: '现金流', + asset_status: '资产状况', + liability: '负债', +} + +/** 将画像字段的英文标签翻译为中文 */ +function translateDimLabel(label: string): string { + const lower = label.toLowerCase().trim() + return PROFILE_DIM_LABELS[lower] ?? label } /** 将画像字段的英文值翻译为中文显示 */ @@ -179,6 +270,9 @@ export function ChatPanel({ const [factConfirm, setFactConfirm] = useState>([]) const [factConfirmEditing, setFactConfirmEditing] = useState>({}) const [profileFacts, setProfileFacts] = useState>([]) + const [elementTemplate, setElementTemplate] = useState | null>(null) + const [elementFiling, setElementFiling] = useState<{ cause_of_action: string; elements: Array<{ key: string; label: string; value: string }>; claims: string[]; filing_text: string } | null>(null) + const [generatingFiling, setGeneratingFiling] = useState(false) const [analyzing, setAnalyzing] = useState(false) const fileRef = useRef(null) /** 待切换的目标模式(销毁确认后切换) */ @@ -300,12 +394,13 @@ export function ChatPanel({ // 第1步:分析问题,判断是否需要追问 setAnalyzing(true) - const analysis = await api.askAnalyze(currentSid, userQuestion, scene, emotionMode) + const analysis = await api.askAnalyze(currentSid, userQuestion, scene, emotionMode, undefined, topic) setAnalyzing(false) // 保存画像带入事实 const pf = analysis.profile_facts || [] setProfileFacts(pf) + setElementTemplate(analysis.element_template || null) if (analysis.need_ask && analysis.questions && analysis.questions.length > 0) { // 需要追问:显示追问问题 @@ -358,12 +453,14 @@ export function ChatPanel({ scene, emotionMode, allAnswers, + topic, ) setAnalyzing(false) // 更新画像带入事实 const pf = analysis.profile_facts || [] setProfileFacts(pf) + setElementTemplate(analysis.element_template || null) if (analysis.need_ask && analysis.questions && analysis.questions.length > 0) { // 还需追问 @@ -743,25 +840,24 @@ export function ChatPanel({ 确认事实

请核对以下信息,可直接修改后继续分析。确认后将更新你的用户画像。

-
+
{factConfirm.map((f) => { const isProfile = profileFacts.some((p) => p.dim_key === f.dim_key) - // 画像带入的字段值翻译为中文显示 - const displayValue = isProfile - ? (factConfirmEditing[f.dim_key] ?? translateProfileValue(f.answer)) - : (factConfirmEditing[f.dim_key] ?? f.answer) + const rawValue = factConfirmEditing[f.dim_key] ?? f.answer + const displayValue = isProfile ? translateProfileValue(rawValue) : rawValue return ( -
-
- - {isProfile && ( - 画像 - )} -
- + + {translateDimLabel(f.dim_desc)} + + setFactConfirmEditing((prev) => ({ ...prev, [f.dim_key]: e.target.value }))} - className="bg-white h-8 text-sm" + className="min-w-0 flex-1 border-none bg-transparent px-0.5 py-0 text-xs text-foreground focus:outline-none" />
) @@ -821,6 +917,86 @@ export function ChatPanel({ {loading ? : } 确认并分析 + {scene === 'legal' && elementTemplate && ( + + )} +
+
+ )} + + {/* 要素化立案结果 */} + {elementFiling && ( +
+
+ + 要素式起诉状 · {elementFiling.cause_of_action} +
+
+

诉讼请求

+
+ {elementFiling.claims.map((c, i) => ( + ☐ {c} + ))} +
+
+
+

要素清单

+
+ {elementFiling.elements.map((e, i) => ( +
+ {e.label} + {e.value} +
+ ))} +
+
+
+ 查看完整起诉状文本 +
{elementFiling.filing_text}
+
+
+ +
)} diff --git a/web/src/lib/api.ts b/web/src/lib/api.ts index 1fe9c8d..48c5c86 100644 --- a/web/src/lib/api.ts +++ b/web/src/lib/api.ts @@ -127,6 +127,16 @@ async function request(path: string, init?: RequestInit): Promise { export const api = { health: () => request<{ status: string; service: string }>('/health'), + /** AI 动态生成话题列表 */ + getTopics: ( + scene: Scene = 'legal', + existing?: string[], + ) => + request<{ topics: Array<{ title: string; desc: string; samples: string[] }> }>('/topics', { + method: 'POST', + body: JSON.stringify({ scene, existing }), + }), + /** AI 生成示例问题(换一批) */ generateSamples: ( scene: Scene = 'legal', @@ -186,6 +196,29 @@ export const api = { getProfileHistory: () => request<{ results: Array<{ id: number; version: number; profile: Record; source: string; created_at: string }> }>('/profile/me/history'), + /** 要素化立案:根据确认事实 + 案由模板生成要素式起诉状 */ + elementFiling: ( + sid: string, + question: string, + causeOfAction: string, + factAnswers: Array<{ dim_key: string; dim_desc: string; answer: string }>, + template?: Record, + ) => + request<{ + cause_of_action: string + elements: Array<{ key: string; label: string; value: string }> + claims: string[] + filing_text: string + }>(`/sessions/${sid}/element-filing`, { + method: 'POST', + body: JSON.stringify({ + question, + cause_of_action: causeOfAction, + fact_answers: factAnswers, + template, + }), + }), + /** 事实追问分析:返回追问问题或标记事实已充分 */ askAnalyze: ( sid: string, @@ -193,6 +226,7 @@ export const api = { scene: Scene = 'legal', emotionMode?: EmotionMode, factAnswers?: Array<{ dim_key: string; dim_desc: string; answer: string }>, + topic?: string, ) => request<{ need_ask: boolean @@ -203,6 +237,7 @@ export const api = { question_type: string risk_level: string profile_facts?: Array<{ dim_key: string; dim_desc: string; answer: string }> + element_template?: Record }>(`/sessions/${sid}/ask-analyze`, { method: 'POST', body: JSON.stringify({ @@ -210,6 +245,7 @@ export const api = { scene, emotion_mode: emotionMode, fact_answers: factAnswers, + topic, }), }), @@ -331,7 +367,7 @@ export const api = { }), listKnowledge: (docType?: string) => - request<{ results: KnowledgeDoc[] }>( + request<{ results: KnowledgeDoc[]; counts: Record; total: number }>( `/knowledge${docType ? `?doc_type=${docType}` : ''}`, ), diff --git a/web/src/pages/Decisions.tsx b/web/src/pages/Decisions.tsx index 74cc510..00f477d 100644 --- a/web/src/pages/Decisions.tsx +++ b/web/src/pages/Decisions.tsx @@ -1,84 +1,51 @@ -import { useState } from 'react' +import { useState, useCallback } from 'react' import { PageLayout } from '@/components/common/PageLayout' import { ChatPanel } from '@/components/common/ChatPanel' import { Card, CardContent, CardHeader } from '@/components/ui/card' -import { Wallet, Store, Handshake, Tag, UserPlus, Repeat, ChevronDown } from 'lucide-react' +import { TrendingUp, ChevronDown, RefreshCw, Loader2 } from 'lucide-react' import { cn } from '@/lib/utils' +import { api } from '@/lib/api' -/** 决策话题:每个话题对应不同的示例问题 */ -const TOPICS = [ - { - icon: Store, - title: '扩张收缩', - desc: '开店、关店、业务线调整', - samples: [ - '现在适合扩张开第二家店吗?', - '要不要关闭亏损的业务线?', - '新业务线该自营还是加盟?', - '应该先扩张还是先巩固现有市场?', - ], - }, - { - icon: Handshake, - title: '项目承接', - desc: '大单、长期合同、付款条件', - samples: [ - '是否应该接一个付款周期 90 天的大单?', - '长期框架合同要不要签?', - '预付款比例低的项目能接吗?', - '客户要求独家合作,利弊怎么权衡?', - ], - }, - { - icon: Tag, - title: '定价策略', - desc: '降价、涨价、促销', - samples: [ - '该不该降价 15% 抢竞品的客户?', - '产品涨价 10% 会流失多少客户?', - '要不要做满减促销活动?', - '新产品定价应该走高端还是性价比?', - ], - }, - { - icon: UserPlus, - title: '招人裁员', - desc: '关键岗位、团队扩张、减员', - samples: [ - '应该招一个销售总监吗?', - '要不要招应届生自己培养?', - '团队人效低,该裁谁?', - '核心员工被挖,要不要加薪留人?', - ], - }, - { - icon: Wallet, - title: '融资合伙', - desc: '投资、入股、融资', - samples: [ - '要不要接受天使投资?', - '合伙人要退股,怎么谈条件?', - '朋友要入股,股权怎么分?', - '银行贷款还是股权融资更合适?', - ], - }, - { - icon: Repeat, - title: '转型外包', - desc: '业务转型、外包、合作', - samples: [ - '传统业务要不要转型线上?', - '非核心业务外包还是自己做?', - '要不要和同行做联合采购?', - '代工还是自建生产线?', - ], - }, +/** 话题类型 */ +interface Topic { + title: string + desc: string + samples: string[] +} + +/** 经营决策助手:初始兜底话题,换一批时 AI 动态生成 */ +const FALLBACK_TOPICS: Topic[] = [ + { title: '扩张收缩', desc: '开店、关店、业务线', samples: ['现在适合扩张开第二家店吗?', '要不要关闭亏损的业务线?', '新业务线该自营还是加盟?', '应该先扩张还是先巩固?'] }, + { title: '项目承接', desc: '大单、长期合同', samples: ['是否应该接付款周期90天的大单?', '长期框架合同要不要签?', '预付款比例低的项目能接吗?', '客户要求独家合作利弊?'] }, + { title: '定价策略', desc: '涨价、降价、促销', samples: ['该不该降价15%抢竞品客户?', '产品涨价怎么跟客户沟通?', '促销活动会不会损害品牌?', '成本上涨如何调整定价?'] }, + { title: '招人裁员', desc: '招聘、解雇、绩效', samples: ['现在该招人还是裁人?', '裁掉绩效差的员工怎么操作?', '关键岗位招人还是培养?', '外包和正式员工怎么选?'] }, + { title: '融资合伙', desc: '融资、合伙、股权', samples: ['现在适合融资吗?', '合伙人要退股怎么谈条件?', '出让多少股权合适?', '银行贷款还是股权融资?'] }, + { title: '转型外包', desc: '转型、外包、调整', samples: ['业务转型方向怎么选?', '哪些业务可以外包?', '转型期间现金流怎么管理?', '外包质量怎么控?'] }, ] -/** 经营决策助手:情景推演、方案对比、收益/风险/现金流/推荐程度 */ export function Decisions() { + const [topics, setTopics] = useState(FALLBACK_TOPICS) const [selectedTopic, setSelectedTopic] = useState(0) const [topicsCollapsed, setTopicsCollapsed] = useState(false) + const [loadingTopics, setLoadingTopics] = useState(false) + + /** 换一批:调用 AI 动态生成话题(避免重复) */ + const refreshTopics = useCallback(async () => { + setLoadingTopics(true) + try { + const res = await api.getTopics('decision', topics.map((t) => t.title)) + if (res.topics?.length > 0) { + setTopics(res.topics) + setSelectedTopic(0) + } + } catch { + // AI 不可用时保持当前话题 + } finally { + setLoadingTopics(false) + } + }, [topics]) + + const currentTopic = topics[selectedTopic] return ( - +
+ + +
{!topicsCollapsed && ( -
- {TOPICS.map((t, i) => ( - - ))} -
+ {loadingTopics && ( +
+ + AI 正在生成新话题… +
+ )} +
+ {topics.map((t, i) => ( + + ))} +
)}
- + {currentTopic && ( + + )}
) } diff --git a/web/src/pages/KnowledgeBase.tsx b/web/src/pages/KnowledgeBase.tsx index 791cb16..ea36ef8 100644 --- a/web/src/pages/KnowledgeBase.tsx +++ b/web/src/pages/KnowledgeBase.tsx @@ -54,6 +54,7 @@ const DOC_TYPES = [ { value: 'industry', label: '行业知识', icon: Factory }, { value: 'emotion', label: '情绪疏导', icon: Heart }, { value: 'life', label: '生活常识', icon: Coffee }, + { value: 'element_template', label: '要素表模板', icon: FileText }, ] /** 来源英文 → 中文映射 */ @@ -67,6 +68,8 @@ const SOURCE_LABELS: Record = { /** 法规知识库管理:7 类分类,录入、检索、删除 */ export function KnowledgeBase() { const [docs, setDocs] = useState([]) + const [counts, setCounts] = useState>({}) + const [totalCount, setTotalCount] = useState(0) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [searchQuery, setSearchQuery] = useState('') @@ -93,6 +96,8 @@ export function KnowledgeBase() { try { const res = await api.listKnowledge(filterType !== 'all' ? filterType : undefined) setDocs(res.results) + setCounts(res.counts || {}) + setTotalCount(res.total || 0) } catch (e) { setError(e instanceof Error ? e.message : '加载失败') } finally { @@ -255,7 +260,7 @@ export function KnowledgeBase() { size="sm" onClick={() => setFilterType('all')} > - 全部 + 全部 {totalCount} {DOC_TYPES.map((t) => ( ))} @@ -305,7 +311,39 @@ export function KnowledgeBase() { 相关度 {doc.score} )} -

{doc.content}

+ {doc.doc_type !== 'element_template' && ( +

{doc.content}

+ )} + {doc.doc_type === 'element_template' && (() => { + try { + const tmpl = JSON.parse(doc.content) + return ( +
+

案由:{tmpl.cause_of_action}

+

适用:{tmpl.applicable}

+

要素清单({tmpl.elements?.length || 0}项)

+
+ {tmpl.elements?.map((e: Record, i: number) => ( +
+ {e.label} + {e.type}{e.required === '是' ? ' ·必填' : ''} +
+ ))} +
+ {tmpl.claims?.length > 0 && ( + <> +

诉讼请求

+
+ {tmpl.claims.map((c: string, i: number) => ( + {c} + ))} +
+ + )} +
+ ) + } catch { return null } + })()}
来源:{SOURCE_LABELS[doc.source] || doc.source} diff --git a/web/src/pages/LegalAdvisor.tsx b/web/src/pages/LegalAdvisor.tsx index 2de74f9..87bf679 100644 --- a/web/src/pages/LegalAdvisor.tsx +++ b/web/src/pages/LegalAdvisor.tsx @@ -1,136 +1,122 @@ -import { useState } from 'react' +import { useState, useCallback } from 'react' import { PageLayout } from '@/components/common/PageLayout' import { ChatPanel } from '@/components/common/ChatPanel' import { Card, CardContent, CardHeader } from '@/components/ui/card' -import { Briefcase, FileText, Coins, Users, Receipt, Gavel, ChevronDown } from 'lucide-react' +import { Briefcase, ChevronDown, RefreshCw, Loader2 } from 'lucide-react' import { cn } from '@/lib/utils' +import { api } from '@/lib/api' -/** 法务话题:每个话题对应不同的示例问题 */ -const TOPICS = [ - { - icon: Briefcase, - title: '劳动用工', - desc: '工伤、解雇、工资、社保', - samples: [ - '员工工伤后能否开除?', - '员工旷工三天怎么处理?', - '试用期不合格怎么辞退才合法?', - '加班费计算基数怎么确定?', - ], - }, - { - icon: FileText, - title: '合同审查', - desc: '违约金、付款条款、风险点', - samples: [ - '这份合同付款条款有什么风险?', - '合同违约金怎么约定才合理?', - '对方提供的格式合同有哪些坑?', - '口头协议有法律效力吗?', - ], - }, - { - icon: Coins, - title: '债权债务', - desc: '催款、欠款、债务纠纷', - samples: [ - '客户拖欠货款 3 个月如何催收?', - '欠款人跑了,钱还能要回来吗?', - '供应商要求先款后货,有风险吗?', - '债务超过诉讼时效怎么办?', - ], - }, - { - icon: Users, - title: '股东纠纷', - desc: '股权、分红、退股', - samples: [ - '合伙人要退股,怎么谈条件?', - '小股东查账被拒绝怎么办?', - '股东会决议不执行怎么处理?', - '隐名股东权益如何保护?', - ], - }, - { - icon: Receipt, - title: '税务风险', - desc: '稽查、发票、合规', - samples: [ - '收到税务稽查通知怎么办?', - '公司缺进项发票怎么解决?', - '个税汇算清缴有哪些风险点?', - '关联交易定价被质疑怎么办?', - ], - }, - { - icon: Gavel, - title: '诉讼仲裁', - desc: '起诉、应诉、执行', - samples: [ - '官司打赢了对方不执行怎么办?', - '收到法院传票要不要请律师?', - '仲裁和诉讼哪个更适合?', - '诉讼时效快到了还能起诉吗?', - ], - }, +/** 话题类型 */ +interface Topic { + title: string + desc: string + samples: string[] +} + +/** 法务参谋:初始兜底话题,换一批时 AI 动态生成 */ +// 初始兜底话题(同步显示,无 loading) +const FALLBACK_TOPICS: Topic[] = [ + { title: '劳动用工', desc: '工伤、解雇、工资、社保', samples: ['员工工伤后能否开除?', '拖欠工资怎么追讨?', '未签合同双倍工资怎么算?', '社保没缴全怎么补?'] }, + { title: '合同审查', desc: '违约、条款、效力', samples: ['合同违约金怎么约定?', '对方不履行合同怎么办?', '口头协议有法律效力吗?', '合同条款不公平能改吗?'] }, + { title: '债权债务', desc: '欠款、催收、诉讼', samples: ['客户拖欠货款3个月如何催收?', '借条怎么写才有效?', '债务人不还钱能报警吗?', '超过诉讼时效怎么办?'] }, + { title: '股东纠纷', desc: '股权、分红、退股', samples: ['合伙人要退股怎么谈?', '股东不出资怎么办?', '分红比例怎么定?', '小股东权益被侵害怎么办?'] }, + { title: '税务风险', desc: '稽查、发票、合规', samples: ['收到税务稽查通知怎么办?', '发票开错了怎么处理?', '个体户怎么交税最合理?', '税务罚款能减免吗?'] }, + { title: '诉讼仲裁', desc: '起诉、举证、执行', samples: ['打官司要准备哪些证据?', '仲裁和诉讼哪个更快?', '赢了官司对方不执行怎么办?', '诉讼费用怎么算?'] }, ] -/** 法务参谋:劳动用工、合同审查、债权债务、股东纠纷、税务风险 */ export function LegalAdvisor() { + const [topics, setTopics] = useState(FALLBACK_TOPICS) const [selectedTopic, setSelectedTopic] = useState(0) const [topicsCollapsed, setTopicsCollapsed] = useState(false) + const [loadingTopics, setLoadingTopics] = useState(false) + + /** 换一批:调用 AI 动态生成话题(避免重复) */ + const refreshTopics = useCallback(async () => { + setLoadingTopics(true) + try { + const res = await api.getTopics('legal', topics.map((t) => t.title)) + if (res.topics?.length > 0) { + setTopics(res.topics) + setSelectedTopic(0) + } + } catch { + // AI 不可用时保持当前话题 + } finally { + setLoadingTopics(false) + } + }, [topics]) + + const currentTopic = topics[selectedTopic] return ( - +
+ + +
{!topicsCollapsed && ( -
- {TOPICS.map((t, i) => ( - - ))} -
+ {loadingTopics && ( +
+ + AI 正在生成新话题… +
+ )} +
+ {topics.map((t, i) => ( + + ))} +
)}
- + {currentTopic && ( + + )}
) } diff --git a/web/src/pages/LifeAssistant.tsx b/web/src/pages/LifeAssistant.tsx index f4084df..e1b611e 100644 --- a/web/src/pages/LifeAssistant.tsx +++ b/web/src/pages/LifeAssistant.tsx @@ -1,130 +1,121 @@ -import { useState } from 'react' +import { useState, useCallback } from 'react' import { PageLayout } from '@/components/common/PageLayout' import { ChatPanel } from '@/components/common/ChatPanel' import { Card, CardContent, CardHeader } from '@/components/ui/card' -import { Heart, Users, Plane, Moon, GraduationCap, Stethoscope, ChevronDown } from 'lucide-react' +import { Heart, ChevronDown, RefreshCw, Loader2 } from 'lucide-react' import { cn } from '@/lib/utils' +import { api } from '@/lib/api' -/** 话题定义:每个话题对应不同的示例问题 */ -const TOPICS = [ - { - icon: Users, - title: '家庭沟通', - desc: '伴侣、子女、父母关系', - samples: [ - '怎么和青春期的孩子沟通不想他接班的事?', - '和伴侣在花钱观念上有分歧,怎么谈?', - '父母总是干涉经营决策,怎么温和地划清边界?', - ], - }, - { - icon: GraduationCap, - title: '子女教育', - desc: '升学、留学、职业方向', - samples: [ - '孩子中考成绩一般,选普高还是国际学校?', - '要不要送孩子出国留学?什么阶段出去最合适?', - '孩子想学艺术,但担心就业,该怎么引导?', - ], - }, - { - icon: Heart, - title: '父母养老', - desc: '照护方案、医疗安排', - samples: [ - '父母年纪大了,居家养老还是去养老机构?', - '父母需要长期服药,怎么管理用药和复诊?', - '怎么和兄弟姐妹分担父母的养老责任?', - ], - }, - { - icon: Moon, - title: '睡眠与压力', - desc: '身心状态管理', - samples: [ - '最近睡眠很差,有什么改善建议?', - '经营压力大,经常焦虑,怎么自我调节?', - '长期高强度工作,怎么避免职业倦怠?', - ], - }, - { - icon: Plane, - title: '出差日程', - desc: '行程、商务礼仪', - samples: [ - '下周出差三天,怎么安排最高效?', - '第一次见重要客户,商务礼仪要注意什么?', - '出差期间公司有事,怎么远程处理不耽误?', - ], - }, - { - icon: Stethoscope, - title: '健康习惯', - desc: '体检、运动、饮食', - samples: [ - '体检报告有几项异常,需要进一步检查吗?', - '久坐办公,每天多少运动量才够?', - '应酬多,怎么调整饮食减少对身体的负担?', - ], - }, +/** 话题类型 */ +interface Topic { + title: string + desc: string + samples: string[] +} + +/** 生活助理:初始兜底话题,换一批时 AI 动态生成 */ +const FALLBACK_TOPICS: Topic[] = [ + { title: '家庭沟通', desc: '亲子、夫妻、关系', samples: ['怎么和青春期的孩子沟通?', '夫妻因工作吵架怎么办?', '家人不支持创业怎么说服?', '工作太忙忽略家人怎么办?'] }, + { title: '子女教育', desc: '升学、兴趣、规划', samples: ['孩子不想上学怎么办?', '兴趣班该报几个?', '要不要送孩子出国?', '孩子成绩下滑怎么沟通?'] }, + { title: '父母养老', desc: '养老、医疗、陪伴', samples: ['父母年纪大了养老方案怎么选?', '异地父母怎么照顾?', '养老院还是居家养老?', '父母医疗费用怎么分担?'] }, + { title: '睡眠与压力', desc: '失眠、焦虑、调节', samples: ['最近睡眠很差怎么改善?', '工作压力大怎么缓解?', '焦虑到影响工作怎么办?', '怎么判断需要看心理医生?'] }, + { title: '出差日程', desc: '出行、时间管理', samples: ['出差频繁怎么兼顾家庭?', '行程太满怎么优化?', '出差期间公司怎么管?', '如何减少无效出差?'] }, + { title: '健康习惯', desc: '体检、饮食、运动', samples: ['体检报告几项异常怎么办?', '久坐怎么改善健康?', '应酬多怎么控制饮食?', '没时间运动怎么办?'] }, ] -/** 老板生活助理:降低非经营决策负担 */ export function LifeAssistant() { + const [topics, setTopics] = useState(FALLBACK_TOPICS) const [selectedTopic, setSelectedTopic] = useState(0) const [topicsCollapsed, setTopicsCollapsed] = useState(false) + const [loadingTopics, setLoadingTopics] = useState(false) + + /** 换一批:调用 AI 动态生成话题(避免重复) */ + const refreshTopics = useCallback(async () => { + setLoadingTopics(true) + try { + const res = await api.getTopics('life', topics.map((t) => t.title)) + if (res.topics?.length > 0) { + setTopics(res.topics) + setSelectedTopic(0) + } + } catch { + // AI 不可用时保持当前话题 + } finally { + setLoadingTopics(false) + } + }, [topics]) + + const currentTopic = topics[selectedTopic] return ( - +
+ + +
{!topicsCollapsed && ( -
- {TOPICS.map((t, i) => ( - - ))} -
+ {loadingTopics && ( +
+ + AI 正在生成新话题… +
+ )} +
+ {topics.map((t, i) => ( + + ))} +
)}
- + {currentTopic && ( + + )}
) } diff --git a/web/src/pages/MyProfile.tsx b/web/src/pages/MyProfile.tsx index 1638891..3ce1e95 100644 --- a/web/src/pages/MyProfile.tsx +++ b/web/src/pages/MyProfile.tsx @@ -60,6 +60,213 @@ const RISK_LABELS: Record = { aggressive: '进取型', } +/** 角色映射 */ +const ROLE_LABELS: Record = { + owner: '老板/创始人', + manager: '管理者', + ceo: 'CEO', + director: '总监', +} + +/** 决策风格映射 */ +const DECISION_STYLE_LABELS: Record = { + 'data-driven': '数据驱动型', + intuitive: '直觉型', + collaborative: '协作型', +} + +/** 沟通偏好映射 */ +const COMMUNICATION_STYLE_LABELS: Record = { + concise: '简洁', + detailed: '详细', + structured: '结构化', +} + +/** 行业映射 */ +const INDUSTRY_LABELS: Record = { + retail: '零售', + manufacturing: '制造业', + tech: '科技', + service: '服务业', + finance: '金融', + realestate: '房地产', + education: '教育', + healthcare: '医疗健康', + construction: '建筑', + logistics: '物流', + agriculture: '农业', + hospitality: '餐饮酒店', +} + +/** key_facts 的 key 中文映射 */ +const KEY_FACT_LABELS: Record = { + region: '地区', + company_type: '公司类型', + team_ability: '团队能力', + communication: '沟通情况', + medical_proof: '医疗证明', + contract_terms: '合同条款', + medical_period: '医疗期', + financial_status: '财务状况', + injury_situation: '工伤情况', + legal_procedures: '法律程序', + market_potential: '市场潜力', + alternative_option: '备选方案', + work_injury_details: '工伤详情', + alternative_solution: '替代方案', + work_injury_insurance: '工伤保险', + performance_assessment: '绩效评估', + relevant_legal_provisions: '相关法律条款', + employee_count: '员工人数', + revenue: '营收', + profit_status: '盈利状况', + business_model: '商业模式', + funding_stage: '融资阶段', + expansion_plan: '扩张计划', + competitor: '竞争对手', + customer_concentration: '客户集中度', + supply_chain: '供应链', + cash_flow: '现金流', + asset_status: '资产状况', + liability: '负债', + contract_dispute: '合同纠纷', + debt_amount: '债务金额', + tax_risk: '税务风险', + litigation_status: '诉讼状态', + shareholder_structure: '股权结构', + partnership: '合伙关系', + salary_status: '薪资状况', + social_security: '社保', + severance: '经济补偿', + working_years: '工作年限', + probation_period: '试用期', + termination_reason: '解雇原因', + overtime_status: '加班情况', + export_capability: '出口能力', + family_situation: '家庭情况', + health_status: '健康状况', + travel_plan: '出行计划', + important_event: '重要事项', + education_background: '教育背景', + stress_source: '压力来源', + personality: '性格特征', + work_time: '工作时间', + contract_status: '合同状态', + salary_calculation_basis: '薪资计算依据', + injury_detail: '受伤详情', + treatment_status: '治疗状况', + recovery_status: '康复状况', + compensation_claim: '赔偿诉求', + arbitration_status: '仲裁状态', + employment_relationship: '劳动关系', + wage_standard: '工资标准', + working_hours: '工时', + leave_record: '请假记录', + discipline_record: '违纪记录', + training_agreement: '培训协议', + confidentiality_agreement: '保密协议', + non_compete: '竞业限制', + ip_ownership: '知识产权归属', + data_protection: '数据保护', + compliance_status: '合规状况', + regulatory_requirement: '监管要求', + license_status: '许可状态', + audit_finding: '审计发现', + internal_control: '内部控制', + risk_management: '风险管理', + insurance_coverage: '保险覆盖', + claim_status: '理赔状态', + policy_detail: '保单详情', + premium_status: '保费状态', + beneficiary: '受益人', + coverage_amount: '保额', + deductible: '免赔额', + policy_period: '保险期间', + renewal_status: '续保状态', + cancellation_reason: '退保原因', + loan_purpose: '借款用途', + repayment_plan: '还款计划', + collateral: '抵押物', + guarantor_info: '担保人', + interest_rate: '利率', + penalty_rate: '罚息率', + overdue_days: '逾期天数', + collection_status: '催收状态', + settlement_status: '结算状态', + bankruptcy_status: '破产状态', + restructure_plan: '重组方案', + liquidation_status: '清算状态', + debt_restructuring: '债务重组', + asset_disposal: '资产处置', + business_transfer: '业务转让', + merger_status: '并购状态', + acquisition_status: '收购状态', + divestiture: '剥离', + joint_venture: '合资', + strategic_alliance: '战略联盟', + ip_valuation: '知识产权估值', + technology_transfer: '技术转让', + royalty_rate: '许可费率', + infringement_scope: '侵权范围', + damages_claim: '损害赔偿诉求', + injunction_status: '禁令状态', + invalidation_request: '无效宣告请求', + opposition_status: '异议状态', + licensing_term: '许可期限', + territory: '地域范围', + exclusivity: '排他性', + sublicensing: '再许可', + warranty_term: '保证条款', + indemnity: '补偿条款', + limitation_liability: '责任限制', + force_majeure: '不可抗力', + dispute_resolution: '争议解决', + governing_law: '适用法律', + jurisdiction: '管辖', + arbitration_clause: '仲裁条款', + mediation_status: '调解状态', + enforcement_status: '执行状态', + execution_status: '执行状况', + preservation_measure: '保全措施', + objection_status: '异议状态', + retrial_request: '再审请求', + appeal_status: '上诉状态', + court_level: '法院层级', + case_procedure: '案件程序', + hearing_date: '开庭日期', + evidence_status: '举证状况', + witness_status: '证人状况', + expert_evaluation: '专家鉴定', + judicial_interpretation: '司法解释', + precedent_case: '先例案例', + legislation_reference: '法律依据', +} + +/** key_facts 的值中文映射 */ +const KEY_FACT_VALUE_LABELS: Record = { + yes: '是', + no: '否', + true: '是', + false: '否', + none: '无', + unknown: '未知', + 'n/a': '不适用', + pending: '待定', + active: '活跃', + inactive: '停用', + profit: '盈利', + loss: '亏损', + expansion: '扩张', + contraction: '收缩', + stable: '稳定', + growth: '增长中', + declining: '下滑中', + ...SIZE_LABELS, + ...RISK_LABELS, + ...ROLE_LABELS, + ...INDUSTRY_LABELS, +} + /** 场景中文映射 */ const SCENE_LABELS: Record = { legal: '法务参谋', @@ -87,9 +294,24 @@ function formatTime(dt: string): string { function formatValue(key: string, value: string): string { if (key === 'company_size') return SIZE_LABELS[value] || value if (key === 'risk_tolerance') return RISK_LABELS[value] || value + if (key === 'role') return ROLE_LABELS[value] || value + if (key === 'decision_style') return DECISION_STYLE_LABELS[value] || value + if (key === 'communication_style') return COMMUNICATION_STYLE_LABELS[value] || value + if (key === 'industry') return INDUSTRY_LABELS[value] || value return value } +/** 翻译 key_facts 的 key */ +function translateFactKey(key: string): string { + return KEY_FACT_LABELS[key.toLowerCase()] || key +} + +/** 翻译 key_facts 的值 */ +function translateFactValue(value: string): string { + const lower = value.toLowerCase().trim() + return KEY_FACT_VALUE_LABELS[lower] || value +} + export function MyProfile() { const [profile, setProfile] = useState(null) const [history, setHistory] = useState([]) @@ -136,45 +358,48 @@ export function MyProfile() {
- {Object.entries(FIELD_LABELS).map(([key, label]) => { - const val = hp[key] as string - if (!val) return null - return ( -
- {label} - {formatValue(key, val)} -
- ) - })} + {/* 标准字段:多列网格 */} +
+ {Object.entries(FIELD_LABELS).map(([key, label]) => { + const val = hp[key] as string + if (!val) return null + return ( +
+ {label} + {formatValue(key, val)} +
+ ) + })} +
{Array.isArray(hp.common_topics) && (hp.common_topics as string[]).length > 0 && (
-

常问话题

-
+

常问话题

+
{(hp.common_topics as string[]).map((t, i) => ( - {String(t)} + {String(t)} ))}
)} {Boolean(hp.key_facts && typeof hp.key_facts === 'object' && !Array.isArray(hp.key_facts) && Object.keys(hp.key_facts as Record).length > 0) && (
-

关键事实

-
+

关键事实

+
{Object.entries(hp.key_facts as Record).map(([k, v]) => (
- {k} - {String(v)} + {translateFactKey(k)} + {translateFactValue(String(v))}
))}
)} {Array.isArray(hp.common_scenes) && (hp.common_scenes as string[]).length > 0 && ( -
-

常用场景

-
+
+ 常用场景 +
{(hp.common_scenes as string[]).map((s, i) => ( - + {SCENE_LABELS[String(s)] || String(s)} ))} @@ -206,23 +431,26 @@ export function MyProfile() {
- {Object.entries(FIELD_LABELS).map(([key, label]) => { - const val = profile[key as keyof ProfileData] as string - if (!val) return null - return ( -
- {label} - {formatValue(key, val)} -
- ) - })} + {/* 标准字段:多列网格 */} +
+ {Object.entries(FIELD_LABELS).map(([key, label]) => { + const val = profile[key as keyof ProfileData] as string + if (!val) return null + return ( +
+ {label} + {formatValue(key, val)} +
+ ) + })} +
{profile.common_topics && profile.common_topics.length > 0 && (
-

常问话题

-
+

常问话题

+
{profile.common_topics.map((t, i) => ( - {t} + {t} ))}
@@ -230,12 +458,12 @@ export function MyProfile() { {profile.key_facts && Object.keys(profile.key_facts).length > 0 && (
-

关键事实

-
+

关键事实

+
{Object.entries(profile.key_facts).map(([k, v]) => (
- {k} - {v} + {translateFactKey(k)} + {translateFactValue(v)}
))}
@@ -243,11 +471,11 @@ export function MyProfile() { )} {profile.common_scenes && profile.common_scenes.length > 0 && ( -
-

常用场景

-
+
+ 常用场景 +
{profile.common_scenes.map((s, i) => ( - + {SCENE_LABELS[s] || s} ))} @@ -256,7 +484,7 @@ export function MyProfile() { )} {profile.last_active && ( -

+

最后活跃:{formatTime(profile.last_active)}

)}