from classify_chat_helper import call_classification_llm from classify_parameters import TRACKED_FIELDS, ALLOWED_STORY_TOPICS, TOPIC_DESCRIPTIONS from db_user import load_user_info, save_user_info, update_country from db_5_process_session import _load_history _VALID_TOPICS = set(TOPIC_DESCRIPTIONS.keys()) RECENT_HISTORY_LIMIT = 5 def analyze_message(user_id: str, query: str, character_id: str = "socrates"): # --- Load current user_info for this user --- user_info = load_user_info(user_id) profile = user_info.get("user_profile", {}) missing_fields = [f for f in ["name", "living_country", "origin_country"] if not profile.get(f)] # --- Trim history to the most recent turns --- history = _load_history("chat_history_short", user_id) all_messages = [] for session in history.get("sessions", []): all_messages.extend(session.get("messages", [])) recent_history = all_messages[-RECENT_HISTORY_LIMIT:] if all_messages else [] # --- Call LLM for classification + extraction --- analysis = call_classification_llm(query, recent_history, user_info, missing_fields, character_id=character_id) # Strip empty/blank values — classifier returns all fields, most empty raw_extracted = analysis.get("extracted_user_info", {}) extracted_info = { k: v for k, v in raw_extracted.items() if v not in (None, "", [], {}) } relevant_missing = analysis.get("relevant_missing_fields", []) topic = analysis.get("topic", "personal") # Guard: LLM sometimes bleeds response_mode values (e.g. "dialogic") into topic. if topic not in _VALID_TOPICS: topic = "personal" response_mode = analysis.get("response_mode", "dialogic") topic_for_tale = analysis.get("topic_for_tale", "none") if topic_for_tale not in ALLOWED_STORY_TOPICS: topic_for_tale = "none" # --- Update user_info in Supabase only when genuinely new info was extracted --- if extracted_info: _prev_living = profile.get("living_country", "") _prev_origin = profile.get("origin_country", "") profile.update(extracted_info) user_info["user_profile"] = profile save_user_info(user_info, user_id) # Only update countries when the LLM extracted a value that differs from what was stored if "living_country" in extracted_info and extracted_info["living_country"] != _prev_living: update_country("living", extracted_info["living_country"], user_id) if "origin_country" in extracted_info and extracted_info["origin_country"] != _prev_origin: update_country("origin", extracted_info["origin_country"], user_id) return { "topic": topic, "response_mode": response_mode, "user_info": user_info, "relevant_missing": relevant_missing, "topic_for_tale": topic_for_tale, "chunks": [], "needs_news_fetch": analysis.get("needs_news_fetch", False), "news_topic": analysis.get("news_topic", ""), "news_question": analysis.get("news_question", ""), "news_temporal_context": analysis.get("news_temporal_context", ""), "socratic_trigger": analysis.get("socratic_trigger", "none") or "none", "trigger_subtype": analysis.get("trigger_subtype", "") or "", "socratic_alignment": analysis.get("socratic_alignment", "none") or "none", }