V3.3.1 修复:WBS 解析 'Extra data' 报错 + 开工接口空 body 容错

- parse_wbs 改用 raw_decode 提取第一个完整 JSON,忽略尾部杂质/多余 JSON(原按首{到尾}切片,模型输出带第二段JSON或解释文字时解析失败)
- 兼容 subtasks/task_list/items/task 等任务键名
- /autostart 接口 get_json 改 silent 容错(无 body 时不再 400)
This commit is contained in:
2026-08-14 12:55:15 +08:00
parent c8cc945b8d
commit f53e1b264e
2 changed files with 28 additions and 22 deletions
+1 -1
View File
@@ -1076,7 +1076,7 @@ def project_autostart(pid):
return jsonify({'ok': False, 'error': '请先在编辑项目中设置 AI 主管 Worker'}), 400 return jsonify({'ok': False, 'error': '请先在编辑项目中设置 AI 主管 Worker'}), 400
if not db.q('SELECT 1 FROM project_team_workers WHERE project_id=?', (pid,)): if not db.q('SELECT 1 FROM project_team_workers WHERE project_id=?', (pid,)):
return jsonify({'ok': False, 'error': '请先在编辑项目中勾选干活团队 Worker(≥1 个)'}), 400 return jsonify({'ok': False, 'error': '请先在编辑项目中勾选干活团队 Worker(≥1 个)'}), 400
d = request.get_json(force=True) or {} d = request.get_json(silent=True) or {}
ok = autostart.launch(pid, review_required=1 if d.get('auto_review') else 0) ok = autostart.launch(pid, review_required=1 if d.get('auto_review') else 0)
if not ok: if not ok:
return jsonify({'ok': False, 'error': 'AI 主管正在工作中,请稍候'}), 400 return jsonify({'ok': False, 'error': 'AI 主管正在工作中,请稍候'}), 400
+27 -21
View File
@@ -47,19 +47,39 @@ REVISE_PROMPT = (
) )
def parse_wbs(text): def _extract_json(text):
"""从 LLM 输出中稳健提取 JSON 任务列表""" """用 raw_decode 稳健提取第一个完整 JSON 值(自动忽略尾部杂质/多余 JSON)"""
t = text.strip() t = text.strip()
if t.startswith('```'): if t.startswith('```'):
t = t.strip('`') t = t.strip('`')
if t.startswith('json'): if t.startswith('json'):
t = t[4:] t = t[4:]
t = t.strip() t = t.strip()
start = min([i for i in (t.find('{'), t.find('[')) if i >= 0] or [0]) candidates = [i for i in (t.find('{'), t.find('[')) if i >= 0]
end = max(t.rfind('}'), t.rfind(']')) + 1 last_err = None
data = json.loads(t[start:end]) for i in sorted(candidates):
tasks = data['tasks'] if isinstance(data, dict) else data try:
assert isinstance(tasks, list) and tasks, '任务列表为空' obj, _ = json.JSONDecoder().raw_decode(t[i:])
return obj
except Exception as e:
last_err = e
raise last_err or ValueError('未找到 JSON 内容')
def parse_wbs(text):
"""从 LLM 输出中稳健提取 JSON 任务列表(兼容任务键名/多余内容)"""
try:
data = _extract_json(text)
except Exception:
raise
if isinstance(data, dict):
for key in ('tasks', 'subtasks', 'task_list', 'items', 'task'):
if key in data:
data = data[key]
break
tasks = data if isinstance(data, list) else []
if not tasks:
raise ValueError('任务列表为空或格式不正确')
return tasks return tasks
@@ -100,20 +120,6 @@ def _chat_json(worker, messages, max_tokens=3000, temperature=0.3):
raise last_err or ValueError('JSON 解析失败') raise last_err or ValueError('JSON 解析失败')
def _extract_json(text):
t = text.strip()
if t.startswith('```'):
t = t.strip('`')
if t.startswith('json'):
t = t[4:]
t = t.strip()
start = min([i for i in (t.find('{'), t.find('[')) if i >= 0] or [0])
end = max(t.rfind('}'), t.rfind(']')) + 1
if end <= start:
raise ValueError('未找到 JSON 内容')
return json.loads(t[start:end])
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# 团队读取 # 团队读取
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------