Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 36 additions & 1 deletion eval/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,41 @@ def gpt_summarize(dialogs, client):
print("调用 GPT 生成主题摘要...")
return gpt_generate_answer(prompt, messages, client)

def strip_code_fence(text):
"""Return `text` without a surrounding Markdown code fence.

Many current models wrap JSON in a ```json ... ``` fence by default,
even when asked for bare JSON. That is a correct answer, but
json.loads rejects it, so every caller below falls back and loses the
structure it asked for. Text that is not fenced is returned unchanged.

>>> strip_code_fence('[{"theme": "trip"}]')
'[{"theme": "trip"}]'
>>> strip_code_fence('```json\\n[{"theme": "trip"}]\\n```')
'[{"theme": "trip"}]'
>>> strip_code_fence('```\\n{"a": 1}\\n```')
'{"a": 1}'
>>> strip_code_fence(' ```json\\n{"a": 1}\\n``` ')
'{"a": 1}'
>>> strip_code_fence('```json\\n{"a": 1}')
'{"a": 1}'
>>> strip_code_fence('')
''
"""
if not text:
return text
stripped = text.strip()
if not stripped.startswith("```"):
return text
lines = stripped.splitlines()
# Drop the opening fence line, which carries the optional language tag.
lines = lines[1:]
# Drop the closing fence when the model sent one (it may be truncated).
if lines and lines[-1].strip().startswith("```"):
lines = lines[:-1]
return "\n".join(lines).strip()


def gpt_generate_multi_summary(text, client):
"""
调用 LLM 生成多子主题摘要,返回格式示例如下:
Expand All @@ -137,7 +172,7 @@ def gpt_generate_multi_summary(text, client):
response_text = gpt_generate_answer(prompt, messages, client)
import json
try:
summaries = json.loads(response_text)
summaries = json.loads(strip_code_fence(response_text))
except Exception:
summaries = []
return {"input": text, "summaries": summaries}
Expand Down
39 changes: 37 additions & 2 deletions memoryos-chromadb/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,41 @@ def gpt_summarize_dialogs(dialogs, client: OpenAIClient, model="gpt-4o-mini"):
print("Calling LLM to generate topic summary...")
return client.chat_completion(model=model, messages=messages)

def strip_code_fence(text):
"""Return `text` without a surrounding Markdown code fence.

Many current models wrap JSON in a ```json ... ``` fence by default,
even when asked for bare JSON. That is a correct answer, but
json.loads rejects it, so every caller below falls back and loses the
structure it asked for. Text that is not fenced is returned unchanged.

>>> strip_code_fence('[{"theme": "trip"}]')
'[{"theme": "trip"}]'
>>> strip_code_fence('```json\\n[{"theme": "trip"}]\\n```')
'[{"theme": "trip"}]'
>>> strip_code_fence('```\\n{"a": 1}\\n```')
'{"a": 1}'
>>> strip_code_fence(' ```json\\n{"a": 1}\\n``` ')
'{"a": 1}'
>>> strip_code_fence('```json\\n{"a": 1}')
'{"a": 1}'
>>> strip_code_fence('')
''
"""
if not text:
return text
stripped = text.strip()
if not stripped.startswith("```"):
return text
lines = stripped.splitlines()
# Drop the opening fence line, which carries the optional language tag.
lines = lines[1:]
# Drop the closing fence when the model sent one (it may be truncated).
if lines and lines[-1].strip().startswith("```"):
lines = lines[:-1]
return "\n".join(lines).strip()


def gpt_generate_multi_summary(text, client: OpenAIClient, model="gpt-4o-mini"):
messages = [
{"role": "system", "content": prompts.MULTI_SUMMARY_SYSTEM_PROMPT},
Expand All @@ -181,7 +216,7 @@ def gpt_generate_multi_summary(text, client: OpenAIClient, model="gpt-4o-mini"):
print("Calling LLM to generate multi-topic summary...")
response_text = client.chat_completion(model=model, messages=messages)
try:
summaries = json.loads(response_text)
summaries = json.loads(strip_code_fence(response_text))
except json.JSONDecodeError:
print(f"Warning: Could not parse multi-summary JSON: {response_text}")
summaries = []
Expand Down Expand Up @@ -224,7 +259,7 @@ def gpt_user_profile_analysis(conversation_str: str, client: OpenAIClient, model
print("Calling LLM for user profile analysis and update...")
result_text = client.chat_completion(model=model, messages=messages)
try:
return json.loads(result_text)
return json.loads(strip_code_fence(result_text))
except json.JSONDecodeError:
print(f"Warning: User profile analysis did not return valid JSON. Content: {result_text}")
return {"raw_text_profile": result_text}
Expand Down
37 changes: 36 additions & 1 deletion memoryos-mcp/memoryos/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,41 @@ def gpt_summarize_dialogs(dialogs, client: OpenAIClient, model="gpt-4o-mini"):
print("Calling LLM to generate topic summary...")
return client.chat_completion(model=model, messages=messages)

def strip_code_fence(text):
"""Return `text` without a surrounding Markdown code fence.

Many current models wrap JSON in a ```json ... ``` fence by default,
even when asked for bare JSON. That is a correct answer, but
json.loads rejects it, so every caller below falls back and loses the
structure it asked for. Text that is not fenced is returned unchanged.

>>> strip_code_fence('[{"theme": "trip"}]')
'[{"theme": "trip"}]'
>>> strip_code_fence('```json\\n[{"theme": "trip"}]\\n```')
'[{"theme": "trip"}]'
>>> strip_code_fence('```\\n{"a": 1}\\n```')
'{"a": 1}'
>>> strip_code_fence(' ```json\\n{"a": 1}\\n``` ')
'{"a": 1}'
>>> strip_code_fence('```json\\n{"a": 1}')
'{"a": 1}'
>>> strip_code_fence('')
''
"""
if not text:
return text
stripped = text.strip()
if not stripped.startswith("```"):
return text
lines = stripped.splitlines()
# Drop the opening fence line, which carries the optional language tag.
lines = lines[1:]
# Drop the closing fence when the model sent one (it may be truncated).
if lines and lines[-1].strip().startswith("```"):
lines = lines[:-1]
return "\n".join(lines).strip()


def gpt_generate_multi_summary(text, client: OpenAIClient, model="gpt-4o-mini"):
messages = [
{"role": "system", "content": prompts.MULTI_SUMMARY_SYSTEM_PROMPT},
Expand All @@ -256,7 +291,7 @@ def gpt_generate_multi_summary(text, client: OpenAIClient, model="gpt-4o-mini"):
print("Calling LLM to generate multi-topic summary...")
response_text = client.chat_completion(model=model, messages=messages)
try:
summaries = json.loads(response_text)
summaries = json.loads(strip_code_fence(response_text))
except json.JSONDecodeError:
print(f"Warning: Could not parse multi-summary JSON: {response_text}")
summaries = [] # Return empty list or a default structure
Expand Down
37 changes: 36 additions & 1 deletion memoryos-playground/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,41 @@ def gpt_summarize_dialogs(dialogs, client: OpenAIClient, model="gpt-4o-mini"):
print("Calling LLM to generate topic summary...")
return client.chat_completion(model=model, messages=messages)

def strip_code_fence(text):
"""Return `text` without a surrounding Markdown code fence.

Many current models wrap JSON in a ```json ... ``` fence by default,
even when asked for bare JSON. That is a correct answer, but
json.loads rejects it, so every caller below falls back and loses the
structure it asked for. Text that is not fenced is returned unchanged.

>>> strip_code_fence('[{"theme": "trip"}]')
'[{"theme": "trip"}]'
>>> strip_code_fence('```json\\n[{"theme": "trip"}]\\n```')
'[{"theme": "trip"}]'
>>> strip_code_fence('```\\n{"a": 1}\\n```')
'{"a": 1}'
>>> strip_code_fence(' ```json\\n{"a": 1}\\n``` ')
'{"a": 1}'
>>> strip_code_fence('```json\\n{"a": 1}')
'{"a": 1}'
>>> strip_code_fence('')
''
"""
if not text:
return text
stripped = text.strip()
if not stripped.startswith("```"):
return text
lines = stripped.splitlines()
# Drop the opening fence line, which carries the optional language tag.
lines = lines[1:]
# Drop the closing fence when the model sent one (it may be truncated).
if lines and lines[-1].strip().startswith("```"):
lines = lines[:-1]
return "\n".join(lines).strip()


def gpt_generate_multi_summary(text, client: OpenAIClient, model="gpt-4o-mini"):
messages = [
{"role": "system", "content": prompts.MULTI_SUMMARY_SYSTEM_PROMPT},
Expand All @@ -256,7 +291,7 @@ def gpt_generate_multi_summary(text, client: OpenAIClient, model="gpt-4o-mini"):
print("Calling LLM to generate multi-topic summary...")
response_text = client.chat_completion(model=model, messages=messages)
try:
summaries = json.loads(response_text)
summaries = json.loads(strip_code_fence(response_text))
except json.JSONDecodeError:
print(f"Warning: Could not parse multi-summary JSON: {response_text}")
summaries = [] # Return empty list or a default structure
Expand Down
37 changes: 36 additions & 1 deletion memoryos-pypi/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,41 @@ def gpt_summarize_dialogs(dialogs, client: OpenAIClient, model="gpt-4o-mini"):
print("Calling LLM to generate topic summary...")
return client.chat_completion(model=model, messages=messages)

def strip_code_fence(text):
"""Return `text` without a surrounding Markdown code fence.

Many current models wrap JSON in a ```json ... ``` fence by default,
even when asked for bare JSON. That is a correct answer, but
json.loads rejects it, so every caller below falls back and loses the
structure it asked for. Text that is not fenced is returned unchanged.

>>> strip_code_fence('[{"theme": "trip"}]')
'[{"theme": "trip"}]'
>>> strip_code_fence('```json\\n[{"theme": "trip"}]\\n```')
'[{"theme": "trip"}]'
>>> strip_code_fence('```\\n{"a": 1}\\n```')
'{"a": 1}'
>>> strip_code_fence(' ```json\\n{"a": 1}\\n``` ')
'{"a": 1}'
>>> strip_code_fence('```json\\n{"a": 1}')
'{"a": 1}'
>>> strip_code_fence('')
''
"""
if not text:
return text
stripped = text.strip()
if not stripped.startswith("```"):
return text
lines = stripped.splitlines()
# Drop the opening fence line, which carries the optional language tag.
lines = lines[1:]
# Drop the closing fence when the model sent one (it may be truncated).
if lines and lines[-1].strip().startswith("```"):
lines = lines[:-1]
return "\n".join(lines).strip()


def gpt_generate_multi_summary(text, client: OpenAIClient, model="gpt-4o-mini"):
messages = [
{"role": "system", "content": prompts.MULTI_SUMMARY_SYSTEM_PROMPT},
Expand All @@ -256,7 +291,7 @@ def gpt_generate_multi_summary(text, client: OpenAIClient, model="gpt-4o-mini"):
print("Calling LLM to generate multi-topic summary...")
response_text = client.chat_completion(model=model, messages=messages)
try:
summaries = json.loads(response_text)
summaries = json.loads(strip_code_fence(response_text))
except json.JSONDecodeError:
print(f"Warning: Could not parse multi-summary JSON: {response_text}")
summaries = [] # Return empty list or a default structure
Expand Down