fix:优化输出内容
This commit is contained in:
@@ -34,9 +34,9 @@ def _is_likely_timeout_error(exc: BaseException) -> bool:
|
||||
return "timed out" in s or "timeout" in s
|
||||
|
||||
|
||||
# 短文洗稿:5 个自然段、正文总字数上限(含标点)
|
||||
MAX_BODY_CHARS = 500
|
||||
# 短文洗稿:正文目标约 500 字,优先完整性(软约束,不硬截断)
|
||||
MIN_BODY_CHARS = 80
|
||||
TARGET_BODY_CHARS = 500
|
||||
|
||||
|
||||
def _preview_for_log(text: str, limit: int = 400) -> str:
|
||||
@@ -54,7 +54,7 @@ SYSTEM_PROMPT = """
|
||||
1) **忠实原意**:只概括、转述原文已有信息,不编造事实,不偷换主题;
|
||||
2) 语气通俗、干脆,避免套话堆砌;
|
||||
3) 只输出合法 JSON:title, summary, body_markdown;
|
||||
4) **body_markdown 约束**:恰好 **5 个自然段**;段与段之间用一个空行分隔;**不要**使用 # / ## 标题符号;全文(正文)总字数 **不超过 500 字**(含标点);
|
||||
4) **body_markdown 约束**:按内容密度使用 **4~6 个自然段**;段与段之间用一个空行分隔;**不要**使用 # / ## 标题符号;正文以 **约 500 字**为目标,优先完整表达并避免冗长重复;
|
||||
5) title、summary 也要短:标题约 8~18 字;摘要约 40~80 字;
|
||||
6) 正文每段需首行缩进(建议段首使用两个全角空格「 」),避免顶格;
|
||||
7) 关键观点需要加粗:请用 Markdown `**加粗**` 标出 2~4 个重点短语;
|
||||
@@ -71,19 +71,19 @@ REWRITE_SCHEMA_HINT = """
|
||||
}
|
||||
|
||||
body_markdown 写法:
|
||||
- 必须且只能有 **5 段**:每段若干完整句子,段之间 **\\n\\n**(空一行);
|
||||
- 使用 **4~6 段**:每段若干完整句子,段之间 **\\n\\n**(空一行);
|
||||
- **禁止** markdown 标题(不要用 #);
|
||||
- 正文总长 **≤500 字**,宁可短而清楚,不要写满废话;
|
||||
- 正文目标约 **500 字**(可上下浮动),以信息完整为先,避免冗长和重复;
|
||||
- 每段段首请保留首行缩进(两个全角空格「 」);
|
||||
- 请用 `**...**` 加粗 2~4 个关键观点词;
|
||||
- 内容顺序建议:第 1 段交代在说什么;中间 3 段展开关键信息;最后 1 段收束或提醒(均须紧扣原文,勿乱发挥)。
|
||||
- 内容顺序建议:首段交代在说什么;中间段展开关键信息;末段收束或提醒(均须紧扣原文,勿乱发挥)。
|
||||
""".strip()
|
||||
|
||||
# 通义等模型若首次过短/结构不对,再要一次
|
||||
_JSON_BODY_TOO_SHORT_RETRY = """
|
||||
|
||||
【系统复检】上一次 body_markdown 不符合要求。请重输出**完整** JSON:
|
||||
- 正文必须 **恰好 5 个自然段**(仅 \\n\\n 分段),无 # 标题,总字数 **≤500 字**;
|
||||
- 正文必须使用 **4~6 个自然段**(仅 \\n\\n 分段),无 # 标题;篇幅尽量收敛到约 500 字,同时保持信息完整;
|
||||
- 忠实原稿、简短高效;
|
||||
- 引号只用「」『』;
|
||||
- 只输出 JSON。
|
||||
@@ -347,7 +347,8 @@ class AIRewriter:
|
||||
self, req: RewriteRequest, cleaned_source: str, reason: str, trace: dict[str, Any] | None = None
|
||||
) -> RewriteResponse:
|
||||
sentences = self._extract_sentences(cleaned_source)
|
||||
points = self._pick_key_points(sentences, limit=5)
|
||||
para_count = self._fallback_para_count(cleaned_source)
|
||||
points = self._pick_key_points(sentences, limit=max(5, para_count))
|
||||
title = req.title_hint.strip() or self._build_fallback_title(sentences)
|
||||
|
||||
summary = self._build_fallback_summary(points, cleaned_source)
|
||||
@@ -358,17 +359,14 @@ class AIRewriter:
|
||||
t = re.sub(r"\s+", " ", (s or "").strip())
|
||||
return t if len(t) <= n else t[: n - 1] + "…"
|
||||
|
||||
paras = [
|
||||
_one_line(self._build_intro(points, cleaned_source), 105),
|
||||
_one_line(analysis["cause"], 105),
|
||||
_one_line(analysis["impact"], 105),
|
||||
_one_line(analysis["risk"], 105),
|
||||
_one_line(conclusion, 105),
|
||||
]
|
||||
paras = [_one_line(self._build_intro(points, cleaned_source), 105)]
|
||||
if para_count >= 4:
|
||||
paras.append(_one_line(analysis["cause"], 105))
|
||||
paras.append(_one_line(analysis["impact"], 105))
|
||||
if para_count >= 5:
|
||||
paras.append(_one_line(analysis["risk"], 105))
|
||||
paras.append(_one_line(conclusion, 105))
|
||||
body = "\n\n".join(paras)
|
||||
if len(body) > MAX_BODY_CHARS:
|
||||
body = body[: MAX_BODY_CHARS - 1] + "…"
|
||||
|
||||
normalized = {
|
||||
"title": title,
|
||||
"summary": summary,
|
||||
@@ -429,6 +427,14 @@ class AIRewriter:
|
||||
),
|
||||
}
|
||||
|
||||
def _fallback_para_count(self, source: str) -> int:
|
||||
length = len((source or "").strip())
|
||||
if length < 240:
|
||||
return 4
|
||||
if length > 1200:
|
||||
return 6
|
||||
return 5
|
||||
|
||||
def _clean_source(self, text: str) -> str:
|
||||
src = (text or "").replace("\r\n", "\n").strip()
|
||||
src = re.sub(r"https?://\S+", "", src)
|
||||
@@ -725,8 +731,6 @@ class AIRewriter:
|
||||
text = (body or "").strip()
|
||||
if not text:
|
||||
text = "(正文生成失败,请重试。)"
|
||||
if len(text) > MAX_BODY_CHARS:
|
||||
text = text[: MAX_BODY_CHARS - 1] + "…"
|
||||
return text
|
||||
|
||||
def _quality_issues(
|
||||
@@ -749,16 +753,18 @@ class AIRewriter:
|
||||
|
||||
paragraphs = [p.strip() for p in re.split(r"\n\s*\n", body) if p.strip()]
|
||||
pc = len(paragraphs)
|
||||
need_p = 4 if lenient else 5
|
||||
if pc < need_p:
|
||||
issues.append(f"正文需约 5 个自然段、空行分隔(当前 {pc} 段)")
|
||||
elif not lenient and pc > 6:
|
||||
issues.append(f"正文段落过多(当前 {pc} 段),请合并为 5 段左右")
|
||||
min_p, max_p = (3, 6) if lenient else (4, 6)
|
||||
if pc < min_p:
|
||||
issues.append(f"正文段落偏少(当前 {pc} 段),建议 {min_p}-{max_p} 段")
|
||||
elif pc > max_p:
|
||||
issues.append(f"正文段落偏多(当前 {pc} 段),建议控制在 {min_p}-{max_p} 段")
|
||||
|
||||
if len(body) > MAX_BODY_CHARS:
|
||||
issues.append(f"正文超过 {MAX_BODY_CHARS} 字(当前 {len(body)} 字),请压缩")
|
||||
elif len(body) < MIN_BODY_CHARS:
|
||||
if len(body) < MIN_BODY_CHARS:
|
||||
issues.append(f"正文过短(当前阈值 ≥{MIN_BODY_CHARS} 字)")
|
||||
elif len(body) > 900:
|
||||
issues.append(
|
||||
f"正文偏长(当前 {len(body)} 字),建议收敛到约 {TARGET_BODY_CHARS} 字(可上下浮动)"
|
||||
)
|
||||
|
||||
if re.search(r"(?m)^#+\s", body):
|
||||
issues.append("正文请勿使用 # 标题符号,只用自然段")
|
||||
@@ -805,8 +811,6 @@ class AIRewriter:
|
||||
title = (normalized.get("title") or "").strip()
|
||||
if len(title) < 4 or len(body) < 40:
|
||||
return False
|
||||
if len(body) > MAX_BODY_CHARS + 80:
|
||||
return False
|
||||
return True
|
||||
|
||||
def _format_markdown(self, text: str) -> str:
|
||||
|
||||
Reference in New Issue
Block a user