This commit is contained in:
bridge
2025-10-08 23:46:51 +08:00
parent ad29011193
commit 0bcf0cbef1
2 changed files with 97 additions and 12 deletions

View File

@@ -412,9 +412,9 @@ class Avatar:
# 宗门信息
sect_name = self.get_sect_str()
if self.sect is not None:
sect_info = f"宗门信息:{sect_name},风格:{self.sect.member_act_style}"
else:
sect_info = f"宗门信息:{sect_name}"
sect_info = f"{sect_name},风格:{self.sect.member_act_style},驻地:{self.sect.headquarter.name}"
else: # 散修
sect_info = sect_name
# 历史事件摘要
if self.history_events:

View File

@@ -61,18 +61,103 @@ async def call_llm_async(prompt: str, mode="normal") -> str:
result = await asyncio.to_thread(call_llm, prompt, mode)
return result
def _extract_code_blocks(text: str):
"""
提取所有markdown代码块返回 (lang, content) 列表。
"""
pattern = re.compile(r"```([^\n`]*)\n([\s\S]*?)```", re.DOTALL)
blocks = []
for lang, content in pattern.findall(text):
blocks.append((lang.strip().lower(), content.strip()))
return blocks
def _find_first_balanced_json_object(text: str):
"""
在整段文本中扫描并返回首个平衡的花括号 {...} 片段(忽略字符串中的括号)。
找到则返回子串否则返回None。
"""
depth = 0
start_index = None
in_string = False
string_char = ''
escape = False
for idx, ch in enumerate(text):
if in_string:
if escape:
escape = False
continue
if ch == '\\':
escape = True
continue
if ch == string_char:
in_string = False
continue
if ch in ('"', "'"):
in_string = True
string_char = ch
continue
if ch == '{':
if depth == 0:
start_index = idx
depth += 1
continue
if ch == '}':
if depth > 0:
depth -= 1
if depth == 0 and start_index is not None:
return text[start_index:idx + 1]
return None
def parse_llm_response(res: str) -> dict:
"""
解析LLM返回的结果支持多种格式
仅针对 JSON 的稳健解析:
1) 优先解析 ```json/json5``` 或未标注语言的代码块
2) 自由文本中定位首个平衡的 {...}
3) 整体 json5 兜底
最终返回字典;否则抛错。
"""
res = res.strip()
# 提取markdown代码块中的JSON
json_match = re.search(r'```(?:json)?\s*(\{.*?\})\s*```', res, re.DOTALL)
if json_match:
res = json_match.group(1)
return json5.loads(res)
res = (res or '').strip()
if not res:
return {}
# 1) 优先解析代码块(仅 json/json5/未标注语言)
for lang, block in _extract_code_blocks(res):
if lang and lang not in ("json", "json5"):
continue
# 先在块内找平衡对象
span = _find_first_balanced_json_object(block)
candidates = [span] if span else [block]
for cand in candidates:
if not cand:
continue
try:
obj = json5.loads(cand)
if isinstance(obj, dict):
return obj
except Exception:
continue
# 2) 扫描全文首个平衡的JSON对象
json_span = _find_first_balanced_json_object(res)
if json_span:
try:
obj = json5.loads(json_span)
if isinstance(obj, dict):
return obj
except Exception:
pass
# 3) 整体 json5 兜底
try:
obj = json5.loads(res)
if isinstance(obj, dict):
return obj
except Exception:
pass
raise ValueError("无法从LLM响应中解析出有效的JSON字典对象")
def get_prompt_and_call_llm(template_path: Path, infos: dict, mode="normal") -> str:
"""