initial upload

This commit is contained in:
2023-07-19 00:47:09 -05:00
commit c993ea8b6a
13 changed files with 881 additions and 0 deletions

0
app/__init__.py Normal file
View File

20
app/dependencies.py Normal file
View File

@@ -0,0 +1,20 @@
import json
# Helper functions
def load_animeguess_anime_list():
"""
Load in the parsed anime list
"""
global animeguess_anime_list
f = open('app/parsed-anime-list-mini.json')
animeguess_anime_list = json.load(f)
def return_animeguess_anime_list():
"""
Return the parsed anime list
Returns:
JSON:
parsed anime list
"""
return animeguess_anime_list

28
app/main.py Normal file
View File

@@ -0,0 +1,28 @@
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from .dependencies import load_animeguess_anime_list
from .routers import animeguess
# Load anime list
load_animeguess_anime_list()
app = FastAPI()
# Middleware CORS
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"]
)
# Routes
app.include_router(animeguess.router)
# Health check
@app.get("/ping")
async def ping():
return {"Ping":"Pong"}

File diff suppressed because one or more lines are too long

0
app/routers/__init__.py Normal file
View File

145
app/routers/animeguess.py Normal file
View File

@@ -0,0 +1,145 @@
import os
import requests
from ..dependencies import return_animeguess_anime_list
from fastapi import APIRouter
from pydantic import BaseModel
from rapidfuzz import fuzz
from operator import itemgetter
router = APIRouter()
# Helper functions
def return_bad():
"""
Returns HTTP 400 and message for a bad request
Returns:
JSON:
statusCode: 400
headers: Content-Type text/plain
body: 400: Bad request
"""
return {
'statusCode': 400,
'headers': {
'Content-Type': 'text/plain'
},
'body': '400: Bad Request'
}
# Models
class Metadata(BaseModel):
id: str
class Search(BaseModel):
query: str
# Routes
@router.post("/ag-metadata")
async def ag_metadata(metadata: Metadata):
"""
Gets the metadata from MyAnimeList based on the inputted name
Requires:
POST:
'id': MyAnimeList ID of the anime
Returns:
JSON:
metadata from MyAnimeList
"""
if not metadata.id.isdigit():
return return_bad()
# MAL API key
CLIENT_ID = os.getenv('MAL_CLIENT_ID')
# Get data from MAL
url = f'https://api.myanimelist.net/v2/anime/{str(metadata.id)}?fields=title,studios,genres,mean,start_season'
resp = requests.get(url, headers={
'X-MAL-CLIENT-ID': CLIENT_ID
})
return resp.json()
@router.post("/ag-search")
async def ag_search(search: Search):
"""
Perform a fuzzy search for an anime title
Requires:
POST - 'query': search query
Returns:
JSON - possible anime titles
"""
# Ensure search is at least 3 characters
if len(search.query) < 3:
return return_bad()
search_item = search.query
# Keep track of titles, ids, and scores that are possible
data = return_animeguess_anime_list()
anime_score_list = []
# Cycle through parsed list
for item in data:
# Perform fuzzy search against titles
fuzzy_search = fuzz.ratio(search_item.lower(), item['title'].lower())
# Check if search item is in the title
in_title = search_item.lower() in item['title'].lower()
# If the query is in the title or has a high fuzzy search score
if in_title or fuzzy_search > 65:
# If the query is in the title, give it a higher score
if in_title:
# If the query is the same as the title, give it the highest score
if search_item.lower() == item['title'].lower():
anime_score_list.append({'title': item['title'], 'score': 200, 'mal_id': item['mal_id']})
else:
anime_score_list.append({'title': item['title'], 'score': 100, 'mal_id': item['mal_id']})
# Else, set it to the fuzzy search score
else:
anime_score_list.append({'title': item['title'], 'score': fuzzy_search, 'mal_id': item['mal_id']})
# Check synonyms if it's not in the title or a fuzzy search isn't matched
else:
for synonym in item['synonyms']:
# Perform fuzzy search against each synonym
fuzzy_search = fuzz.ratio(search_item.lower(), synonym.lower())
# Check if the search item is in the synonym
in_synonym = search_item.lower() in synonym.lower()
# If the query is in the synonym or has a high fuzzy search score
if in_synonym or fuzzy_search > 65:
# If the query is in the synonym give it a higher score
if in_synonym:
# If the query is the same as the synonym, give it the highest score
if search_item.lower() == synonym.lower():
anime_score_list.append({'title': f'{item["title"]} [{synonym}]', 'score': 200, 'mal_id': item['mal_id']})
else:
anime_score_list.append({'title': f'{item["title"]} [{synonym}]', 'score': 100, 'mal_id': item['mal_id']})
break
# Else, give it the fuzzy search score
else:
anime_score_list.append({'title': f'{item["title"]} [{synonym}]', 'score': fuzzy_search, 'mal_id': item['mal_id']})
break
# Sort possible anime titles by score
anime_score_list = sorted(anime_score_list, key=itemgetter('score'), reverse=True)
# Remove score key since it is un-needed after sort
for anime in anime_score_list:
anime = anime.pop('score')
return anime_score_list