Emma / memory_bank /summarize_memory.py
Keyvan1986's picture
Update memory_bank/summarize_memory.py
950efa1 verified
Raw
History Blame Contribute Delete
6.09 kB
import os
import json
import re
from openai import OpenAI
# --- Configuration & Client Setup ---
api_key = os.environ.get("GAPGPT_API_KEY")
base_url = "https://api.gapgpt.app/v1"
if not api_key:
print("⚠️ Warning: 'GAPGPT_API_KEY' not found. Checking for 'OPENAI_API_KEY'...")
api_key = os.environ.get("OPENAI_API_KEY")
if api_key:
print("ℹ️ Using 'OPENAI_API_KEY' instead. Switching base_url to default.")
base_url = None
else:
print("❌ CRITICAL ERROR: No API Key found. LLM calls will fail.")
if base_url:
client = OpenAI(api_key=api_key, base_url=base_url)
else:
client = OpenAI(api_key=api_key)
def get_llm_response(prompt):
"""Helper to call LLM and handle basic errors."""
if not client.api_key:
return "{}"
try:
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": "You are a JSON generator. Output ONLY valid JSON. No markdown, no explanations."},
{"role": "user", "content": prompt}
],
temperature=0.3,
max_tokens=1000
)
content = response.choices[0].message.content
if not content:
print("⚠️ LLM returned empty content.")
return "{}"
return content
except Exception as e:
print(f"❌ Error calling LLM: {e}")
return "{}"
def clean_json_text(text):
"""
Robustly extracts JSON object from text using Regex.
Finds the substring starting with '{' and ending with '}'.
"""
if not text: return ""
# First, try to remove markdown code blocks if present
text = text.replace('```json', '').replace('```', '')
# Use Regex to find the outer-most JSON object
match = re.search(r'\{.*\}', text, re.DOTALL)
if match:
return match.group(0)
return text.strip()
def update_episodic_memory_only(memory_data, user_name):
"""
Analyzes the LATEST session to extract: Topics, Emotions, Insights.
"""
print(f"⚡ Processing Episodic Memory for session end: {user_name}")
if user_name not in memory_data:
return memory_data
user_data = memory_data[user_name]
sessions = user_data.get("sessions", [])
if not sessions:
return memory_data
last_session = sessions[-1]
if last_session.get("analyzed", False):
print(f" Session {last_session.get('session_id')} already analyzed.")
return memory_data
conversation = last_session.get("conversation", [])
if not conversation:
return memory_data
print(" ... ⚡ Generating Episodic Memory (Calling LLM) ...")
conversation_text = json.dumps(conversation, ensure_ascii=False)
prompt = f"""
Analyze this chat session between AI (Emma) and user ({user_name}).
Conversation:
{conversation_text}
Return a JSON object with these exact keys:
{{
"topics": ["list", "of", "topics"],
"emotion": "single string emotion",
"key_insights": ["list", "of", "insights"]
}}
"""
response_text = get_llm_response(prompt)
cleaned_text = clean_json_text(response_text)
try:
analysis_result = json.loads(cleaned_text)
except json.JSONDecodeError as e:
print(f" ⚠️ JSON Error: {e}")
print(f" 📝 Raw LLM Response was: {response_text}") # Debug print
analysis_result = {"topics": [], "emotion": "Unknown", "key_insights": []}
episode_entry = {
"session_id": last_session.get("session_id"),
"date": last_session.get("date"),
"topics": analysis_result.get("topics", []),
"emotion": analysis_result.get("emotion", "Neutral"),
"insights": analysis_result.get("key_insights", [])
}
if "episodic_memory" not in user_data:
user_data["episodic_memory"] = []
user_data["episodic_memory"].append(episode_entry)
last_session["analyzed"] = True
print(f" ✅ Episodic memory successfully updated.")
return memory_data
def update_semantic_memory_only(memory_data, user_name):
"""
Analyzes ALL episodic memories to update the Semantic Profile.
"""
print(f"🧠 Processing Semantic Memory for: {user_name}")
if user_name not in memory_data:
return memory_data
user_data = memory_data[user_name]
episodes = user_data.get("episodic_memory", [])
if not episodes:
print(" No episodic memory found.")
return memory_data
episodes_text = json.dumps(episodes[-10:], ensure_ascii=False)
prompt = f"""
Based on these past session analyses for user '{user_name}', update their profile.
History:
{episodes_text}
Current Profile:
{user_data.get('semantic_memory', 'None')}
Return JSON:
{{
"big_five": {{
"openness": "Low/Medium/High",
"conscientiousness": "Low/Medium/High",
"extraversion": "Low/Medium/High",
"agreeableness": "Low/Medium/High",
"neuroticism": "Low/Medium/High"
}},
"core_values": ["value1", "value2"],
"summary": "Concise personality summary."
}}
"""
response_text = get_llm_response(prompt)
cleaned_text = clean_json_text(response_text)
try:
semantic_result = json.loads(cleaned_text)
if "summary" in semantic_result:
user_data["semantic_profile"] = semantic_result
user_data["semantic_memory"] = semantic_result["summary"]
print(f" ✅ Semantic memory updated.")
else:
print(" ⚠️ Semantic update failed: 'summary' key missing.")
except json.JSONDecodeError as e:
print(f" ⚠️ JSON Error: {e}")
print(f" 📝 Raw LLM Response was: {response_text}")
return memory_data
def summarize_memory(memory_data, user_name):
data = update_episodic_memory_only(memory_data, user_name)
data = update_semantic_memory_only(data, user_name)
return data