mothy-08 commited on
Commit
1d1b426
·
1 Parent(s): aaa4ec9

Added a frontend/Chrome Extension

Browse files
README.md CHANGED
@@ -1,4 +1,4 @@
1
- # 🌐 RAGBot
2
 
3
  A cloud-native, multi-tenant AI chatbot that instantly learns the content of any website and answers questions in real-time. Built for the Cloud Computing final project.
4
 
@@ -26,14 +26,17 @@ A cloud-native, multi-tenant AI chatbot that instantly learns the content of any
26
  ## 📂 Project Structure
27
 
28
  ```bash
29
- ├── server.py # Main FastAPI entry point
30
- ├── crawler.py # Logic for sitemap parsing & scraping
31
- ├── vectorstore.py # Pinecone batching & management
32
- ├── config.py # Environment & Logging setup
33
- ├── utils.py # Security & URL validation
34
- ├── schemas.py # Pydantic data models
35
- ├── extension/ # Chrome Extension Source Code
 
 
 
36
  │ ├── manifest.json
37
  │ ├── popup.html
38
  │ └── popup.js
39
- └── requirements.txt # Python Dependencies
 
1
+ # 🤖 RAGBot
2
 
3
  A cloud-native, multi-tenant AI chatbot that instantly learns the content of any website and answers questions in real-time. Built for the Cloud Computing final project.
4
 
 
26
  ## 📂 Project Structure
27
 
28
  ```bash
29
+ ragbot/
30
+ ├── api/ # 🐍 Backend Logic
31
+ ├── server.py # Main FastAPI entry point
32
+ ├── crawler.py # Logic for sitemap parsing & scraping
33
+ ├── vectorstore.py # Pinecone batching & management
34
+ ├── config.py # Environment & Logging setup
35
+ ├── utils.py # Security & URL validation
36
+ │ ├── schemas.py # Pydantic data models
37
+ │ └── requirements.txt # Python Dependencies
38
+ ├── extension/ # 🧩 Frontend Client
39
  │ ├── manifest.json
40
  │ ├── popup.html
41
  │ └── popup.js
42
+ └── README.md # Documentation
api/config.py CHANGED
@@ -2,7 +2,7 @@ import os
2
  import sys
3
  import logging
4
  from dotenv import load_dotenv
5
- from vectorstore import VectorStoreManager
6
  import google.generativeai as genai
7
 
8
  logging.basicConfig(
@@ -38,6 +38,7 @@ try:
38
  genai.configure(api_key=GOOGLE_API_KEY) # type: ignore
39
  flash = genai.GenerativeModel("gemini-2.0-flash") # type: ignore
40
 
 
41
  except Exception as e:
42
  logger.critical(f"Startup Failure: {e}")
43
  sys.exit(1)
 
2
  import sys
3
  import logging
4
  from dotenv import load_dotenv
5
+ from api.vectorstore import VectorStoreManager
6
  import google.generativeai as genai
7
 
8
  logging.basicConfig(
 
38
  genai.configure(api_key=GOOGLE_API_KEY) # type: ignore
39
  flash = genai.GenerativeModel("gemini-2.0-flash") # type: ignore
40
 
41
+ logger.info("✅ System initialized: Pinecone & Gemini ready.")
42
  except Exception as e:
43
  logger.critical(f"Startup Failure: {e}")
44
  sys.exit(1)
api/crawler.py CHANGED
@@ -1,7 +1,7 @@
1
  import time
2
  import trafilatura
3
  from trafilatura.sitemaps import sitemap_search
4
- from utils import logger, is_valid_url
5
 
6
 
7
  def smart_chunk(text: str, chunk_size=500) -> list[str]:
 
1
  import time
2
  import trafilatura
3
  from trafilatura.sitemaps import sitemap_search
4
+ from api.utils import logger, is_valid_url
5
 
6
 
7
  def smart_chunk(text: str, chunk_size=500) -> list[str]:
api/server.py CHANGED
@@ -1,10 +1,10 @@
1
  from fastapi import FastAPI, BackgroundTasks, HTTPException
2
  from fastapi.middleware.cors import CORSMiddleware
3
 
4
- from utils import get_namespace_id, logger
5
- from crawler import crawl_website
6
- from schemas import ChatRequest, IngestRequest
7
- from config import vs, flash
8
 
9
  app = FastAPI(title="RAG Chatbot API", version="1.0")
10
 
 
1
  from fastapi import FastAPI, BackgroundTasks, HTTPException
2
  from fastapi.middleware.cors import CORSMiddleware
3
 
4
+ from api.utils import get_namespace_id, logger
5
+ from api.crawler import crawl_website
6
+ from api.schemas import ChatRequest, IngestRequest
7
+ from api.config import vs, flash
8
 
9
  app = FastAPI(title="RAG Chatbot API", version="1.0")
10
 
api/vectorstore.py CHANGED
@@ -2,7 +2,7 @@ from typing import Any
2
  import uuid
3
  from pinecone import Pinecone, ServerlessSpec
4
  from sentence_transformers import SentenceTransformer
5
- from utils import logger
6
 
7
 
8
  class VectorStoreManager:
 
2
  import uuid
3
  from pinecone import Pinecone, ServerlessSpec
4
  from sentence_transformers import SentenceTransformer
5
+ from api.utils import logger
6
 
7
 
8
  class VectorStoreManager:
chrome-extension/.DS_Store ADDED
Binary file (6.15 kB). View file
 
chrome-extension/icons/icon128.png ADDED
chrome-extension/icons/icon16.png ADDED
chrome-extension/icons/icon32.png ADDED
chrome-extension/icons/icon48.png ADDED
chrome-extension/manifest.json ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "Ragbot",
3
+ "description": "Chat with any website using RAG.",
4
+ "version": "1.0",
5
+ "manifest_version": 3,
6
+ "action": {
7
+ "default_popup": "popup.html",
8
+ "default_icon": {
9
+ "16": "icons/icon16.png",
10
+ "48": "icons/icon48.png",
11
+ "128": "icons/icon128.png"
12
+ }
13
+ },
14
+ "icons": {
15
+ "16": "icons/icon16.png",
16
+ "32": "icons/icon32.png",
17
+ "48": "icons/icon48.png",
18
+ "128": "icons/icon128.png"
19
+ },
20
+ "permissions": ["activeTab", "scripting"],
21
+ "host_permissions": ["http://localhost:8000/*"]
22
+ }
chrome-extension/popup.css ADDED
@@ -0,0 +1,186 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ * {
2
+ box-sizing: border-box;
3
+ }
4
+
5
+ body {
6
+ width: 360px;
7
+ height: 500px;
8
+ font-family:
9
+ -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial,
10
+ sans-serif;
11
+ margin: 0;
12
+ padding: 0;
13
+ background-color: #ffffff;
14
+ color: #1a1a1a;
15
+ display: flex;
16
+ flex-direction: column;
17
+ }
18
+
19
+ header {
20
+ padding: 15px;
21
+ border-bottom: 1px solid #eaeaea;
22
+ display: flex;
23
+ align-items: center;
24
+ justify-content: space-between;
25
+ background: #fafafa;
26
+ }
27
+
28
+ h1 {
29
+ margin: 0;
30
+ font-size: 16px;
31
+ font-weight: 600;
32
+ }
33
+
34
+ .badge {
35
+ font-size: 10px;
36
+ padding: 2px 6px;
37
+ border-radius: 4px;
38
+ background: #eee;
39
+ color: #666;
40
+ }
41
+
42
+ main {
43
+ flex: 1;
44
+ overflow: hidden;
45
+ display: flex;
46
+ flex-direction: column;
47
+ }
48
+
49
+ .view {
50
+ padding: 20px;
51
+ flex: 1;
52
+ display: flex;
53
+ flex-direction: column;
54
+ align-items: center;
55
+ justify-content: center;
56
+ text-align: center;
57
+ }
58
+
59
+ .hidden {
60
+ display: none !important;
61
+ }
62
+
63
+ .icon-large {
64
+ font-size: 48px;
65
+ margin-bottom: 15px;
66
+ }
67
+
68
+ h2 {
69
+ margin: 0 0 10px 0;
70
+ font-size: 18px;
71
+ }
72
+
73
+ p {
74
+ margin: 0 0 20px 0;
75
+ font-size: 13px;
76
+ color: #666;
77
+ line-height: 1.4;
78
+ }
79
+
80
+ button {
81
+ background: #000;
82
+ color: #fff;
83
+ border: none;
84
+ padding: 10px 20px;
85
+ border-radius: 6px;
86
+ font-size: 14px;
87
+ font-weight: 500;
88
+ cursor: pointer;
89
+ transition: opacity 0.2s;
90
+ width: 100%;
91
+ }
92
+
93
+ button:hover {
94
+ opacity: 0.8;
95
+ }
96
+
97
+ button:disabled {
98
+ background: #ccc;
99
+ cursor: not-allowed;
100
+ }
101
+
102
+ #chat-view {
103
+ justify-content: flex-start;
104
+ padding: 0;
105
+ }
106
+
107
+ #messages {
108
+ flex: 1;
109
+ width: 100%;
110
+ overflow-y: auto;
111
+ padding: 15px;
112
+ display: flex;
113
+ flex-direction: column;
114
+ gap: 10px;
115
+ }
116
+
117
+ .msg {
118
+ max-width: 85%;
119
+ padding: 8px 12px;
120
+ border-radius: 12px;
121
+ font-size: 13px;
122
+ line-height: 1.4;
123
+ word-wrap: break-word;
124
+ }
125
+ .msg.user {
126
+ align-self: flex-end;
127
+ background: #000;
128
+ color: #fff;
129
+ border-bottom-right-radius: 2px;
130
+ }
131
+ .msg.bot {
132
+ align-self: flex-start;
133
+ background: #f0f0f0;
134
+ color: #000;
135
+ border-bottom-left-radius: 2px;
136
+ }
137
+ .msg.error {
138
+ align-self: center;
139
+ background: #ffebee;
140
+ color: #c62828;
141
+ font-size: 12px;
142
+ }
143
+
144
+ .input-area {
145
+ width: 100%;
146
+ padding: 15px;
147
+ border-top: 1px solid #eaeaea;
148
+ display: flex;
149
+ gap: 10px;
150
+ background: #fff;
151
+ }
152
+
153
+ input {
154
+ flex: 1;
155
+ padding: 10px;
156
+ border: 1px solid #ddd;
157
+ border-radius: 6px;
158
+ outline: none;
159
+ font-size: 14px;
160
+ }
161
+ input:focus {
162
+ border-color: #000;
163
+ }
164
+ .send-btn {
165
+ width: auto;
166
+ padding: 0 15px;
167
+ }
168
+
169
+ .loader {
170
+ border: 3px solid #f3f3f3;
171
+ border-top: 3px solid #000;
172
+ border-radius: 50%;
173
+ width: 20px;
174
+ height: 20px;
175
+ animation: spin 1s linear infinite;
176
+ display: inline-block;
177
+ }
178
+
179
+ @keyframes spin {
180
+ 0% {
181
+ transform: rotate(0deg);
182
+ }
183
+ 100% {
184
+ transform: rotate(360deg);
185
+ }
186
+ }
chrome-extension/popup.html ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>RAG Bot</title>
7
+ <link rel="stylesheet" href="popup.css" />
8
+ <script src="popup.js" defer></script>
9
+ </head>
10
+ <body>
11
+ <header>
12
+ <h1>RAG Bot</h1>
13
+ <span id="domain-badge" class="badge">Checking...</span>
14
+ </header>
15
+
16
+ <main>
17
+ <div id="loading-view" class="view">
18
+ <div class="loader"></div>
19
+ <p>Connecting to Brain...</p>
20
+ </div>
21
+
22
+ <!-- Train View -->
23
+ <div id="train-view" class="view hidden">
24
+ <div class="icon-large">🧠</div>
25
+ <h2>New Knowledge</h2>
26
+ <p>
27
+ I haven't read this website yet.<br />Train me to answer questions
28
+ about it.
29
+ </p>
30
+ <button id="train-btn">Train on this Page</button>
31
+ <p id="train-status" class="hidden">
32
+ <span class="loader"></span>
33
+ Processing...
34
+ </p>
35
+ </div>
36
+
37
+ <!-- Chat View -->
38
+ <div id="chat-view" class="view hidden">
39
+ <div id="messages">
40
+ <div class="msg bot">Hello! Ask me anything about this page.</div>
41
+ </div>
42
+ <div class="input-area">
43
+ <input
44
+ type="text"
45
+ id="user-input"
46
+ placeholder="Ask a question..."
47
+ autocomplete="off"
48
+ />
49
+ <button id="send-btn" class="send-btn">↑</button>
50
+ </div>
51
+ </div>
52
+ </main>
53
+
54
+ <!-- The Logic -->
55
+ </body>
56
+ </html>
chrome-extension/popup.js ADDED
@@ -0,0 +1,162 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Config
2
+ const API_BASE = "http://localhost:8000";
3
+
4
+ // DOM Elements
5
+ const views = {
6
+ loading: document.getElementById("loading-view"),
7
+ train: document.getElementById("train-view"),
8
+ chat: document.getElementById("chat-view"),
9
+ };
10
+ const els = {
11
+ domainBadge: document.getElementById("domain-badge"),
12
+ trainBtn: document.getElementById("train-btn"),
13
+ trainStatus: document.getElementById("train-status"),
14
+ messages: document.getElementById("messages"),
15
+ input: document.getElementById("user-input"),
16
+ sendBtn: document.getElementById("send-btn"),
17
+ };
18
+
19
+ // State
20
+ let currentUrl = "";
21
+
22
+ // --- Initialization ---
23
+
24
+ document.addEventListener("DOMContentLoaded", async () => {
25
+ try {
26
+ const tab = await getCurrentTab();
27
+ currentUrl = tab.url;
28
+
29
+ // Update Badge with Domain
30
+ const urlObj = new URL(currentUrl);
31
+ els.domainBadge.textContent = urlObj.hostname;
32
+
33
+ // Check Backend
34
+ await checkIndexStatus(currentUrl);
35
+ } catch (err) {
36
+ showError("Error: " + err.message);
37
+ }
38
+ });
39
+
40
+ // --- Core Logic ---
41
+
42
+ async function checkIndexStatus(url) {
43
+ showView("loading");
44
+
45
+ try {
46
+ const res = await fetch(`${API_BASE}/check`, {
47
+ method: "POST",
48
+ headers: { "Content-Type": "application/json" },
49
+ body: JSON.stringify({ url: url }),
50
+ });
51
+
52
+ const data = await res.json();
53
+
54
+ if (data.exists) {
55
+ showView("chat");
56
+ } else {
57
+ showView("train");
58
+ }
59
+ } catch (err) {
60
+ showError("Backend Offline. Is server.py running?");
61
+ }
62
+ }
63
+
64
+ async function startTraining() {
65
+ els.trainBtn.disabled = true;
66
+ els.trainStatus.classList.remove("hidden");
67
+
68
+ try {
69
+ const res = await fetch(`${API_BASE}/ingest`, {
70
+ method: "POST",
71
+ headers: { "Content-Type": "application/json" },
72
+ body: JSON.stringify({ url: currentUrl }),
73
+ });
74
+
75
+ const data = await res.json();
76
+
77
+ // Since ingestion is background, we wait a bit then switch to chat
78
+ // In a real app, we would poll status. Here we fake a 2s delay.
79
+ setTimeout(() => {
80
+ showView("chat");
81
+ addMessage(
82
+ "bot",
83
+ "I've started reading this site! You can ask me questions now. (Note: It might take a minute to finish reading everything).",
84
+ );
85
+ }, 2000);
86
+ } catch (err) {
87
+ els.trainBtn.disabled = false;
88
+ els.trainStatus.classList.add("hidden");
89
+ alert("Training failed: " + err.message);
90
+ }
91
+ }
92
+
93
+ async function sendMessage() {
94
+ const text = els.input.value.trim();
95
+ if (!text) return;
96
+
97
+ // UI Updates
98
+ addMessage("user", text);
99
+ els.input.value = "";
100
+ els.input.disabled = true;
101
+ els.sendBtn.disabled = true;
102
+
103
+ try {
104
+ const res = await fetch(`${API_BASE}/chat`, {
105
+ method: "POST",
106
+ headers: { "Content-Type": "application/json" },
107
+ body: JSON.stringify({
108
+ message: text,
109
+ url: currentUrl,
110
+ }),
111
+ });
112
+
113
+ if (!res.ok) throw new Error("API Error");
114
+
115
+ const data = await res.json();
116
+ addMessage("bot", data.answer);
117
+ } catch (err) {
118
+ addMessage("error", "Failed to get response. Try again.");
119
+ } finally {
120
+ els.input.disabled = false;
121
+ els.sendBtn.disabled = false;
122
+ els.input.focus();
123
+ }
124
+ }
125
+
126
+ // --- Utilities ---
127
+
128
+ function getCurrentTab() {
129
+ return new Promise((resolve, reject) => {
130
+ chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
131
+ if (tabs[0]) resolve(tabs[0]);
132
+ else reject(new Error("No active tab"));
133
+ });
134
+ });
135
+ }
136
+
137
+ function showView(name) {
138
+ Object.values(views).forEach((el) => el.classList.add("hidden"));
139
+ views[name].classList.remove("hidden");
140
+ }
141
+
142
+ function addMessage(type, text) {
143
+ const div = document.createElement("div");
144
+ div.className = `msg ${type}`;
145
+ div.innerText = text; // Safe text insertion
146
+ els.messages.appendChild(div);
147
+ els.messages.scrollTop = els.messages.scrollHeight;
148
+ }
149
+
150
+ function showError(msg) {
151
+ document.body.innerHTML = `<div style="padding:20px; color:red; text-align:center;">${msg}</div>`;
152
+ }
153
+
154
+ // --- Event Listeners ---
155
+
156
+ els.trainBtn.addEventListener("click", startTraining);
157
+
158
+ els.sendBtn.addEventListener("click", sendMessage);
159
+
160
+ els.input.addEventListener("keypress", (e) => {
161
+ if (e.key === "Enter") sendMessage();
162
+ });
requirements.txt CHANGED
@@ -1,11 +1,7 @@
1
- altair==5.5.0
2
  annotated-doc==0.0.4
3
  annotated-types==0.7.0
4
  anyio==4.11.0
5
- attrs==25.4.0
6
  babel==2.17.0
7
- beautifulsoup4==4.14.2
8
- blinker==1.9.0
9
  cachetools==6.2.2
10
  certifi==2025.11.12
11
  charset-normalizer==3.4.4
@@ -13,10 +9,6 @@ click==8.3.1
13
  courlan==1.3.2
14
  dateparser==1.2.2
15
  fastapi==0.122.0
16
- filelock==3.20.0
17
- fsspec==2025.10.0
18
- gitdb==4.0.12
19
- GitPython==3.1.45
20
  google-ai-generativelanguage==0.6.15
21
  google-api-core==2.28.1
22
  google-api-python-client==2.187.0
@@ -27,74 +19,37 @@ googleapis-common-protos==1.72.0
27
  grpcio==1.76.0
28
  grpcio-status==1.71.2
29
  h11==0.16.0
30
- hf-xet==1.2.0
31
  htmldate==1.9.4
32
  httplib2==0.31.0
33
- huggingface-hub==0.36.0
34
  idna==3.11
35
- Jinja2==3.1.6
36
- joblib==1.5.2
37
- jsonschema==4.25.1
38
- jsonschema-specifications==2025.9.1
39
  jusText==3.0.2
40
  lxml==6.0.2
41
  lxml_html_clean==0.4.3
42
- MarkupSafe==3.0.3
43
- mpmath==1.3.0
44
- narwhals==2.12.0
45
- networkx==3.6
46
- numpy==2.3.5
47
  orjson==3.11.4
48
  packaging==24.2
49
- pandas==2.3.3
50
- pillow==12.0.0
51
  pinecone==8.0.0
52
- pinecone-client==6.0.0
53
  pinecone-plugin-assistant==3.0.1
54
  pinecone-plugin-interface==0.0.7
55
  proto-plus==1.26.1
56
  protobuf==5.29.5
57
- pyarrow==21.0.0
58
  pyasn1==0.6.1
59
  pyasn1_modules==0.4.2
60
  pydantic==2.12.4
61
  pydantic_core==2.41.5
62
- pydeck==0.9.1
63
  pyparsing==3.2.5
64
  python-dateutil==2.9.0.post0
65
- python-dotenv==1.2.1
66
  pytz==2025.2
67
- PyYAML==6.0.3
68
- referencing==0.37.0
69
  regex==2025.11.3
70
  requests==2.32.5
71
- rpds-py==0.29.0
72
  rsa==4.9.1
73
- safetensors==0.7.0
74
- scikit-learn==1.7.2
75
- scipy==1.16.3
76
- sentence-transformers==5.1.2
77
- setuptools==80.9.0
78
  six==1.17.0
79
- smmap==5.0.2
80
  sniffio==1.3.1
81
- soupsieve==2.8
82
  starlette==0.50.0
83
- streamlit==1.51.0
84
- sympy==1.14.0
85
- tenacity==9.1.2
86
- threadpoolctl==3.6.0
87
  tld==0.13.1
88
- tokenizers==0.22.1
89
- toml==0.10.2
90
- torch==2.9.1
91
- tornado==6.5.2
92
  tqdm==4.67.1
93
  trafilatura==2.0.0
94
- transformers==4.57.2
95
  typing-inspection==0.4.2
96
  typing_extensions==4.15.0
97
- tzdata==2025.2
98
  tzlocal==5.3.1
99
  uritemplate==4.2.0
100
  urllib3==2.5.0
 
 
1
  annotated-doc==0.0.4
2
  annotated-types==0.7.0
3
  anyio==4.11.0
 
4
  babel==2.17.0
 
 
5
  cachetools==6.2.2
6
  certifi==2025.11.12
7
  charset-normalizer==3.4.4
 
9
  courlan==1.3.2
10
  dateparser==1.2.2
11
  fastapi==0.122.0
 
 
 
 
12
  google-ai-generativelanguage==0.6.15
13
  google-api-core==2.28.1
14
  google-api-python-client==2.187.0
 
19
  grpcio==1.76.0
20
  grpcio-status==1.71.2
21
  h11==0.16.0
 
22
  htmldate==1.9.4
23
  httplib2==0.31.0
 
24
  idna==3.11
 
 
 
 
25
  jusText==3.0.2
26
  lxml==6.0.2
27
  lxml_html_clean==0.4.3
 
 
 
 
 
28
  orjson==3.11.4
29
  packaging==24.2
 
 
30
  pinecone==8.0.0
 
31
  pinecone-plugin-assistant==3.0.1
32
  pinecone-plugin-interface==0.0.7
33
  proto-plus==1.26.1
34
  protobuf==5.29.5
 
35
  pyasn1==0.6.1
36
  pyasn1_modules==0.4.2
37
  pydantic==2.12.4
38
  pydantic_core==2.41.5
 
39
  pyparsing==3.2.5
40
  python-dateutil==2.9.0.post0
 
41
  pytz==2025.2
 
 
42
  regex==2025.11.3
43
  requests==2.32.5
 
44
  rsa==4.9.1
 
 
 
 
 
45
  six==1.17.0
 
46
  sniffio==1.3.1
 
47
  starlette==0.50.0
 
 
 
 
48
  tld==0.13.1
 
 
 
 
49
  tqdm==4.67.1
50
  trafilatura==2.0.0
 
51
  typing-inspection==0.4.2
52
  typing_extensions==4.15.0
 
53
  tzlocal==5.3.1
54
  uritemplate==4.2.0
55
  urllib3==2.5.0