Spaces:
Running
Running
Commit ·
d7434b7
1
Parent(s): f69a6fa
Final changes in local
Browse files- .gitignore +2 -1
- pyproject.toml +1 -0
- src/api/main.py +2 -2
- src/llm/anime_reranker.py +2 -2
- src/retrieval/rag_pipeline.py +18 -17
- src/retrieval/vector_search.py +1 -3
- ui/gradio_app.py +2 -3
- uv.lock +84 -0
.gitignore
CHANGED
|
@@ -2,4 +2,5 @@ __pycache__
|
|
| 2 |
.venv
|
| 3 |
.env
|
| 4 |
data
|
| 5 |
-
.gradio
|
|
|
|
|
|
| 2 |
.venv
|
| 3 |
.env
|
| 4 |
data
|
| 5 |
+
.gradio
|
| 6 |
+
supabase_dump.sql
|
pyproject.toml
CHANGED
|
@@ -13,6 +13,7 @@ dependencies = [
|
|
| 13 |
"pandas>=2.3.3",
|
| 14 |
"psycopg2-binary>=2.9.11",
|
| 15 |
"python-dotenv>=1.2.1",
|
|
|
|
| 16 |
"requests>=2.32.5",
|
| 17 |
"sentence-transformers>=5.2.0",
|
| 18 |
"sqlmodel>=0.0.37",
|
|
|
|
| 13 |
"pandas>=2.3.3",
|
| 14 |
"psycopg2-binary>=2.9.11",
|
| 15 |
"python-dotenv>=1.2.1",
|
| 16 |
+
"qdrant-client>=1.17.0",
|
| 17 |
"requests>=2.32.5",
|
| 18 |
"sentence-transformers>=5.2.0",
|
| 19 |
"sqlmodel>=0.0.37",
|
src/api/main.py
CHANGED
|
@@ -21,7 +21,7 @@ async def lifespan(app: FastAPI):
|
|
| 21 |
Replaces lazy global initialization with app state.
|
| 22 |
"""
|
| 23 |
print("Initializing Anime RAG Pipeline...")
|
| 24 |
-
app.state.pipeline = AnimeRAGPipeline(retriever_k=
|
| 25 |
|
| 26 |
yield
|
| 27 |
print("Shutting down... Cleaning up resources.")
|
|
@@ -79,7 +79,7 @@ async def get_recommendations(request: RecommendationRequest, fastapi_req: Reque
|
|
| 79 |
|
| 80 |
if request.genre_filter:
|
| 81 |
filters["genre_filter"] = request.genre_filter
|
| 82 |
-
|
| 83 |
if request.anime_type:
|
| 84 |
filters["anime_type"] = request.anime_type
|
| 85 |
|
|
|
|
| 21 |
Replaces lazy global initialization with app state.
|
| 22 |
"""
|
| 23 |
print("Initializing Anime RAG Pipeline...")
|
| 24 |
+
app.state.pipeline = AnimeRAGPipeline(retriever_k=50)
|
| 25 |
|
| 26 |
yield
|
| 27 |
print("Shutting down... Cleaning up resources.")
|
|
|
|
| 79 |
|
| 80 |
if request.genre_filter:
|
| 81 |
filters["genre_filter"] = request.genre_filter
|
| 82 |
+
|
| 83 |
if request.anime_type:
|
| 84 |
filters["anime_type"] = request.anime_type
|
| 85 |
|
src/llm/anime_reranker.py
CHANGED
|
@@ -87,7 +87,7 @@ if __name__ == "__main__":
|
|
| 87 |
reranker_service = AnimeReranker()
|
| 88 |
retriever = AnimeRetriever()
|
| 89 |
|
| 90 |
-
user_query = "
|
| 91 |
vector_db_results = retriever.search(query=user_query,
|
| 92 |
n_results=50)
|
| 93 |
|
|
@@ -100,7 +100,7 @@ if __name__ == "__main__":
|
|
| 100 |
# 2. Call the `.process()` method during runtime (e.g., inside an API endpoint)
|
| 101 |
df = reranker_service.process(user_query,
|
| 102 |
vector_db_results,
|
| 103 |
-
top_k=
|
| 104 |
df_dict_list = df.to_dict(orient="records") if not df.empty else []
|
| 105 |
print("\nAFTER RERANKING")
|
| 106 |
print("--------------------------------------------------")
|
|
|
|
| 87 |
reranker_service = AnimeReranker()
|
| 88 |
retriever = AnimeRetriever()
|
| 89 |
|
| 90 |
+
user_query = "Racing Anime"
|
| 91 |
vector_db_results = retriever.search(query=user_query,
|
| 92 |
n_results=50)
|
| 93 |
|
|
|
|
| 100 |
# 2. Call the `.process()` method during runtime (e.g., inside an API endpoint)
|
| 101 |
df = reranker_service.process(user_query,
|
| 102 |
vector_db_results,
|
| 103 |
+
top_k=15)
|
| 104 |
df_dict_list = df.to_dict(orient="records") if not df.empty else []
|
| 105 |
print("\nAFTER RERANKING")
|
| 106 |
print("--------------------------------------------------")
|
src/retrieval/rag_pipeline.py
CHANGED
|
@@ -76,7 +76,8 @@ class AnimeRAGPipeline:
|
|
| 76 |
return {
|
| 77 |
"query": user_query,
|
| 78 |
"recommendations": "Sorry, I'm having trouble processing your query. Can you be more clear and try again?",
|
| 79 |
-
"
|
|
|
|
| 80 |
"retrieved_animes": []
|
| 81 |
}
|
| 82 |
if not initial_response.tool_calls:
|
|
@@ -84,7 +85,8 @@ class AnimeRAGPipeline:
|
|
| 84 |
"[2/5] No search needed. Returning conversational response.")
|
| 85 |
return {
|
| 86 |
"query": user_query,
|
| 87 |
-
"
|
|
|
|
| 88 |
"recommendations": initial_response.content,
|
| 89 |
"retrieved_animes": []
|
| 90 |
}
|
|
@@ -111,15 +113,12 @@ class AnimeRAGPipeline:
|
|
| 111 |
reranked_df = self.reranker.process(
|
| 112 |
user_query=optimized_query,
|
| 113 |
retrieved_anime=retrieved_animes,
|
| 114 |
-
top_k=
|
| 115 |
)
|
| 116 |
|
| 117 |
top_animes_list = reranked_df.to_dict(
|
| 118 |
orient="records") if not reranked_df.empty else []
|
| 119 |
-
|
| 120 |
-
top_animes_list[0])
|
| 121 |
-
print("SECOND IN TOP ANIMES LIST AFTER RERANKING \n",
|
| 122 |
-
top_animes_list[1])
|
| 123 |
print(
|
| 124 |
f"After reranking, fetched {len(top_animes_list)} top animes....")
|
| 125 |
|
|
@@ -145,7 +144,7 @@ class AnimeRAGPipeline:
|
|
| 145 |
|
| 146 |
return {
|
| 147 |
"query": user_query,
|
| 148 |
-
"
|
| 149 |
"reranked_count": len(top_animes_list),
|
| 150 |
"recommendations": recommendations,
|
| 151 |
"retrieved_animes": top_animes_list
|
|
@@ -173,7 +172,8 @@ if __name__ == "__main__":
|
|
| 173 |
|
| 174 |
test_queries = [
|
| 175 |
"Anime similar to Death Note but lighter in tone",
|
| 176 |
-
|
|
|
|
| 177 |
"A generic isekai with an overpowered main character" # Test the mainstream math
|
| 178 |
]
|
| 179 |
|
|
@@ -189,28 +189,28 @@ if __name__ == "__main__":
|
|
| 189 |
# We need to reach into the pipeline's retriever to see what the raw ChromaDB output was,
|
| 190 |
# since the pipeline only returns the *reranked* list.
|
| 191 |
# Note: If the LLM chose NOT to search, result["retrieved_count"] will be 0.
|
| 192 |
-
|
| 193 |
diagnostic_data = {
|
| 194 |
"1_initial_user_query": result["query"],
|
| 195 |
"2_llm_routing_decision": "Searched" if result["retrieved_count"] > 0 else "Chatted",
|
| 196 |
"3_total_retrieved_from_chroma": result["retrieved_count"],
|
| 197 |
"4_total_survived_reranking": result.get("reranked_count", 0),
|
| 198 |
"5_final_llm_recommendation_text": result["recommendations"],
|
| 199 |
-
|
| 200 |
# The "Before" state: We want to see what ChromaDB found just using embeddings
|
| 201 |
"6_raw_chroma_results_before_reranking": [],
|
| 202 |
-
|
| 203 |
# The "After" state: We want to see the exact math scores for the top survivors
|
| 204 |
"7_reranked_results_with_math": []
|
| 205 |
}
|
| 206 |
|
| 207 |
# If the LLM actually performed a search, let's build the detailed lists
|
| 208 |
if result["retrieved_count"] > 0:
|
| 209 |
-
|
| 210 |
# We need to get the optimized query that the LLM generated for the tool call.
|
| 211 |
# (In a real app, you might want to return `optimized_query` in the `result` dict from `recommend()`)
|
| 212 |
# For this test, we will just assume it's the original query if we can't easily grab it here.
|
| 213 |
-
|
| 214 |
# Let's format the top 15 Reranked items with all their math exposed
|
| 215 |
for rank, anime in enumerate(result["retrieved_animes"]):
|
| 216 |
diagnostic_data["7_reranked_results_with_math"].append({
|
|
@@ -221,13 +221,14 @@ if __name__ == "__main__":
|
|
| 221 |
"quality_score_raw": round(anime.get("raw_quality_score", 0), 4),
|
| 222 |
"bayesian_average": round(anime.get("bayesian_score", 0), 4),
|
| 223 |
"passion_rate": round(anime.get("passion_rate", 0), 5),
|
| 224 |
-
|
|
|
|
| 225 |
})
|
| 226 |
|
| 227 |
# 3. Save the diagnostic report
|
| 228 |
safe_filename = f"diagnostic_{query[:20].replace(' ', '_').lower()}.json"
|
| 229 |
filepath = os.path.join("data", safe_filename)
|
| 230 |
-
|
| 231 |
with open(filepath, "w") as f:
|
| 232 |
json.dump(diagnostic_data, f, indent=2)
|
| 233 |
|
|
@@ -236,4 +237,4 @@ if __name__ == "__main__":
|
|
| 236 |
|
| 237 |
# Pause to respect Groq API rate limits
|
| 238 |
import time
|
| 239 |
-
time.sleep(3)
|
|
|
|
| 76 |
return {
|
| 77 |
"query": user_query,
|
| 78 |
"recommendations": "Sorry, I'm having trouble processing your query. Can you be more clear and try again?",
|
| 79 |
+
"retrieved_count_from_DB": 0,
|
| 80 |
+
"reranked_count": 0,
|
| 81 |
"retrieved_animes": []
|
| 82 |
}
|
| 83 |
if not initial_response.tool_calls:
|
|
|
|
| 85 |
"[2/5] No search needed. Returning conversational response.")
|
| 86 |
return {
|
| 87 |
"query": user_query,
|
| 88 |
+
"retrieved_count_from_DB": 0,
|
| 89 |
+
"reranked_count": 0,
|
| 90 |
"recommendations": initial_response.content,
|
| 91 |
"retrieved_animes": []
|
| 92 |
}
|
|
|
|
| 113 |
reranked_df = self.reranker.process(
|
| 114 |
user_query=optimized_query,
|
| 115 |
retrieved_anime=retrieved_animes,
|
| 116 |
+
top_k=10
|
| 117 |
)
|
| 118 |
|
| 119 |
top_animes_list = reranked_df.to_dict(
|
| 120 |
orient="records") if not reranked_df.empty else []
|
| 121 |
+
|
|
|
|
|
|
|
|
|
|
| 122 |
print(
|
| 123 |
f"After reranking, fetched {len(top_animes_list)} top animes....")
|
| 124 |
|
|
|
|
| 144 |
|
| 145 |
return {
|
| 146 |
"query": user_query,
|
| 147 |
+
"retrieved_count_from_DB": len(retrieved_animes),
|
| 148 |
"reranked_count": len(top_animes_list),
|
| 149 |
"recommendations": recommendations,
|
| 150 |
"retrieved_animes": top_animes_list
|
|
|
|
| 172 |
|
| 173 |
test_queries = [
|
| 174 |
"Anime similar to Death Note but lighter in tone",
|
| 175 |
+
# Test the hidden gem / passion rate
|
| 176 |
+
"A really obscure and weird sci-fi mecha from the 90s",
|
| 177 |
"A generic isekai with an overpowered main character" # Test the mainstream math
|
| 178 |
]
|
| 179 |
|
|
|
|
| 189 |
# We need to reach into the pipeline's retriever to see what the raw ChromaDB output was,
|
| 190 |
# since the pipeline only returns the *reranked* list.
|
| 191 |
# Note: If the LLM chose NOT to search, result["retrieved_count"] will be 0.
|
| 192 |
+
|
| 193 |
diagnostic_data = {
|
| 194 |
"1_initial_user_query": result["query"],
|
| 195 |
"2_llm_routing_decision": "Searched" if result["retrieved_count"] > 0 else "Chatted",
|
| 196 |
"3_total_retrieved_from_chroma": result["retrieved_count"],
|
| 197 |
"4_total_survived_reranking": result.get("reranked_count", 0),
|
| 198 |
"5_final_llm_recommendation_text": result["recommendations"],
|
| 199 |
+
|
| 200 |
# The "Before" state: We want to see what ChromaDB found just using embeddings
|
| 201 |
"6_raw_chroma_results_before_reranking": [],
|
| 202 |
+
|
| 203 |
# The "After" state: We want to see the exact math scores for the top survivors
|
| 204 |
"7_reranked_results_with_math": []
|
| 205 |
}
|
| 206 |
|
| 207 |
# If the LLM actually performed a search, let's build the detailed lists
|
| 208 |
if result["retrieved_count"] > 0:
|
| 209 |
+
|
| 210 |
# We need to get the optimized query that the LLM generated for the tool call.
|
| 211 |
# (In a real app, you might want to return `optimized_query` in the `result` dict from `recommend()`)
|
| 212 |
# For this test, we will just assume it's the original query if we can't easily grab it here.
|
| 213 |
+
|
| 214 |
# Let's format the top 15 Reranked items with all their math exposed
|
| 215 |
for rank, anime in enumerate(result["retrieved_animes"]):
|
| 216 |
diagnostic_data["7_reranked_results_with_math"].append({
|
|
|
|
| 221 |
"quality_score_raw": round(anime.get("raw_quality_score", 0), 4),
|
| 222 |
"bayesian_average": round(anime.get("bayesian_score", 0), 4),
|
| 223 |
"passion_rate": round(anime.get("passion_rate", 0), 5),
|
| 224 |
+
# Showing original vector distance
|
| 225 |
+
"chroma_distance": round(1 - anime.get("relevance_score", 1), 4)
|
| 226 |
})
|
| 227 |
|
| 228 |
# 3. Save the diagnostic report
|
| 229 |
safe_filename = f"diagnostic_{query[:20].replace(' ', '_').lower()}.json"
|
| 230 |
filepath = os.path.join("data", safe_filename)
|
| 231 |
+
|
| 232 |
with open(filepath, "w") as f:
|
| 233 |
json.dump(diagnostic_data, f, indent=2)
|
| 234 |
|
|
|
|
| 237 |
|
| 238 |
# Pause to respect Groq API rate limits
|
| 239 |
import time
|
| 240 |
+
time.sleep(3)
|
src/retrieval/vector_search.py
CHANGED
|
@@ -131,9 +131,7 @@ class AnimeRetriever:
|
|
| 131 |
"favorites": pg_anime.favorites,
|
| 132 |
"images": pg_anime.images,
|
| 133 |
"synopsis": pg_anime.synopsis,
|
| 134 |
-
"searchable_text": pg_anime.searchable_text
|
| 135 |
-
# Clean rounded score
|
| 136 |
-
"relevance_score": round(1 - distance, 3),
|
| 137 |
}
|
| 138 |
anime_list.append(anime_info)
|
| 139 |
|
|
|
|
| 131 |
"favorites": pg_anime.favorites,
|
| 132 |
"images": pg_anime.images,
|
| 133 |
"synopsis": pg_anime.synopsis,
|
| 134 |
+
"searchable_text": pg_anime.searchable_text
|
|
|
|
|
|
|
| 135 |
}
|
| 136 |
anime_list.append(anime_info)
|
| 137 |
|
ui/gradio_app.py
CHANGED
|
@@ -91,9 +91,8 @@ def build_retrieved_row(anime: dict, idx: int) -> str:
|
|
| 91 |
kind = anime.get("type") or ""
|
| 92 |
genres = (anime.get("genres") or [])[:2]
|
| 93 |
url = anime.get("mal_url", "#")
|
| 94 |
-
raw_score = anime.get("
|
| 95 |
-
|
| 96 |
-
rel_pct = int(normalized_score * 100)
|
| 97 |
genre_str = " · ".join(genres)
|
| 98 |
|
| 99 |
return (
|
|
|
|
| 91 |
kind = anime.get("type") or ""
|
| 92 |
genres = (anime.get("genres") or [])[:2]
|
| 93 |
url = anime.get("mal_url", "#")
|
| 94 |
+
raw_score = anime.get("final_hybrid_score", 0)
|
| 95 |
+
rel_pct = max(5, int(raw_score * 100))
|
|
|
|
| 96 |
genre_str = " · ".join(genres)
|
| 97 |
|
| 98 |
return (
|
uv.lock
CHANGED
|
@@ -35,6 +35,7 @@ dependencies = [
|
|
| 35 |
{ name = "pandas" },
|
| 36 |
{ name = "psycopg2-binary" },
|
| 37 |
{ name = "python-dotenv" },
|
|
|
|
| 38 |
{ name = "requests" },
|
| 39 |
{ name = "sentence-transformers" },
|
| 40 |
{ name = "sqlmodel" },
|
|
@@ -62,6 +63,7 @@ requires-dist = [
|
|
| 62 |
{ name = "pandas", specifier = ">=2.3.3" },
|
| 63 |
{ name = "psycopg2-binary", specifier = ">=2.9.11" },
|
| 64 |
{ name = "python-dotenv", specifier = ">=1.2.1" },
|
|
|
|
| 65 |
{ name = "requests", specifier = ">=2.32.5" },
|
| 66 |
{ name = "sentence-transformers", specifier = ">=5.2.0" },
|
| 67 |
{ name = "sqlmodel", specifier = ">=0.0.37" },
|
|
@@ -1024,6 +1026,19 @@ wheels = [
|
|
| 1024 |
{ url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
|
| 1025 |
]
|
| 1026 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1027 |
[[package]]
|
| 1028 |
name = "hf-xet"
|
| 1029 |
version = "1.2.0"
|
|
@@ -1046,6 +1061,15 @@ wheels = [
|
|
| 1046 |
{ url = "https://files.pythonhosted.org/packages/cb/44/870d44b30e1dcfb6a65932e3e1506c103a8a5aea9103c337e7a53180322c/hf_xet-1.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:e6584a52253f72c9f52f9e549d5895ca7a471608495c4ecaa6cc73dba2b24d69", size = 2905735, upload-time = "2025-10-24T19:04:35.928Z" },
|
| 1047 |
]
|
| 1048 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1049 |
[[package]]
|
| 1050 |
name = "httpcore"
|
| 1051 |
version = "1.0.9"
|
|
@@ -1103,6 +1127,11 @@ wheels = [
|
|
| 1103 |
{ url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" },
|
| 1104 |
]
|
| 1105 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1106 |
[[package]]
|
| 1107 |
name = "huggingface-hub"
|
| 1108 |
version = "0.36.0"
|
|
@@ -1122,6 +1151,15 @@ wheels = [
|
|
| 1122 |
{ url = "https://files.pythonhosted.org/packages/cb/bd/1a875e0d592d447cbc02805fd3fe0f497714d6a2583f59d14fa9ebad96eb/huggingface_hub-0.36.0-py3-none-any.whl", hash = "sha256:7bcc9ad17d5b3f07b57c78e79d527102d08313caa278a641993acddcb894548d", size = 566094, upload-time = "2025-10-23T12:11:59.557Z" },
|
| 1123 |
]
|
| 1124 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1125 |
[[package]]
|
| 1126 |
name = "idna"
|
| 1127 |
version = "3.11"
|
|
@@ -2411,6 +2449,18 @@ wheels = [
|
|
| 2411 |
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
|
| 2412 |
]
|
| 2413 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2414 |
[[package]]
|
| 2415 |
name = "posthog"
|
| 2416 |
version = "5.4.0"
|
|
@@ -2872,6 +2922,22 @@ wheels = [
|
|
| 2872 |
{ url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" },
|
| 2873 |
]
|
| 2874 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2875 |
[[package]]
|
| 2876 |
name = "pywinpty"
|
| 2877 |
version = "3.0.2"
|
|
@@ -2969,6 +3035,24 @@ wheels = [
|
|
| 2969 |
{ url = "https://files.pythonhosted.org/packages/01/1b/5dbe84eefc86f48473947e2f41711aded97eecef1231f4558f1f02713c12/pyzmq-27.1.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c9f7f6e13dff2e44a6afeaf2cf54cee5929ad64afaf4d40b50f93c58fc687355", size = 544862, upload-time = "2025-09-08T23:09:56.509Z" },
|
| 2970 |
]
|
| 2971 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2972 |
[[package]]
|
| 2973 |
name = "referencing"
|
| 2974 |
version = "0.37.0"
|
|
|
|
| 35 |
{ name = "pandas" },
|
| 36 |
{ name = "psycopg2-binary" },
|
| 37 |
{ name = "python-dotenv" },
|
| 38 |
+
{ name = "qdrant-client" },
|
| 39 |
{ name = "requests" },
|
| 40 |
{ name = "sentence-transformers" },
|
| 41 |
{ name = "sqlmodel" },
|
|
|
|
| 63 |
{ name = "pandas", specifier = ">=2.3.3" },
|
| 64 |
{ name = "psycopg2-binary", specifier = ">=2.9.11" },
|
| 65 |
{ name = "python-dotenv", specifier = ">=1.2.1" },
|
| 66 |
+
{ name = "qdrant-client", specifier = ">=1.17.0" },
|
| 67 |
{ name = "requests", specifier = ">=2.32.5" },
|
| 68 |
{ name = "sentence-transformers", specifier = ">=5.2.0" },
|
| 69 |
{ name = "sqlmodel", specifier = ">=0.0.37" },
|
|
|
|
| 1026 |
{ url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
|
| 1027 |
]
|
| 1028 |
|
| 1029 |
+
[[package]]
|
| 1030 |
+
name = "h2"
|
| 1031 |
+
version = "4.3.0"
|
| 1032 |
+
source = { registry = "https://pypi.org/simple" }
|
| 1033 |
+
dependencies = [
|
| 1034 |
+
{ name = "hpack" },
|
| 1035 |
+
{ name = "hyperframe" },
|
| 1036 |
+
]
|
| 1037 |
+
sdist = { url = "https://files.pythonhosted.org/packages/1d/17/afa56379f94ad0fe8defd37d6eb3f89a25404ffc71d4d848893d270325fc/h2-4.3.0.tar.gz", hash = "sha256:6c59efe4323fa18b47a632221a1888bd7fde6249819beda254aeca909f221bf1", size = 2152026, upload-time = "2025-08-23T18:12:19.778Z" }
|
| 1038 |
+
wheels = [
|
| 1039 |
+
{ url = "https://files.pythonhosted.org/packages/69/b2/119f6e6dcbd96f9069ce9a2665e0146588dc9f88f29549711853645e736a/h2-4.3.0-py3-none-any.whl", hash = "sha256:c438f029a25f7945c69e0ccf0fb951dc3f73a5f6412981daee861431b70e2bdd", size = 61779, upload-time = "2025-08-23T18:12:17.779Z" },
|
| 1040 |
+
]
|
| 1041 |
+
|
| 1042 |
[[package]]
|
| 1043 |
name = "hf-xet"
|
| 1044 |
version = "1.2.0"
|
|
|
|
| 1061 |
{ url = "https://files.pythonhosted.org/packages/cb/44/870d44b30e1dcfb6a65932e3e1506c103a8a5aea9103c337e7a53180322c/hf_xet-1.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:e6584a52253f72c9f52f9e549d5895ca7a471608495c4ecaa6cc73dba2b24d69", size = 2905735, upload-time = "2025-10-24T19:04:35.928Z" },
|
| 1062 |
]
|
| 1063 |
|
| 1064 |
+
[[package]]
|
| 1065 |
+
name = "hpack"
|
| 1066 |
+
version = "4.1.0"
|
| 1067 |
+
source = { registry = "https://pypi.org/simple" }
|
| 1068 |
+
sdist = { url = "https://files.pythonhosted.org/packages/2c/48/71de9ed269fdae9c8057e5a4c0aa7402e8bb16f2c6e90b3aa53327b113f8/hpack-4.1.0.tar.gz", hash = "sha256:ec5eca154f7056aa06f196a557655c5b009b382873ac8d1e66e79e87535f1dca", size = 51276, upload-time = "2025-01-22T21:44:58.347Z" }
|
| 1069 |
+
wheels = [
|
| 1070 |
+
{ url = "https://files.pythonhosted.org/packages/07/c6/80c95b1b2b94682a72cbdbfb85b81ae2daffa4291fbfa1b1464502ede10d/hpack-4.1.0-py3-none-any.whl", hash = "sha256:157ac792668d995c657d93111f46b4535ed114f0c9c8d672271bbec7eae1b496", size = 34357, upload-time = "2025-01-22T21:44:56.92Z" },
|
| 1071 |
+
]
|
| 1072 |
+
|
| 1073 |
[[package]]
|
| 1074 |
name = "httpcore"
|
| 1075 |
version = "1.0.9"
|
|
|
|
| 1127 |
{ url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" },
|
| 1128 |
]
|
| 1129 |
|
| 1130 |
+
[package.optional-dependencies]
|
| 1131 |
+
http2 = [
|
| 1132 |
+
{ name = "h2" },
|
| 1133 |
+
]
|
| 1134 |
+
|
| 1135 |
[[package]]
|
| 1136 |
name = "huggingface-hub"
|
| 1137 |
version = "0.36.0"
|
|
|
|
| 1151 |
{ url = "https://files.pythonhosted.org/packages/cb/bd/1a875e0d592d447cbc02805fd3fe0f497714d6a2583f59d14fa9ebad96eb/huggingface_hub-0.36.0-py3-none-any.whl", hash = "sha256:7bcc9ad17d5b3f07b57c78e79d527102d08313caa278a641993acddcb894548d", size = 566094, upload-time = "2025-10-23T12:11:59.557Z" },
|
| 1152 |
]
|
| 1153 |
|
| 1154 |
+
[[package]]
|
| 1155 |
+
name = "hyperframe"
|
| 1156 |
+
version = "6.1.0"
|
| 1157 |
+
source = { registry = "https://pypi.org/simple" }
|
| 1158 |
+
sdist = { url = "https://files.pythonhosted.org/packages/02/e7/94f8232d4a74cc99514c13a9f995811485a6903d48e5d952771ef6322e30/hyperframe-6.1.0.tar.gz", hash = "sha256:f630908a00854a7adeabd6382b43923a4c4cd4b821fcb527e6ab9e15382a3b08", size = 26566, upload-time = "2025-01-22T21:41:49.302Z" }
|
| 1159 |
+
wheels = [
|
| 1160 |
+
{ url = "https://files.pythonhosted.org/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl", hash = "sha256:b03380493a519fce58ea5af42e4a42317bf9bd425596f7a0835ffce80f1a42e5", size = 13007, upload-time = "2025-01-22T21:41:47.295Z" },
|
| 1161 |
+
]
|
| 1162 |
+
|
| 1163 |
[[package]]
|
| 1164 |
name = "idna"
|
| 1165 |
version = "3.11"
|
|
|
|
| 2449 |
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
|
| 2450 |
]
|
| 2451 |
|
| 2452 |
+
[[package]]
|
| 2453 |
+
name = "portalocker"
|
| 2454 |
+
version = "3.2.0"
|
| 2455 |
+
source = { registry = "https://pypi.org/simple" }
|
| 2456 |
+
dependencies = [
|
| 2457 |
+
{ name = "pywin32", marker = "sys_platform == 'win32'" },
|
| 2458 |
+
]
|
| 2459 |
+
sdist = { url = "https://files.pythonhosted.org/packages/5e/77/65b857a69ed876e1951e88aaba60f5ce6120c33703f7cb61a3c894b8c1b6/portalocker-3.2.0.tar.gz", hash = "sha256:1f3002956a54a8c3730586c5c77bf18fae4149e07eaf1c29fc3faf4d5a3f89ac", size = 95644, upload-time = "2025-06-14T13:20:40.03Z" }
|
| 2460 |
+
wheels = [
|
| 2461 |
+
{ url = "https://files.pythonhosted.org/packages/4b/a6/38c8e2f318bf67d338f4d629e93b0b4b9af331f455f0390ea8ce4a099b26/portalocker-3.2.0-py3-none-any.whl", hash = "sha256:3cdc5f565312224bc570c49337bd21428bba0ef363bbcf58b9ef4a9f11779968", size = 22424, upload-time = "2025-06-14T13:20:38.083Z" },
|
| 2462 |
+
]
|
| 2463 |
+
|
| 2464 |
[[package]]
|
| 2465 |
name = "posthog"
|
| 2466 |
version = "5.4.0"
|
|
|
|
| 2922 |
{ url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" },
|
| 2923 |
]
|
| 2924 |
|
| 2925 |
+
[[package]]
|
| 2926 |
+
name = "pywin32"
|
| 2927 |
+
version = "311"
|
| 2928 |
+
source = { registry = "https://pypi.org/simple" }
|
| 2929 |
+
wheels = [
|
| 2930 |
+
{ url = "https://files.pythonhosted.org/packages/7c/af/449a6a91e5d6db51420875c54f6aff7c97a86a3b13a0b4f1a5c13b988de3/pywin32-311-cp311-cp311-win32.whl", hash = "sha256:184eb5e436dea364dcd3d2316d577d625c0351bf237c4e9a5fabbcfa5a58b151", size = 8697031, upload-time = "2025-07-14T20:13:13.266Z" },
|
| 2931 |
+
{ url = "https://files.pythonhosted.org/packages/51/8f/9bb81dd5bb77d22243d33c8397f09377056d5c687aa6d4042bea7fbf8364/pywin32-311-cp311-cp311-win_amd64.whl", hash = "sha256:3ce80b34b22b17ccbd937a6e78e7225d80c52f5ab9940fe0506a1a16f3dab503", size = 9508308, upload-time = "2025-07-14T20:13:15.147Z" },
|
| 2932 |
+
{ url = "https://files.pythonhosted.org/packages/44/7b/9c2ab54f74a138c491aba1b1cd0795ba61f144c711daea84a88b63dc0f6c/pywin32-311-cp311-cp311-win_arm64.whl", hash = "sha256:a733f1388e1a842abb67ffa8e7aad0e70ac519e09b0f6a784e65a136ec7cefd2", size = 8703930, upload-time = "2025-07-14T20:13:16.945Z" },
|
| 2933 |
+
{ url = "https://files.pythonhosted.org/packages/e7/ab/01ea1943d4eba0f850c3c61e78e8dd59757ff815ff3ccd0a84de5f541f42/pywin32-311-cp312-cp312-win32.whl", hash = "sha256:750ec6e621af2b948540032557b10a2d43b0cee2ae9758c54154d711cc852d31", size = 8706543, upload-time = "2025-07-14T20:13:20.765Z" },
|
| 2934 |
+
{ url = "https://files.pythonhosted.org/packages/d1/a8/a0e8d07d4d051ec7502cd58b291ec98dcc0c3fff027caad0470b72cfcc2f/pywin32-311-cp312-cp312-win_amd64.whl", hash = "sha256:b8c095edad5c211ff31c05223658e71bf7116daa0ecf3ad85f3201ea3190d067", size = 9495040, upload-time = "2025-07-14T20:13:22.543Z" },
|
| 2935 |
+
{ url = "https://files.pythonhosted.org/packages/ba/3a/2ae996277b4b50f17d61f0603efd8253cb2d79cc7ae159468007b586396d/pywin32-311-cp312-cp312-win_arm64.whl", hash = "sha256:e286f46a9a39c4a18b319c28f59b61de793654af2f395c102b4f819e584b5852", size = 8710102, upload-time = "2025-07-14T20:13:24.682Z" },
|
| 2936 |
+
{ url = "https://files.pythonhosted.org/packages/a5/be/3fd5de0979fcb3994bfee0d65ed8ca9506a8a1260651b86174f6a86f52b3/pywin32-311-cp313-cp313-win32.whl", hash = "sha256:f95ba5a847cba10dd8c4d8fefa9f2a6cf283b8b88ed6178fa8a6c1ab16054d0d", size = 8705700, upload-time = "2025-07-14T20:13:26.471Z" },
|
| 2937 |
+
{ url = "https://files.pythonhosted.org/packages/e3/28/e0a1909523c6890208295a29e05c2adb2126364e289826c0a8bc7297bd5c/pywin32-311-cp313-cp313-win_amd64.whl", hash = "sha256:718a38f7e5b058e76aee1c56ddd06908116d35147e133427e59a3983f703a20d", size = 9494700, upload-time = "2025-07-14T20:13:28.243Z" },
|
| 2938 |
+
{ url = "https://files.pythonhosted.org/packages/04/bf/90339ac0f55726dce7d794e6d79a18a91265bdf3aa70b6b9ca52f35e022a/pywin32-311-cp313-cp313-win_arm64.whl", hash = "sha256:7b4075d959648406202d92a2310cb990fea19b535c7f4a78d3f5e10b926eeb8a", size = 8709318, upload-time = "2025-07-14T20:13:30.348Z" },
|
| 2939 |
+
]
|
| 2940 |
+
|
| 2941 |
[[package]]
|
| 2942 |
name = "pywinpty"
|
| 2943 |
version = "3.0.2"
|
|
|
|
| 3035 |
{ url = "https://files.pythonhosted.org/packages/01/1b/5dbe84eefc86f48473947e2f41711aded97eecef1231f4558f1f02713c12/pyzmq-27.1.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c9f7f6e13dff2e44a6afeaf2cf54cee5929ad64afaf4d40b50f93c58fc687355", size = 544862, upload-time = "2025-09-08T23:09:56.509Z" },
|
| 3036 |
]
|
| 3037 |
|
| 3038 |
+
[[package]]
|
| 3039 |
+
name = "qdrant-client"
|
| 3040 |
+
version = "1.17.0"
|
| 3041 |
+
source = { registry = "https://pypi.org/simple" }
|
| 3042 |
+
dependencies = [
|
| 3043 |
+
{ name = "grpcio" },
|
| 3044 |
+
{ name = "httpx", extra = ["http2"] },
|
| 3045 |
+
{ name = "numpy" },
|
| 3046 |
+
{ name = "portalocker" },
|
| 3047 |
+
{ name = "protobuf" },
|
| 3048 |
+
{ name = "pydantic" },
|
| 3049 |
+
{ name = "urllib3" },
|
| 3050 |
+
]
|
| 3051 |
+
sdist = { url = "https://files.pythonhosted.org/packages/20/fb/c9c4cecf6e7fdff2dbaeee0de40e93fe495379eb5fe2775b184ea45315da/qdrant_client-1.17.0.tar.gz", hash = "sha256:47eb033edb9be33a4babb4d87b0d8d5eaf03d52112dca0218db7f2030bf41ba9", size = 344839, upload-time = "2026-02-19T16:03:17.069Z" }
|
| 3052 |
+
wheels = [
|
| 3053 |
+
{ url = "https://files.pythonhosted.org/packages/c1/15/dfadbc9d8c9872e8ac45fa96f5099bb2855f23426bfea1bbcdc85e64ef6e/qdrant_client-1.17.0-py3-none-any.whl", hash = "sha256:f5b452c68c42b3580d3d266446fb00d3c6e3aae89c916e16585b3c704e108438", size = 390381, upload-time = "2026-02-19T16:03:15.486Z" },
|
| 3054 |
+
]
|
| 3055 |
+
|
| 3056 |
[[package]]
|
| 3057 |
name = "referencing"
|
| 3058 |
version = "0.37.0"
|