Spaces:
Sleeping
Sleeping
Download classify_chat.py from alesamodio/Socrates_docker: direct link, hf CLI and curl.
- Browser
- Download file 5.42 kB
-
https://huggingface.co/spaces/alesamodio/Socrates_docker/resolve/main/classify_chat.py
- Command line
-
hf download hf://spaces/alesamodio/Socrates_docker/classify_chat.py
-
curl -L -o classify_chat.py https://huggingface.co/spaces/alesamodio/Socrates_docker/resolve/main/classify_chat.py
5.42 kB
| from typing import Optional | |
| import concurrent.futures | |
| from classify_chat_helper import ( | |
| call_core_classification_llm, | |
| call_opinion_trigger_llm, | |
| call_news_formulation_llm, | |
| call_thread_match_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", | |
| core_model: Optional[str] = None, | |
| opinion_model: Optional[str] = None, | |
| secondary_model: Optional[str] = None, | |
| ): | |
| """ | |
| Agent 1 (core: topic/response_mode/user_info/topic_for_tale/needs_news_fetch/needs_coverage_check) | |
| and Agent 2a (opinion-trigger, scoped to the active character) run in parallel every turn. | |
| Agent 2b (news question formulation) and Agent 2c (philosophy-thread matching) are conditional | |
| follow-ups, fired only when Agent 1's own output says they're relevant. | |
| """ | |
| # --- 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 [] | |
| # --- Agent 1 + Agent 2a in parallel --- | |
| with concurrent.futures.ThreadPoolExecutor(max_workers=2) as _ex: | |
| _f_core = _ex.submit( | |
| call_core_classification_llm, query, recent_history, user_info, missing_fields, | |
| character_id=character_id, model=core_model, | |
| ) | |
| _f_opinion = _ex.submit( | |
| call_opinion_trigger_llm, query, recent_history, | |
| character_id=character_id, model=opinion_model, | |
| ) | |
| core = _f_core.result() | |
| opinion = _f_opinion.result() | |
| # Strip empty/blank values — classifier returns all fields, most empty | |
| raw_extracted = core.get("extracted_user_info", {}) | |
| extracted_info = { | |
| k: v for k, v in raw_extracted.items() | |
| if v not in (None, "", [], {}) | |
| } | |
| topic = core.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 = core.get("response_mode", "dialogic") | |
| topic_for_tale = core.get("topic_for_tale", "none") | |
| if topic_for_tale not in ALLOWED_STORY_TOPICS: | |
| topic_for_tale = "none" | |
| needs_news_fetch = bool(core.get("needs_news_fetch", False)) | |
| # --- Agent 2b — conditional: news question formulation --- | |
| news_topic, news_question, news_temporal_context = [], "", "" | |
| if needs_news_fetch: | |
| news = call_news_formulation_llm(query, recent_history, model=secondary_model) | |
| news_topic = news.get("news_topic", []) | |
| news_question = news.get("news_question", "") | |
| news_temporal_context = news.get("news_temporal_context", "") | |
| # --- Agent 2c — conditional: philosophy-thread matching --- | |
| philosophy_thread_index, philosophy_depth_requested = -1, "" | |
| if response_mode == "philosophy_thread": | |
| thread = call_thread_match_llm(query, recent_history, character_id=character_id, model=secondary_model) | |
| philosophy_thread_index = thread.get("philosophy_thread_index", -1) | |
| philosophy_depth_requested = thread.get("philosophy_depth_requested", "") or "" | |
| # --- 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": missing_fields, | |
| "topic_for_tale": topic_for_tale, | |
| "chunks": [], | |
| "needs_news_fetch": needs_news_fetch, | |
| "news_topic": news_topic, | |
| "news_question": news_question, | |
| "news_temporal_context": news_temporal_context, | |
| "socratic_trigger": opinion.get("socratic_trigger", "none") or "none", | |
| "trigger_subtype": opinion.get("trigger_subtype", "") or "", | |
| "socratic_alignment": opinion.get("socratic_alignment", "none") or "none", | |
| "needs_coverage_check": bool(core.get("needs_coverage_check", False)), | |
| "philosophy_thread_index": philosophy_thread_index, | |
| "philosophy_depth_requested": philosophy_depth_requested, | |
| } | |