feat: 话题动态化 + 要素化立案 + 知识库增强
话题动态化: - 新增 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>
This commit is contained in:
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user