Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
-
import os, json, html, requests, re
|
| 2 |
import gradio as gr
|
| 3 |
|
| 4 |
-
APP_TITLE = "孙子你好(DeepSeek
|
| 5 |
|
| 6 |
# 可通过 Secrets 覆盖:
|
| 7 |
# DEEPSEEK_API_KEY = sk-xxxxxxxx
|
|
@@ -12,20 +12,28 @@ APP_TITLE = "孙子你好(DeepSeek 直连·诊断版)"
|
|
| 12 |
MODEL_NAME = os.getenv("DEEPSEEK_MODEL", "deepseek-chat").strip() or "deepseek-chat"
|
| 13 |
|
| 14 |
SYS_PROMPT = (
|
| 15 |
-
"你是中文军师,
|
|
|
|
| 16 |
"规则:\n"
|
| 17 |
-
"1
|
| 18 |
-
"
|
| 19 |
-
"
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
"
|
| 24 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
)
|
| 26 |
|
| 27 |
-
# few-shot
|
| 28 |
FEWSHOT = [
|
|
|
|
| 29 |
{
|
| 30 |
"role": "user",
|
| 31 |
"content": "问题:老板临时要我通宵加班,我状态很差,怎么体面拒绝?只输出JSON。"
|
|
@@ -33,14 +41,15 @@ FEWSHOT = [
|
|
| 33 |
{
|
| 34 |
"role": "assistant",
|
| 35 |
"content": json.dumps({
|
| 36 |
-
"chapter": "
|
| 37 |
-
"quote": "
|
| 38 |
"unsure": False,
|
| 39 |
-
"insight": "
|
| 40 |
-
"action": "
|
| 41 |
-
"speech": "
|
| 42 |
}, ensure_ascii=False)
|
| 43 |
},
|
|
|
|
| 44 |
{
|
| 45 |
"role": "user",
|
| 46 |
"content": "问题:朋友借钱不还,怎样体面要回?只输出JSON。"
|
|
@@ -52,14 +61,46 @@ FEWSHOT = [
|
|
| 52 |
"quote": "兵者,诡道也。",
|
| 53 |
"unsure": False,
|
| 54 |
"insight": "绕开硬催,设局顺势收回。",
|
| 55 |
-
"action": "
|
| 56 |
-
"speech": "我这边在清账需要安排下,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 57 |
}, ensure_ascii=False)
|
| 58 |
}
|
| 59 |
]
|
| 60 |
|
| 61 |
def call_deepseek(user_question: str, alt: bool = False) -> dict:
|
| 62 |
-
"""带精确诊断:自动尝试两个端点,页面/日志展示状态码与返回体。"""
|
| 63 |
key = os.getenv("DEEPSEEK_API_KEY", "").strip()
|
| 64 |
if not key:
|
| 65 |
return {
|
|
@@ -77,7 +118,16 @@ def call_deepseek(user_question: str, alt: bool = False) -> dict:
|
|
| 77 |
"https://api.deepseek.com/chat/completions",
|
| 78 |
]
|
| 79 |
|
| 80 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 81 |
{"role": "user", "content": f"问题:{user_question} 只输出JSON。"}
|
| 82 |
]
|
| 83 |
|
|
@@ -97,7 +147,7 @@ def call_deepseek(user_question: str, alt: bool = False) -> dict:
|
|
| 97 |
json=payload,
|
| 98 |
timeout=60
|
| 99 |
)
|
| 100 |
-
print(f"[DeepSeek] endpoint={ep} status={r.status_code} model={MODEL_NAME}") #
|
| 101 |
|
| 102 |
if r.status_code // 100 != 2:
|
| 103 |
try:
|
|
@@ -113,19 +163,17 @@ def call_deepseek(user_question: str, alt: bool = False) -> dict:
|
|
| 113 |
js = m.group(0) if m else content
|
| 114 |
result = json.loads(js)
|
| 115 |
|
| 116 |
-
# 规整长度,防止偶发超长
|
| 117 |
return {
|
| 118 |
"chapter": result.get("chapter", "")[:20],
|
| 119 |
-
"quote": result.get("quote", "")[:
|
| 120 |
"unsure": bool(result.get("unsure", False)),
|
| 121 |
"insight": result.get("insight", "")[:40],
|
| 122 |
-
"action": result.get("action", "")[:
|
| 123 |
-
"speech": result.get("speech", "")[:
|
| 124 |
}
|
| 125 |
except Exception as e:
|
| 126 |
last_err = f"{type(e).__name__}: {e}"
|
| 127 |
|
| 128 |
-
# 两个端点都失败
|
| 129 |
return {
|
| 130 |
"chapter": "",
|
| 131 |
"quote": "为避免误引,已隐藏原文与篇名(模型不确定出典)。",
|
|
|
|
| 1 |
+
import os, json, html, requests, re, random
|
| 2 |
import gradio as gr
|
| 3 |
|
| 4 |
+
APP_TITLE = "孙子你好(DeepSeek 多样化·诊断版)"
|
| 5 |
|
| 6 |
# 可通过 Secrets 覆盖:
|
| 7 |
# DEEPSEEK_API_KEY = sk-xxxxxxxx
|
|
|
|
| 12 |
MODEL_NAME = os.getenv("DEEPSEEK_MODEL", "deepseek-chat").strip() or "deepseek-chat"
|
| 13 |
|
| 14 |
SYS_PROMPT = (
|
| 15 |
+
"你是中文军师,擅长将《孙子兵法》的智慧用于现实问题。\n"
|
| 16 |
+
"任务:针对用户的问题,从《孙子兵法》十三篇中找出最贴合的一章,引用原文(若能确定),并转化为现代生活策略。\n\n"
|
| 17 |
"规则:\n"
|
| 18 |
+
"1. 优先根据问题性质挑选不同篇章:\n"
|
| 19 |
+
" - 计划/评估:〈始计篇〉〈作战篇〉\n"
|
| 20 |
+
" - 谈判/攻防:〈谋攻篇〉〈虚实篇〉\n"
|
| 21 |
+
" - 节奏/风险:〈军形篇〉〈兵势篇〉\n"
|
| 22 |
+
" - 主动出击/竞争:〈军争篇〉〈九变篇〉〈地形篇〉\n"
|
| 23 |
+
" - 困境/沟通:〈行军篇〉〈九地篇〉〈用间篇〉〈火攻篇〉\n"
|
| 24 |
+
"2. 若问题重复,尽量换不同篇章或换角度回答,保持多样性。\n"
|
| 25 |
+
"3. 若无法百分之百确认原文或篇名,不要硬编,改为思想意译并标记 unsure=true。\n"
|
| 26 |
+
"4. 严格仅输出 JSON,固定字段:\n"
|
| 27 |
+
" {\"chapter\":\"<篇名>\",\"quote\":\"<原文或思想>\",\"unsure\":false/true,"
|
| 28 |
+
"\"insight\":\"<一句人话启示≤24字>\",\"action\":\"<一步可执行做法≤100字>\","
|
| 29 |
+
"\"speech\":\"<直接可说的话术≤120字>\"}\n"
|
| 30 |
+
"5. 语气简洁、机智、委婉、有边界;不得人身攻击、威胁或违法建议。\n"
|
| 31 |
+
"6. 禁止输出 JSON 以外的任何文字。"
|
| 32 |
)
|
| 33 |
|
| 34 |
+
# few-shot:覆盖多篇章,减少模型只用某一章的倾向
|
| 35 |
FEWSHOT = [
|
| 36 |
+
# 加班 → 作战篇
|
| 37 |
{
|
| 38 |
"role": "user",
|
| 39 |
"content": "问题:老板临时要我通宵加班,我状态很差,怎么体面拒绝?只输出JSON。"
|
|
|
|
| 41 |
{
|
| 42 |
"role": "assistant",
|
| 43 |
"content": json.dumps({
|
| 44 |
+
"chapter": "作战篇",
|
| 45 |
+
"quote": "夫兵久而国利者,未之有也。",
|
| 46 |
"unsure": False,
|
| 47 |
+
"insight": "避免持久消耗,保整体战力。",
|
| 48 |
+
"action": "提出“明早高质量交付”的替代方案,比熬夜更稳更可靠。",
|
| 49 |
+
"speech": "今晚赶出来质量可能不稳,我建议明早整理成终版,保证更可靠,您看可以吗?"
|
| 50 |
}, ensure_ascii=False)
|
| 51 |
},
|
| 52 |
+
# 借钱 → 始计篇
|
| 53 |
{
|
| 54 |
"role": "user",
|
| 55 |
"content": "问题:朋友借钱不还,怎样体面要回?只输出JSON。"
|
|
|
|
| 61 |
"quote": "兵者,诡道也。",
|
| 62 |
"unsure": False,
|
| 63 |
"insight": "绕开硬催,设局顺势收回。",
|
| 64 |
+
"action": "以“清账/安排资金”为由先要部分或分期,降低对抗。",
|
| 65 |
+
"speech": "我这边在清账需要安排下,能否先转一部分?分期也行,别影响咱们交情。"
|
| 66 |
+
}, ensure_ascii=False)
|
| 67 |
+
},
|
| 68 |
+
# 邻居噪音 → 行军篇
|
| 69 |
+
{
|
| 70 |
+
"role": "user",
|
| 71 |
+
"content": "问题:邻居太吵,怎么友好沟通?只输出JSON。"
|
| 72 |
+
},
|
| 73 |
+
{
|
| 74 |
+
"role": "assistant",
|
| 75 |
+
"content": json.dumps({
|
| 76 |
+
"chapter": "行军篇",
|
| 77 |
+
"quote": "知彼知己,百战不��。(通用于沟通前的情势判断)",
|
| 78 |
+
"unsure": True, # 行军篇原文无此句,标不确定,演示 unsure 机制
|
| 79 |
+
"insight": "先辨来源时机,再择机沟通。",
|
| 80 |
+
"action": "选非冲突时段,先体谅再提困扰,争取对方自觉收敛。",
|
| 81 |
+
"speech": "最近晚上声音有点明显,我怕打扰到楼上楼下。能否帮忙晚间稍微注意下?谢谢啦~"
|
| 82 |
+
}, ensure_ascii=False)
|
| 83 |
+
},
|
| 84 |
+
# 职场竞争 → 军争篇
|
| 85 |
+
{
|
| 86 |
+
"role": "user",
|
| 87 |
+
"content": "问题:同事跟我抢功劳,怎么应对?只输出JSON。"
|
| 88 |
+
},
|
| 89 |
+
{
|
| 90 |
+
"role": "assistant",
|
| 91 |
+
"content": json.dumps({
|
| 92 |
+
"chapter": "军争篇",
|
| 93 |
+
"quote": "以迂为直,以患为利。",
|
| 94 |
+
"unsure": False,
|
| 95 |
+
"insight": "不硬碰,转势为己用。",
|
| 96 |
+
"action": "会前先递交要点纪要和分工佐证,令功劳记录化、流程化。",
|
| 97 |
+
"speech": "我把这次我的负责点和关键产出提前发一份纪要,方便会里对齐,避免遗漏。"
|
| 98 |
}, ensure_ascii=False)
|
| 99 |
}
|
| 100 |
]
|
| 101 |
|
| 102 |
def call_deepseek(user_question: str, alt: bool = False) -> dict:
|
| 103 |
+
"""带精确诊断:自动尝试两个端点,页面/日志展示状态码与返回体;加入多样化提示。"""
|
| 104 |
key = os.getenv("DEEPSEEK_API_KEY", "").strip()
|
| 105 |
if not key:
|
| 106 |
return {
|
|
|
|
| 118 |
"https://api.deepseek.com/chat/completions",
|
| 119 |
]
|
| 120 |
|
| 121 |
+
# 多样化提示:鼓励换篇章/换角度
|
| 122 |
+
diversity_hint = random.choice([
|
| 123 |
+
"尽量避免重复使用同一篇章,尝试换篇章回答。",
|
| 124 |
+
"优先考虑《军形篇》《兵势篇》《九变篇》《地形篇》的角度。",
|
| 125 |
+
"如果问题可多解,换一个不同篇章来解释。",
|
| 126 |
+
"引用少见但贴合的篇章,保持回答多样性。",
|
| 127 |
+
"可从节奏、态势、资源、时机等不同维度选篇章。"
|
| 128 |
+
])
|
| 129 |
+
|
| 130 |
+
msgs = [{"role": "system", "content": SYS_PROMPT + "\n" + diversity_hint}] + FEWSHOT + [
|
| 131 |
{"role": "user", "content": f"问题:{user_question} 只输出JSON。"}
|
| 132 |
]
|
| 133 |
|
|
|
|
| 147 |
json=payload,
|
| 148 |
timeout=60
|
| 149 |
)
|
| 150 |
+
print(f"[DeepSeek] endpoint={ep} status={r.status_code} model={MODEL_NAME}") # Runtime logs
|
| 151 |
|
| 152 |
if r.status_code // 100 != 2:
|
| 153 |
try:
|
|
|
|
| 163 |
js = m.group(0) if m else content
|
| 164 |
result = json.loads(js)
|
| 165 |
|
|
|
|
| 166 |
return {
|
| 167 |
"chapter": result.get("chapter", "")[:20],
|
| 168 |
+
"quote": result.get("quote", "")[:200],
|
| 169 |
"unsure": bool(result.get("unsure", False)),
|
| 170 |
"insight": result.get("insight", "")[:40],
|
| 171 |
+
"action": result.get("action", "")[:120],
|
| 172 |
+
"speech": result.get("speech", "")[:140]
|
| 173 |
}
|
| 174 |
except Exception as e:
|
| 175 |
last_err = f"{type(e).__name__}: {e}"
|
| 176 |
|
|
|
|
| 177 |
return {
|
| 178 |
"chapter": "",
|
| 179 |
"quote": "为避免误引,已隐藏原文与篇名(模型不确定出典)。",
|