Spaces:
Sleeping
Sleeping
Commit ·
f24939c
1
Parent(s): 1a2b9e6
Initial commit
Browse files- pyproject.toml +1 -0
- src/api/schemas.py +7 -3
- src/llm/prompts.py +4 -0
- src/utils/neo4j_client.py +50 -0
- try.py +45 -8
- ui/gradio_app.py +1 -1
- uv.lock +14 -0
pyproject.toml
CHANGED
|
@@ -10,6 +10,7 @@ dependencies = [
|
|
| 10 |
"gradio>=6.2.0",
|
| 11 |
"langchain>=1.1.3",
|
| 12 |
"langchain-groq>=1.1.1",
|
|
|
|
| 13 |
"pandas>=2.3.3",
|
| 14 |
"python-dotenv>=1.2.1",
|
| 15 |
"requests>=2.32.5",
|
|
|
|
| 10 |
"gradio>=6.2.0",
|
| 11 |
"langchain>=1.1.3",
|
| 12 |
"langchain-groq>=1.1.1",
|
| 13 |
+
"neo4j>=6.1.0",
|
| 14 |
"pandas>=2.3.3",
|
| 15 |
"python-dotenv>=1.2.1",
|
| 16 |
"requests>=2.32.5",
|
src/api/schemas.py
CHANGED
|
@@ -1,13 +1,17 @@
|
|
| 1 |
from pydantic import BaseModel, Field
|
| 2 |
|
|
|
|
| 3 |
class RecommendationRequest(BaseModel):
|
| 4 |
query: str = Field(description="User's anime recommendation request")
|
| 5 |
-
n_results: int | None = Field(
|
| 6 |
-
|
|
|
|
|
|
|
| 7 |
genre_filter: str | None = Field(None, description="Filter by genre")
|
| 8 |
|
|
|
|
| 9 |
class RecommendationResponse(BaseModel):
|
| 10 |
query: str
|
| 11 |
recommendations: str
|
| 12 |
retrieved_count: int
|
| 13 |
-
metadata: dict = {}
|
|
|
|
| 1 |
from pydantic import BaseModel, Field
|
| 2 |
|
| 3 |
+
|
| 4 |
class RecommendationRequest(BaseModel):
|
| 5 |
query: str = Field(description="User's anime recommendation request")
|
| 6 |
+
n_results: int | None = Field(
|
| 7 |
+
5, description="Number of recommendations to return")
|
| 8 |
+
min_score: float | None = Field(
|
| 9 |
+
None, description="Minimum MyAnimeList Score filter")
|
| 10 |
genre_filter: str | None = Field(None, description="Filter by genre")
|
| 11 |
|
| 12 |
+
|
| 13 |
class RecommendationResponse(BaseModel):
|
| 14 |
query: str
|
| 15 |
recommendations: str
|
| 16 |
retrieved_count: int
|
| 17 |
+
metadata: dict = {}
|
src/llm/prompts.py
CHANGED
|
@@ -29,6 +29,10 @@ def create_recommendation_prompt(
|
|
| 29 |
|
| 30 |
prompt = f"""
|
| 31 |
You are an expert anime recommendation assistant. A user has asked for recommendations, and I've retrieved some potentially relevant anime from the database.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
Your task is to:
|
| 33 |
1. Analyze the user's request carefully, paying attention to specific preferences (tone, themes, etc.)
|
| 34 |
2. Evaluate each retrieved anime against their user's criteria
|
|
|
|
| 29 |
|
| 30 |
prompt = f"""
|
| 31 |
You are an expert anime recommendation assistant. A user has asked for recommendations, and I've retrieved some potentially relevant anime from the database.
|
| 32 |
+
First: If the user is asking for a comparison or opinion on specific anime,
|
| 33 |
+
provide thoughtful comparison rather than a list of recommendations.
|
| 34 |
+
|
| 35 |
+
If recommendations, onlt then:
|
| 36 |
Your task is to:
|
| 37 |
1. Analyze the user's request carefully, paying attention to specific preferences (tone, themes, etc.)
|
| 38 |
2. Evaluate each retrieved anime against their user's criteria
|
src/utils/neo4j_client.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from dotenv import load_dotenv
|
| 3 |
+
from neo4j import GraphDatabase
|
| 4 |
+
|
| 5 |
+
load_dotenv()
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
class Neo4j_Client:
|
| 9 |
+
"""Neo4j database client"""
|
| 10 |
+
|
| 11 |
+
def __init__(self):
|
| 12 |
+
uri = os.getenv("NEO4J_URI")
|
| 13 |
+
user = os.getenv("NEO4J_USERNAME")
|
| 14 |
+
password = os.getenv("NEO4J_PASSWORD")
|
| 15 |
+
try:
|
| 16 |
+
self.driver = GraphDatabase.driver(
|
| 17 |
+
uri, auth=(user, password)) # type: ignore
|
| 18 |
+
self.driver.verify_connectivity()
|
| 19 |
+
|
| 20 |
+
except Exception as e:
|
| 21 |
+
raise e
|
| 22 |
+
|
| 23 |
+
def close(self):
|
| 24 |
+
self.driver.close()
|
| 25 |
+
|
| 26 |
+
def verify_connectivity(self):
|
| 27 |
+
"""Test connection"""
|
| 28 |
+
with self.driver.session() as session:
|
| 29 |
+
result = session.run("RETURN 'Connection Successful !' AS message")
|
| 30 |
+
record = result.single()
|
| 31 |
+
if record['message']: #type: ignore
|
| 32 |
+
return record["message"] # type: ignore
|
| 33 |
+
else:
|
| 34 |
+
return "Connection failed"
|
| 35 |
+
|
| 36 |
+
def run_query(self, query, parameters=None):
|
| 37 |
+
with self.driver.session() as session:
|
| 38 |
+
result = session.run(query, parameters or {})
|
| 39 |
+
return [record.data() for record in result]
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
if __name__ == '__main__':
|
| 43 |
+
client = Neo4j_Client()
|
| 44 |
+
|
| 45 |
+
message = client.verify_connectivity()
|
| 46 |
+
print(f"Message: {message}")
|
| 47 |
+
|
| 48 |
+
result = client.run_query("RETURN 1 + 1 AS result")
|
| 49 |
+
print(f"Test query result: {result}")
|
| 50 |
+
client.close()
|
try.py
CHANGED
|
@@ -1,14 +1,51 @@
|
|
| 1 |
-
import requests
|
| 2 |
-
from rich import print
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
import json
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
|
| 5 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
|
| 7 |
-
|
| 8 |
|
| 9 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
|
| 11 |
-
response_json = response.json()
|
| 12 |
|
| 13 |
-
|
| 14 |
-
json.dump(response_json, f, indent=4, ensure_ascii=False)
|
|
|
|
| 1 |
+
# import requests
|
| 2 |
+
# from rich import print
|
| 3 |
+
# import json
|
| 4 |
+
|
| 5 |
+
# url = "https://api.jikan.moe/v4/anime"
|
| 6 |
+
|
| 7 |
+
# payload = {"id": {1}}
|
| 8 |
+
|
| 9 |
+
# response = requests.get(url=url, params=payload)
|
| 10 |
+
|
| 11 |
+
# response_json = response.json()
|
| 12 |
+
|
| 13 |
+
# with open("output.json", "w") as f:
|
| 14 |
+
# json.dump(response_json, f, indent=4, ensure_ascii=False)
|
| 15 |
+
|
| 16 |
import json
|
| 17 |
+
import re
|
| 18 |
+
|
| 19 |
+
data_path = "data/processed/anime_clean.json"
|
| 20 |
+
|
| 21 |
+
with open(data_path, encoding='utf-8', mode='r') as f:
|
| 22 |
+
anime_data = json.load(f)
|
| 23 |
+
|
| 24 |
+
sequel_search = ["Season", "Part"]
|
| 25 |
+
anime_name = "Spy x Family"
|
| 26 |
|
| 27 |
+
title_eng = 0
|
| 28 |
+
sequels = []
|
| 29 |
+
for anime in anime_data:
|
| 30 |
+
pattern = fr"^(?=.*{anime_name})([^.]+)"
|
| 31 |
+
match = re.search(pattern, anime.get("searchable_text"))
|
| 32 |
+
if match:
|
| 33 |
+
sequels.append({
|
| 34 |
+
"mal_id": anime.get("mal_id"),
|
| 35 |
+
"title": match.group(),
|
| 36 |
+
"type": anime.get("type"),
|
| 37 |
+
"year": anime.get("aired_from")
|
| 38 |
+
})
|
| 39 |
|
| 40 |
+
sequels.sort(key=lambda x: x["year"])
|
| 41 |
|
| 42 |
+
for s in sequels:
|
| 43 |
+
sequels_string = f"""
|
| 44 |
+
Mal_Id: {s["mal_id"]}
|
| 45 |
+
Title: {s["title"]}
|
| 46 |
+
Type: {s["type"]}
|
| 47 |
+
Year: {s["year"]}"""
|
| 48 |
+
print(sequels_string)
|
| 49 |
|
|
|
|
| 50 |
|
| 51 |
+
# print(sequels_string)
|
|
|
ui/gradio_app.py
CHANGED
|
@@ -10,7 +10,7 @@ def get_recommendations(query, min_score, genre_filter):
|
|
| 10 |
try:
|
| 11 |
payload = {
|
| 12 |
"query": query,
|
| 13 |
-
"n_results":
|
| 14 |
}
|
| 15 |
|
| 16 |
if min_score > 0:
|
|
|
|
| 10 |
try:
|
| 11 |
payload = {
|
| 12 |
"query": query,
|
| 13 |
+
"n_results": 5
|
| 14 |
}
|
| 15 |
|
| 16 |
if min_score > 0:
|
uv.lock
CHANGED
|
@@ -32,6 +32,7 @@ dependencies = [
|
|
| 32 |
{ name = "gradio" },
|
| 33 |
{ name = "langchain" },
|
| 34 |
{ name = "langchain-groq" },
|
|
|
|
| 35 |
{ name = "pandas" },
|
| 36 |
{ name = "python-dotenv" },
|
| 37 |
{ name = "requests" },
|
|
@@ -57,6 +58,7 @@ requires-dist = [
|
|
| 57 |
{ name = "gradio", specifier = ">=6.2.0" },
|
| 58 |
{ name = "langchain", specifier = ">=1.1.3" },
|
| 59 |
{ name = "langchain-groq", specifier = ">=1.1.1" },
|
|
|
|
| 60 |
{ name = "pandas", specifier = ">=2.3.3" },
|
| 61 |
{ name = "python-dotenv", specifier = ">=1.2.1" },
|
| 62 |
{ name = "requests", specifier = ">=2.32.5" },
|
|
@@ -1940,6 +1942,18 @@ wheels = [
|
|
| 1940 |
{ url = "https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b", size = 78454, upload-time = "2024-04-04T11:20:34.895Z" },
|
| 1941 |
]
|
| 1942 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1943 |
[[package]]
|
| 1944 |
name = "nest-asyncio"
|
| 1945 |
version = "1.6.0"
|
|
|
|
| 32 |
{ name = "gradio" },
|
| 33 |
{ name = "langchain" },
|
| 34 |
{ name = "langchain-groq" },
|
| 35 |
+
{ name = "neo4j" },
|
| 36 |
{ name = "pandas" },
|
| 37 |
{ name = "python-dotenv" },
|
| 38 |
{ name = "requests" },
|
|
|
|
| 58 |
{ name = "gradio", specifier = ">=6.2.0" },
|
| 59 |
{ name = "langchain", specifier = ">=1.1.3" },
|
| 60 |
{ name = "langchain-groq", specifier = ">=1.1.1" },
|
| 61 |
+
{ name = "neo4j", specifier = ">=6.1.0" },
|
| 62 |
{ name = "pandas", specifier = ">=2.3.3" },
|
| 63 |
{ name = "python-dotenv", specifier = ">=1.2.1" },
|
| 64 |
{ name = "requests", specifier = ">=2.32.5" },
|
|
|
|
| 1942 |
{ url = "https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b", size = 78454, upload-time = "2024-04-04T11:20:34.895Z" },
|
| 1943 |
]
|
| 1944 |
|
| 1945 |
+
[[package]]
|
| 1946 |
+
name = "neo4j"
|
| 1947 |
+
version = "6.1.0"
|
| 1948 |
+
source = { registry = "https://pypi.org/simple" }
|
| 1949 |
+
dependencies = [
|
| 1950 |
+
{ name = "pytz" },
|
| 1951 |
+
]
|
| 1952 |
+
sdist = { url = "https://files.pythonhosted.org/packages/1b/01/d6ce65e4647f6cb2b9cca3b813978f7329b54b4e36660aaec1ddf0ccce7a/neo4j-6.1.0.tar.gz", hash = "sha256:b5dde8c0d8481e7b6ae3733569d990dd3e5befdc5d452f531ad1884ed3500b84", size = 239629, upload-time = "2026-01-12T11:27:34.777Z" }
|
| 1953 |
+
wheels = [
|
| 1954 |
+
{ url = "https://files.pythonhosted.org/packages/70/5c/ee71e2dd955045425ef44283f40ba1da67673cf06404916ca2950ac0cd39/neo4j-6.1.0-py3-none-any.whl", hash = "sha256:3bd93941f3a3559af197031157220af9fd71f4f93a311db687bd69ffa417b67d", size = 325326, upload-time = "2026-01-12T11:27:33.196Z" },
|
| 1955 |
+
]
|
| 1956 |
+
|
| 1957 |
[[package]]
|
| 1958 |
name = "nest-asyncio"
|
| 1959 |
version = "1.6.0"
|