alesamodio commited on
Commit
dc3dc12
Β·
1 Parent(s): ce74a97

update on topic_for_story #1

Browse files
Agent_Chat_Classification.py CHANGED
@@ -1,5 +1,5 @@
1
  from Agent_Chat_Classification_Helper import call_classification_llm
2
- from Classification_parameters import TRACKED_FIELDS
3
  from supabase_ie import load_user_info, save_user_info, update_country
4
  from db_5_process_session import _load_history
5
 
@@ -28,6 +28,9 @@ def analyze_message(user_id: str, query: str):
28
  relevant_missing = analysis.get("relevant_missing_fields", [])
29
  topic = analysis.get("topic", "personal")
30
  response_mode = analysis.get("response_mode", "dialogic")
 
 
 
31
 
32
  print(f"[DEBUG][CLASSIFICATION_RAW] analysis={analysis}")
33
  # --- Update user_info in Supabase if new info found ---
@@ -56,6 +59,7 @@ def analyze_message(user_id: str, query: str):
56
  "response_mode": response_mode,
57
  "user_info": user_info,
58
  "relevant_missing": relevant_missing,
 
59
  "chunks": [], # retrieval results can be appended later
60
  "needs_news_fetch": analysis.get("needs_news_fetch", False),
61
  "news_topic": analysis.get("news_topic", ""),
 
1
  from Agent_Chat_Classification_Helper import call_classification_llm
2
+ from Classification_parameters import TRACKED_FIELDS, ALLOWED_STORY_TOPICS
3
  from supabase_ie import load_user_info, save_user_info, update_country
4
  from db_5_process_session import _load_history
5
 
 
28
  relevant_missing = analysis.get("relevant_missing_fields", [])
29
  topic = analysis.get("topic", "personal")
30
  response_mode = analysis.get("response_mode", "dialogic")
31
+ topic_for_story = analysis.get("topic_for_story", "none")
32
+ if topic_for_story not in ALLOWED_STORY_TOPICS:
33
+ topic_for_story = "none"
34
 
35
  print(f"[DEBUG][CLASSIFICATION_RAW] analysis={analysis}")
36
  # --- Update user_info in Supabase if new info found ---
 
59
  "response_mode": response_mode,
60
  "user_info": user_info,
61
  "relevant_missing": relevant_missing,
62
+ "topic_for_story": topic_for_story,
63
  "chunks": [], # retrieval results can be appended later
64
  "needs_news_fetch": analysis.get("needs_news_fetch", False),
65
  "news_topic": analysis.get("news_topic", ""),
Agent_Chat_Classification_Helper.py CHANGED
@@ -4,7 +4,7 @@ from config import OPENAI_CHAT_MODEL
4
  from openai import OpenAI
5
  import json
6
  from supabase_ie import load_user_info
7
- from Classification_parameters import TOPIC_DESCRIPTIONS, RESPONSE_MODE_DESCRIPTIONS, TRACKED_FIELDS, FIELD_DESCRIPTIONS
8
  client = OpenAI()
9
 
10
 
@@ -35,6 +35,7 @@ def call_classification_llm(query: str, recent_history: list, user_info: dict, m
35
  "topic": "",
36
  "response_mode": "",
37
  "emotion": "",
 
38
  "needs_news_fetch": False,
39
  "news_topic": [],
40
  "news_question": ""
@@ -63,6 +64,12 @@ def call_classification_llm(query: str, recent_history: list, user_info: dict, m
63
  * topic: one of {list(TOPIC_DESCRIPTIONS.keys())}
64
  * response_mode: one of {list(RESPONSE_MODE_DESCRIPTIONS.keys())}
65
  * emotion: one of ["curious","happy","sad","angry","neutral"]
 
 
 
 
 
 
66
 
67
  - needs_news_fetch:
68
  * true if the user is clearly asking for news, current events, or external information lookup.
@@ -106,71 +113,10 @@ def call_classification_llm(query: str, recent_history: list, user_info: dict, m
106
  "topic": "",
107
  "response_mode": "",
108
  "emotion": "",
 
109
  "needs_news_fetch": False,
110
  "news_topic": [],
111
  "news_question": ""
112
  }
113
 
114
 
115
- # def summarize_user_info(user_id: str) -> str:
116
- # """Fetch user profile from Supabase, create a natural language summary, and return it as a string."""
117
-
118
- # data = load_user_info(user_id)
119
- # profile = data.get("user_profile", {})
120
-
121
- # parts = []
122
-
123
- # # Location
124
- # if profile.get("living_country"):
125
- # parts.append(f"lives in {profile['living_country']}")
126
- # if profile.get("origin_country"):
127
- # parts.append(f"was born in {profile['origin_country']}")
128
-
129
- # # Kids
130
- # kids = profile.get("kids")
131
- # if kids:
132
- # try:
133
- # if isinstance(kids, str): # sometimes JSONB comes back as string
134
- # kids = json.loads(kids)
135
- # kids_list = [f"{k.get('name','?')} ({k.get('age','?')} yrs)" for k in kids if isinstance(k, dict)]
136
- # if kids_list:
137
- # parts.append("has kids: " + ", ".join(kids_list))
138
- # except Exception as e:
139
- # print("⚠️ Could not parse kids:", kids, e)
140
-
141
- # # Arrays: hobbies, interests, languages, sports
142
- # for field, label in [
143
- # ("hobbies", "enjoys"),
144
- # ("interests", "is interested in"),
145
- # ("sports_played", "plays"),
146
- # ("sports_watched", "watches"),
147
- # ("language_spoken", "speaks")
148
- # ]:
149
- # values = profile.get(field)
150
- # if values:
151
- # if isinstance(values, str):
152
- # values = [values]
153
- # if isinstance(values, list) and values:
154
- # parts.append(f"{label} " + ", ".join(values))
155
-
156
- # # Misc single fields
157
- # if profile.get("profession"):
158
- # parts.append(f"works as {profile['profession']}")
159
- # if profile.get("favorite_team"):
160
- # parts.append(f"supports {profile['favorite_team']}")
161
- # if profile.get("favorite_food"):
162
- # parts.append(f"likes {profile['favorite_food']}")
163
- # if profile.get("favorite_book"):
164
- # parts.append(f"favorite book is {profile['favorite_book']}")
165
- # if profile.get("favorite_movie"):
166
- # parts.append(f"favorite movie is {profile['favorite_movie']}")
167
- # if profile.get("pets"):
168
- # parts.append(f"has pets: {profile['pets']}")
169
- # if profile.get("education"):
170
- # parts.append(f"studied {profile['education']}")
171
-
172
- # # Final summary
173
- # summary = "The user " + "; ".join(parts) + "." if parts else "No profile information available."
174
- # print(f"βœ… User profile summary generated:\n{summary}")
175
-
176
- # return summary
 
4
  from openai import OpenAI
5
  import json
6
  from supabase_ie import load_user_info
7
+ from Classification_parameters import TOPIC_DESCRIPTIONS, RESPONSE_MODE_DESCRIPTIONS, TRACKED_FIELDS, FIELD_DESCRIPTIONS, ALLOWED_STORY_TOPICS
8
  client = OpenAI()
9
 
10
 
 
35
  "topic": "",
36
  "response_mode": "",
37
  "emotion": "",
38
+ "topic_for_story": "",
39
  "needs_news_fetch": False,
40
  "news_topic": [],
41
  "news_question": ""
 
64
  * topic: one of {list(TOPIC_DESCRIPTIONS.keys())}
65
  * response_mode: one of {list(RESPONSE_MODE_DESCRIPTIONS.keys())}
66
  * emotion: one of ["curious","happy","sad","angry","neutral"]
67
+
68
+ - topic_for_story:
69
+ * Choose exactly one label from this list (closed set):
70
+ [{allowed_str}]
71
+ * Return "none" if no fitting label is clearly supported.
72
+ * Never invent new labels.
73
 
74
  - needs_news_fetch:
75
  * true if the user is clearly asking for news, current events, or external information lookup.
 
113
  "topic": "",
114
  "response_mode": "",
115
  "emotion": "",
116
+ "topic_for_story": "none",
117
  "needs_news_fetch": False,
118
  "news_topic": [],
119
  "news_question": ""
120
  }
121
 
122
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Classification_parameters.py CHANGED
@@ -1,6 +1,11 @@
1
  # ==============================
2
  # Descriptions for Classification
3
  # ==============================
 
 
 
 
 
4
  TRACKED_FIELDS = [
5
  "name", "living_country", "origin_country","living_place",
6
  "origin_place","number_of_brothers_and_sisters","kids",
 
1
  # ==============================
2
  # Descriptions for Classification
3
  # ==============================
4
+ ALLOWED_STORY_TOPICS = [
5
+ "fortune","confidence","mental_strength","bullying","fear_phobias",
6
+ "friendship","love","sex","meaning_of_life","justice_fairness","none"
7
+ ]
8
+
9
  TRACKED_FIELDS = [
10
  "name", "living_country", "origin_country","living_place",
11
  "origin_place","number_of_brothers_and_sisters","kids",
Prompt_building.py CHANGED
@@ -180,6 +180,7 @@ def build_socratic_prompt(
180
  style_examples_path: str = "style_examples.json",
181
  relevant_missing: list = None,
182
  topic: str = None,
 
183
  response_mode: str = None,
184
  emotion: dict = None,
185
  ) -> str:
 
180
  style_examples_path: str = "style_examples.json",
181
  relevant_missing: list = None,
182
  topic: str = None,
183
+ topic_for_story: str = None,
184
  response_mode: str = None,
185
  emotion: dict = None,
186
  ) -> str:
Retrieve.py CHANGED
@@ -3,14 +3,15 @@
3
  import os
4
  import json
5
  import numpy as np
6
- from typing import List, Dict
 
7
  from langchain_community.vectorstores import FAISS
8
  import streamlit as st
9
  import numpy as np
10
  #from db_paths import (PERSONAL_INFO_CHUNKS_PATH,CHAT_HISTORY_CHUNKS_PATH)
11
  import json
12
  from supabase_ie import load_user_info, load_history_for_display, download_faiss_from_supabase
13
-
14
 
15
  #used in embed_query
16
  def normalize(v):
@@ -193,3 +194,41 @@ def compute_metadata_boost(metadata: Dict, query: str, filter_keywords: List[str
193
  boost += weight_filter
194
  return boost
195
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  import os
4
  import json
5
  import numpy as np
6
+ from typing import List, Dict, Optional, Any
7
+ import requests
8
  from langchain_community.vectorstores import FAISS
9
  import streamlit as st
10
  import numpy as np
11
  #from db_paths import (PERSONAL_INFO_CHUNKS_PATH,CHAT_HISTORY_CHUNKS_PATH)
12
  import json
13
  from supabase_ie import load_user_info, load_history_for_display, download_faiss_from_supabase
14
+ from config import SUPABASE_URL, SUPABASE_HEADERS
15
 
16
  #used in embed_query
17
  def normalize(v):
 
194
  boost += weight_filter
195
  return boost
196
 
197
+ PERSONAL_BUCKET = {"personal", "advice"}
198
+
199
+ def get_story_from_supabase(
200
+ user_id: str,
201
+ username: str,
202
+ conversation_type: str,
203
+ topic_for_story: str | None,
204
+ ) -> dict | None:
205
+ """
206
+ If conversation_type is personal/advice and topic_for_story is set,
207
+ call a Supabase RPC that:
208
+ - selects a story with your rules (unseen first; else seen<=1 and >90d ago),
209
+ - logs usage,
210
+ - returns a compact JSON payload for the prompt builder.
211
+
212
+ Returns None if no suitable story.
213
+ """
214
+ if conversation_type not in PERSONAL_BUCKET:
215
+ return None
216
+ if not topic_for_story or topic_for_story == "none":
217
+ return None
218
+
219
+ fn = "pick_and_log_story_with_history_rpc"
220
+ payload = {
221
+ "p_user_id": user_id,
222
+ "p_topic": topic_for_story,
223
+ }
224
+
225
+ url = f"{SUPABASE_URL}/rest/v1/rpc/{fn}"
226
+ r = requests.post(url, headers=SUPABASE_HEADERS, json=payload, timeout=20)
227
+
228
+ if r.status_code == 404 or not r.text or r.text == "null":
229
+ return None
230
+ r.raise_for_status()
231
+ story = r.json()
232
+ return story
233
+
234
+ #return r.json()
app_nn.py CHANGED
@@ -28,7 +28,7 @@ from Agent_Emotional_Evaluation import analyze_emotions_from_history
28
  from Agent_Chat_Classification import analyze_message
29
  #from Agent_Chat_Classification_Helper import load_user_info
30
 
31
- from Retrieve import retrieve_all_chunks
32
  from Prompt_building import TOPIC_TO_DBS
33
  from ask_llm_final_prompt import ask_socrates
34
 
@@ -207,12 +207,20 @@ def run_chat_app(user_id: str, username:str, profile: Dict[str, Any],ui_lang:str
207
  topic_to_dbs=TOPIC_TO_DBS,
208
  )
209
 
 
 
 
 
 
 
 
210
  # ---- Compose final answer ----
211
  final_reply_en = ask_socrates(
212
  user_input=user_msg_en,
213
  retrieved_chunks=chunks,
214
  relevant_missing=analysis.get("relevant_missing"),
215
  topic=analysis.get("topic"),
 
216
  response_mode=analysis.get("response_mode"),
217
  emotion=emotion_result,
218
  user_id=user_id,
 
28
  from Agent_Chat_Classification import analyze_message
29
  #from Agent_Chat_Classification_Helper import load_user_info
30
 
31
+ from Retrieve import retrieve_all_chunks, get_story_from_supabase
32
  from Prompt_building import TOPIC_TO_DBS
33
  from ask_llm_final_prompt import ask_socrates
34
 
 
207
  topic_to_dbs=TOPIC_TO_DBS,
208
  )
209
 
210
+ socratic_story = get_story_from_supabase(
211
+ user_id=user_id,
212
+ username=username,
213
+ topic_for_story=analysis.get("topic_for_story"),
214
+ conversation_type=analysis.get("topic"),
215
+ )
216
+
217
  # ---- Compose final answer ----
218
  final_reply_en = ask_socrates(
219
  user_input=user_msg_en,
220
  retrieved_chunks=chunks,
221
  relevant_missing=analysis.get("relevant_missing"),
222
  topic=analysis.get("topic"),
223
+ topic_for_story=analysis.get("topic_for_story"),
224
  response_mode=analysis.get("response_mode"),
225
  emotion=emotion_result,
226
  user_id=user_id,
ask_llm_final_prompt.py CHANGED
@@ -19,6 +19,7 @@ def ask_socrates(
19
  model=OPENAI_CHAT_MODEL,
20
  relevant_missing=None,
21
  topic=None,
 
22
  response_mode=None,
23
  emotion=None
24
  ):
@@ -29,6 +30,7 @@ def ask_socrates(
29
  user_id=user_id,
30
  relevant_missing=relevant_missing,
31
  topic=topic,
 
32
  response_mode=response_mode,
33
  emotion=emotion
34
  )
 
19
  model=OPENAI_CHAT_MODEL,
20
  relevant_missing=None,
21
  topic=None,
22
+ topic_for_story=None,
23
  response_mode=None,
24
  emotion=None
25
  ):
 
30
  user_id=user_id,
31
  relevant_missing=relevant_missing,
32
  topic=topic,
33
+ topic_for_story=topic_for_story,
34
  response_mode=response_mode,
35
  emotion=emotion
36
  )
config.py CHANGED
@@ -28,6 +28,7 @@ HF_EMBEDDING_MODEL = _get("HF_EMBEDDING_MODEL", required=False, default="s
28
  GNEWS_KEY = _get("GNEWS_KEY", required=False, default="")
29
 
30
 
 
31
  # ── Models ─────────────────────────────────────────────────────────────────────
32
  OPENAI_CHAT_MODEL = os.getenv("OPENAI_CHAT_MODEL", "gpt-4.1-mini")
33
  OPENAI_CLASSIFIER_MODEL = os.getenv("OPENAI_CLASSIFIER_MODEL", "gpt-4.1-mini")
@@ -77,3 +78,10 @@ def get_username() -> str | None:
77
  st.session_state.get("username")
78
  or username_from_email(st.session_state.get("email"))
79
  )
 
 
 
 
 
 
 
 
28
  GNEWS_KEY = _get("GNEWS_KEY", required=False, default="")
29
 
30
 
31
+
32
  # ── Models ─────────────────────────────────────────────────────────────────────
33
  OPENAI_CHAT_MODEL = os.getenv("OPENAI_CHAT_MODEL", "gpt-4.1-mini")
34
  OPENAI_CLASSIFIER_MODEL = os.getenv("OPENAI_CLASSIFIER_MODEL", "gpt-4.1-mini")
 
78
  st.session_state.get("username")
79
  or username_from_email(st.session_state.get("email"))
80
  )
81
+
82
+ # Reusable headers for PostgREST / RPC calls
83
+ SUPABASE_HEADERS = {
84
+ "apikey": SUPABASE_SERVICE_KEY,
85
+ "Authorization": f"Bearer {SUPABASE_SERVICE_KEY}",
86
+ "Content-Type": "application/json",
87
+ }