Hammad712 commited on
Commit
56efa3b
Β·
1 Parent(s): c1b303d

Update Chat History Logic

Browse files
Files changed (3) hide show
  1. app/page_speed/config.py +31 -13
  2. app/rag/routes.py +29 -9
  3. app/rag/utils.py +19 -18
app/page_speed/config.py CHANGED
@@ -1,39 +1,57 @@
1
  from pydantic_settings import BaseSettings, SettingsConfigDict
2
- from urllib.parse import quote_plus
3
 
4
  class Settings(BaseSettings):
 
 
 
5
  # Google API Keys
 
6
  pagespeed_api_key: str
7
  gemini_api_key: str
8
 
 
9
  # Chat & RAG Configuration
 
10
  groq_api_key: str
11
  vectorstore_base_path: str = "./vectorstores"
12
 
13
- # Hugging Face
 
 
14
  huggingfacehub_api_token: str
15
 
16
- # MongoDB Config
17
- mongo_password: str
 
 
18
  mongo_chat_db: str = "MAAS"
19
  mongo_chat_collection: str = "chat_histories"
20
 
21
- # FastAPI Server Config
 
 
22
  host: str = "0.0.0.0"
23
  port: int = 8000
24
  debug: bool = False
25
 
26
- # MongoDB Atlas URI (Dynamically Constructed)
27
- @property
28
- def mongo_uri(self):
29
- encoded_pwd = quote_plus(self.mongo_password)
30
- return f"mongodb+srv://Hammad:{encoded_pwd}@cluster0.oi9z5ig.mongodb.net/{self.mongo_chat_db}?retryWrites=true&w=majority"
 
 
 
 
31
 
 
 
 
32
  model_config = SettingsConfigDict(
33
  env_file=".env",
34
  env_file_encoding="utf-8",
35
- extra="ignore"
36
  )
37
 
38
- # Global settings instance
39
- settings = Settings()
 
1
  from pydantic_settings import BaseSettings, SettingsConfigDict
 
2
 
3
  class Settings(BaseSettings):
4
+ """Application settings loaded from environment variables."""
5
+
6
+ # ───────────────────────────────────────────────────────────────────────────
7
  # Google API Keys
8
+ # ───────────────────────────────────────────────────────────────────────────
9
  pagespeed_api_key: str
10
  gemini_api_key: str
11
 
12
+ # ───────────────────────────────────────────────────────────────────────────
13
  # Chat & RAG Configuration
14
+ # ───────────────────────────────────────────────────────────────────────────
15
  groq_api_key: str
16
  vectorstore_base_path: str = "./vectorstores"
17
 
18
+ # ───────────────────────────────────────────────────────────────────────────
19
+ # Hugging Face Hub
20
+ # ───────────────────────────────────────────────────────────────────────────
21
  huggingfacehub_api_token: str
22
 
23
+ # ───────────────────────────────────────────────────────────────────────────
24
+ # MongoDB Configuration (Local)
25
+ # ───────────────────────────────────────────────────────────────────────────
26
+ mongo_uri: str = "mongodb://localhost:27017"
27
  mongo_chat_db: str = "MAAS"
28
  mongo_chat_collection: str = "chat_histories"
29
 
30
+ # ───────────────────────────────────────────────────────────────────────────
31
+ # FastAPI Server Configuration
32
+ # ───────────────────────────────────────────────────────────────────────────
33
  host: str = "0.0.0.0"
34
  port: int = 8000
35
  debug: bool = False
36
 
37
+ # ───────────────────────────────────────────────────────────────────────────
38
+ # App Metadata (unchanged)
39
+ # ───────────────────────────────────────────────────────────────────────────
40
+ app_name: str = "PageSpeed Insights Report Generator"
41
+ app_version: str = "1.0.0"
42
+ app_description: str = (
43
+ "Professional API for generating PageSpeed Insights reports "
44
+ "using Google's APIs and Gemini AI"
45
+ )
46
 
47
+ # ───────────────────────────────────────────────────────────────────────────
48
+ # Tell Pydantic to load from .env and ignore extras
49
+ # ───────────────────────────────────────────────────────────────────────────
50
  model_config = SettingsConfigDict(
51
  env_file=".env",
52
  env_file_encoding="utf-8",
53
+ extra="ignore",
54
  )
55
 
56
+ # Single shared Settings instance
57
+ settings = Settings()
app/rag/routes.py CHANGED
@@ -4,6 +4,7 @@ from fastapi import APIRouter, HTTPException
4
 
5
  from .schemas import SetupRequest, ChatRequest, SetupResponse, ChatResponse
6
  from .utils import (
 
7
  text_splitter,
8
  embeddings,
9
  save_vectorstore_to_disk,
@@ -31,6 +32,23 @@ async def setup_rag_session(onboarding_id: str, body: SetupRequest):
31
  onboarding_id, vectorstore_path
32
  )
33
  vs_path = vectorstore_path
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  else:
35
  if not body.documents:
36
  logger.error(
@@ -40,6 +58,15 @@ async def setup_rag_session(onboarding_id: str, body: SetupRequest):
40
  status_code=400,
41
  detail="Vectorstore does not exist; please provide documents to ingest."
42
  )
 
 
 
 
 
 
 
 
 
43
  # Ingest new vectorstore
44
  all_text = "\n\n".join(body.documents)
45
  text_chunks = text_splitter.split_text(all_text)
@@ -48,18 +75,11 @@ async def setup_rag_session(onboarding_id: str, body: SetupRequest):
48
  vs = _FAISS.from_texts(texts=text_chunks, embedding=embeddings)
49
  vs_path = save_vectorstore_to_disk(vs, onboarding_id)
50
  logger.info("Saved FAISS index to %s", vs_path)
51
- upsert_vectorstore_metadata(onboarding_id, vs_path)
52
  logger.info(
53
  "Upserted vectorstore metadata for onboarding_id=%s", onboarding_id
54
  )
55
-
56
- # Create new chat session
57
- chat_id = str(uuid.uuid4())
58
- ChatHistoryManager.create_session(chat_id)
59
- logger.info(
60
- "Created new chat session %s for onboarding_id=%s",
61
- chat_id, onboarding_id
62
- )
63
 
64
  return SetupResponse(
65
  success=True,
 
4
 
5
  from .schemas import SetupRequest, ChatRequest, SetupResponse, ChatResponse
6
  from .utils import (
7
+ get_vectorstore_metadata,
8
  text_splitter,
9
  embeddings,
10
  save_vectorstore_to_disk,
 
32
  onboarding_id, vectorstore_path
33
  )
34
  vs_path = vectorstore_path
35
+
36
+ chat_session = get_vectorstore_metadata(onboarding_id)
37
+
38
+ if chat_session:
39
+ chat_id = str(chat_session["chat_id"])
40
+ logger.info("Using existing chat session id=%s for onboarding_id=%s", chat_id, onboarding_id)
41
+ else:
42
+ logger.warning("No chat session found for onboarding_id=%s", onboarding_id)
43
+
44
+ return SetupResponse(
45
+ success=True,
46
+ message="RAG setup completed with existing vectorstore.",
47
+ onboarding_id=onboarding_id,
48
+ chat_id=chat_id,
49
+ vectorstore_path=vs_path
50
+ )
51
+
52
  else:
53
  if not body.documents:
54
  logger.error(
 
58
  status_code=400,
59
  detail="Vectorstore does not exist; please provide documents to ingest."
60
  )
61
+
62
+ # Create new chat session
63
+ chat_id = str(uuid.uuid4())
64
+ ChatHistoryManager.create_session(chat_id)
65
+ logger.info(
66
+ "Created new chat session %s for onboarding_id=%s",
67
+ chat_id, onboarding_id
68
+ )
69
+
70
  # Ingest new vectorstore
71
  all_text = "\n\n".join(body.documents)
72
  text_chunks = text_splitter.split_text(all_text)
 
75
  vs = _FAISS.from_texts(texts=text_chunks, embedding=embeddings)
76
  vs_path = save_vectorstore_to_disk(vs, onboarding_id)
77
  logger.info("Saved FAISS index to %s", vs_path)
78
+ upsert_vectorstore_metadata(onboarding_id, vs_path, chat_id)
79
  logger.info(
80
  "Upserted vectorstore metadata for onboarding_id=%s", onboarding_id
81
  )
82
+
 
 
 
 
 
 
 
83
 
84
  return SetupResponse(
85
  success=True,
app/rag/utils.py CHANGED
@@ -16,25 +16,25 @@ from app.rag.prompt_library import page_speed_prompt, default_user_prompt,seo_pr
16
  # ──────────────────────────────────────────────────────────────────────────────
17
  # 1. Helper: Path to Store (or Load) a User's FAISS Vectorstore on Disk
18
  # ──────────────────────────────────────────────────────────────────────────────
19
- def get_vectorstore_path(user_id: str) -> str:
20
  """
21
  Ensure a local directory exists for this user's vectorstore.
22
- Returns a path like './vectorstores/{user_id}'.
23
  """
24
  base_dir = settings.vectorstore_base_path
25
- user_dir = os.path.join(base_dir, user_id)
26
  # os.makedirs(user_dir, exist_ok=True)
27
  return user_dir
28
 
29
  # ──────────────────────────────────────────────────────────────────────────────
30
  # 2. Build or Load an Existing FAISS Index for a User
31
  # ──────────────────────────────────────────────────────────────────────────────
32
- def build_or_load_vectorstore(user_id: str) -> FAISS:
33
  """
34
  Attempt to load an existing FAISS index for this user.
35
  If not found on disk, raise a FileNotFoundError.
36
  """
37
- user_dir = get_vectorstore_path(user_id)
38
  faiss_index_path = os.path.join(user_dir, "faiss_index")
39
 
40
  if not os.path.isdir(faiss_index_path):
@@ -50,12 +50,12 @@ def build_or_load_vectorstore(user_id: str) -> FAISS:
50
  # ──────────────────────────────────────────────────────────────────────────────
51
  # 3. Save a FAISS Vectorstore to Disk for a User
52
  # ──────────────────────────────────────────────────────────────────────────────
53
- def save_vectorstore_to_disk(vectorstore: FAISS, user_id: str) -> str:
54
  """
55
  Save the FAISS vectorstore under './vectorstores/{user_id}/faiss_index'.
56
  Returns the path to that saved folder.
57
  """
58
- user_dir = get_vectorstore_path(user_id)
59
  faiss_index_path = os.path.join(user_dir, "faiss_index")
60
  os.makedirs(faiss_index_path, exist_ok=True)
61
  vectorstore.save_local(folder_path=faiss_index_path)
@@ -64,21 +64,22 @@ def save_vectorstore_to_disk(vectorstore: FAISS, user_id: str) -> str:
64
  # ──────────────────────────────────────────────────────────────────────────────
65
  # 4. Upsert or Fetch Vectorstore Metadata in MongoDB
66
  # ──────────────────────────────────────────────────────────────────────────────
67
- def upsert_vectorstore_metadata(user_id: str, vectorstore_path: str) -> None:
68
  """
69
  Insert or update a document mapping user_id β†’ vectorstore_path in MongoDB.
70
  """
71
  vectorstore_meta_coll.update_one(
72
- {"user_id": user_id},
73
- {"$set": {"vectorstore_path": vectorstore_path}},
 
74
  upsert=True
75
  )
76
 
77
- def get_vectorstore_metadata(user_id: str) -> Optional[Dict[str, Any]]:
78
  """
79
- Retrieve the metadata doc (if any) for this user_id.
80
  """
81
- return vectorstore_meta_coll.find_one({"user_id": user_id})
82
 
83
  # ────────────────────────────────────────────────────��─────────────────────────
84
  # 5. Initialize (or Return) a MongoDBChatMessageHistory for chat_id
@@ -95,20 +96,20 @@ def initialize_chat_history(chat_id: str) -> MongoDBChatMessageHistory:
95
  )
96
 
97
  # ──────────────────────────────────────────────────────────────────────────────
98
- # 6. Build a ConversationalRetrievalChain (RAG Chain) for user_id + chat_id
99
  # ──────────────────────────────────────────────────────────────────────────────
100
- def build_rag_chain(user_id: str, chat_id: str, prompt_type: str) -> ConversationalRetrievalChain:
101
  """
102
- - Loads the FAISS index for user_id.
103
  - Creates a retriever (k=3).
104
  - Wraps MongoDBChatMessageHistory in a ConversationBufferMemory.
105
  - Attaches the ChatGroq LLM + user_prompt.
106
  """
107
  # 1. Load FAISS index (or 404 if not found)
108
  try:
109
- faiss_vs = build_or_load_vectorstore(user_id)
110
  except FileNotFoundError:
111
- raise HTTPException(status_code=404, detail="Vectorstore not found for this user. Call /rag/ingest first.")
112
 
113
  retriever = faiss_vs.as_retriever(search_kwargs={"k": 5})
114
 
 
16
  # ──────────────────────────────────────────────────────────────────────────────
17
  # 1. Helper: Path to Store (or Load) a User's FAISS Vectorstore on Disk
18
  # ──────────────────────────────────────────────────────────────────────────────
19
+ def get_vectorstore_path(onboarding_id: str) -> str:
20
  """
21
  Ensure a local directory exists for this user's vectorstore.
22
+ Returns a path like './vectorstores/{onboarding_id}'.
23
  """
24
  base_dir = settings.vectorstore_base_path
25
+ user_dir = os.path.join(base_dir, onboarding_id)
26
  # os.makedirs(user_dir, exist_ok=True)
27
  return user_dir
28
 
29
  # ──────────────────────────────────────────────────────────────────────────────
30
  # 2. Build or Load an Existing FAISS Index for a User
31
  # ──────────────────────────────────────────────────────────────────────────────
32
+ def build_or_load_vectorstore(onboarding_id: str) -> FAISS:
33
  """
34
  Attempt to load an existing FAISS index for this user.
35
  If not found on disk, raise a FileNotFoundError.
36
  """
37
+ user_dir = get_vectorstore_path(onboarding_id)
38
  faiss_index_path = os.path.join(user_dir, "faiss_index")
39
 
40
  if not os.path.isdir(faiss_index_path):
 
50
  # ──────────────────────────────────────────────────────────────────────────────
51
  # 3. Save a FAISS Vectorstore to Disk for a User
52
  # ──────────────────────────────────────────────────────────────────────────────
53
+ def save_vectorstore_to_disk(vectorstore: FAISS, vectorstore_name: str) -> str:
54
  """
55
  Save the FAISS vectorstore under './vectorstores/{user_id}/faiss_index'.
56
  Returns the path to that saved folder.
57
  """
58
+ user_dir = get_vectorstore_path(vectorstore_name)
59
  faiss_index_path = os.path.join(user_dir, "faiss_index")
60
  os.makedirs(faiss_index_path, exist_ok=True)
61
  vectorstore.save_local(folder_path=faiss_index_path)
 
64
  # ──────────────────────────────────────────────────────────────────────────────
65
  # 4. Upsert or Fetch Vectorstore Metadata in MongoDB
66
  # ──────────────────────────────────────────────────────────────────────────────
67
+ def upsert_vectorstore_metadata(onboarding_id: str, vectorstore_path: str, chat_id: str) -> None:
68
  """
69
  Insert or update a document mapping user_id β†’ vectorstore_path in MongoDB.
70
  """
71
  vectorstore_meta_coll.update_one(
72
+ {"onboarding_id": onboarding_id},
73
+ {"$set": {"vectorstore_path": vectorstore_path},
74
+ "$setOnInsert": {"chat_id": chat_id}},
75
  upsert=True
76
  )
77
 
78
+ def get_vectorstore_metadata(onboarding_id: str) -> Optional[Dict[str, Any]]:
79
  """
80
+ Retrieve the metadata doc (if any) for this onboarding_id.
81
  """
82
+ return vectorstore_meta_coll.find_one({"onboarding_id": onboarding_id})
83
 
84
  # ────────────────────────────────────────────────────��─────────────────────────
85
  # 5. Initialize (or Return) a MongoDBChatMessageHistory for chat_id
 
96
  )
97
 
98
  # ──────────────────────────────────────────────────────────────────────────────
99
+ # 6. Build a ConversationalRetrievalChain (RAG Chain) for onboarding_id + chat_id
100
  # ──────────────────────────────────────────────────────────────────────────────
101
+ def build_rag_chain(onboarding_id: str, chat_id: str, prompt_type: str) -> ConversationalRetrievalChain:
102
  """
103
+ - Loads the FAISS index for onboarding_id.
104
  - Creates a retriever (k=3).
105
  - Wraps MongoDBChatMessageHistory in a ConversationBufferMemory.
106
  - Attaches the ChatGroq LLM + user_prompt.
107
  """
108
  # 1. Load FAISS index (or 404 if not found)
109
  try:
110
+ faiss_vs = build_or_load_vectorstore(onboarding_id)
111
  except FileNotFoundError:
112
+ raise HTTPException(status_code=404, detail="Vectorstore not found for this onboarding_id. Call /rag/ingest first.")
113
 
114
  retriever = faiss_vs.as_retriever(search_kwargs={"k": 5})
115