FastApi / main.py
Yuruyuruu's picture
Update main.py
b6fca69 verified
Raw
History Blame Contribute Delete
4.89 kB
import os
import re
import requests
from fastapi import FastAPI
from pydantic import BaseModel
from typing import List, Optional
from fastapi.middleware.cors import CORSMiddleware
from huggingface_hub import InferenceClient
app = FastAPI(title="Yuyu - LibraryLuxe AI")
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# ================== CONFIG ==================
HF_TOKEN = os.getenv("HF_TOKEN")
client = InferenceClient(api_key=HF_TOKEN)
# Better model (try these in order)
MODEL = "Qwen/Qwen2.5-7B-Instruct" # Best quality
# MODEL = "mistralai/Mistral-7B-Instruct-v0.3"
# MODEL = "microsoft/Phi-3.5-mini-instruct"
# ===========================================
class ChatHistoryItem(BaseModel):
role: str
content: str
class ChatRequest(BaseModel):
message: str
history: List[ChatHistoryItem] = []
class BookEnrichment(BaseModel):
title: Optional[str] = None
author: Optional[str] = None
cover_url: Optional[str] = None
description: Optional[str] = None
isbn: Optional[str] = None
class ChatResponse(BaseModel):
response: str
book_data: Optional[BookEnrichment] = None
# ================== MASTER LIBRARIAN KNOWLEDGE BASE ==================
SYSTEM_PROMPT = """
You are Yuyu, the Master Librarian at LibraryLuxe.
### CORE RULES:
- ALL prices and balances must be mentioned in MMK (Myanmar Kyat).
- Use the 'Actual Library Plans' and 'User Context' provided in the message for precision.
### 1. MEMBERSHIP & SUBSCRIPTIONS
- We have different plans (Basic, Premium, Basic yearly, Premium yearly.) with different book limits and prices.
(Basic: maxed books=3, Borrow days=14 days, Premium: maxed books=5, Borrow days=21days)
- Users can subscribe using their Wallet or other payment methods.
- IMPORTANT: When a user subscribes, it might stay "Pending" until an Admin approves it.
- To Renew/Upgrade: Go to the 'Membership' page and click 'Renew' or 'Upgrade'.
### 2. WALLET & PAYMENTS
- Users have a digital Wallet. They can 'Top Up' money into it.
- Wallet balance can be used to buy subscriptions instantly.
- To Top Up: Go to the 'Wallet' section in the profile menu.
### 3. LOYALTY & REWARDS
- Users earn 'Loyalty Points' for borrowing books and buying membership plans.
- Points can be redeemed for 'Rewards' in 'Rewards' page.
- To check points: Visit the 'Rewards' page.
### 4. BORROWING & RETURNS
- Each plan has a 'Max Books' limit and 'Borrowing Days' limit.
- To Return: Users must 'Request Return' from their 'My Books' page OR go to the library and return it. A librarian will then verify the physical return.
- Overdue books might prevent new borrowings.
### 5. PERSONALITY & TONE
- Be warm, helpful, and professional.
- Use the user's name if provided.
- ALWAYS use the 'Actual Library Plans' and 'User Context' provided in the message for precision.
- If you don't know a specific detail about their account, ask them to check their 'Dashboard' or email aiyurina1610@gmail.com.
Keep responses helpful but concise (max 2 paragraphs).
"""
def get_book_details(isbn: str) -> Optional[BookEnrichment]:
try:
url = f"https://openlibrary.org/api/books?bibkeys=ISBN:{isbn}&format=json&jscmd=data"
resp = requests.get(url, timeout=6)
data = resp.json()
key = f"ISBN:{isbn}"
if key in data:
b = data[key]
return BookEnrichment(
title=b.get("title"),
author=", ".join([a.get("name", "") for a in b.get("authors", [])]),
cover_url=b.get("cover", {}).get("large"),
description=b.get("notes") or b.get("description"),
isbn=isbn
)
except:
pass
return None
@app.get("/")
def home():
return {"status": "online", "message": "Yuyu is ready!"}
@app.post("/chat", response_model=ChatResponse)
async def chat(request: ChatRequest):
# Extract ISBN
isbn_match = re.search(r"\b(?:97[89])?\d{9}[\dX]\b", request.message)
book_data = get_book_details(isbn_match.group(0)) if isbn_match else None
# Build messages
messages = [{"role": "system", "content": SYSTEM_PROMPT}]
# Add recent history
for item in request.history[-6:]:
messages.append({"role": item.role, "content": item.content})
messages.append({"role": "user", "content": request.message})
try:
response = client.chat.completions.create(
model=MODEL,
messages=messages,
max_tokens=450,
temperature=0.75,
top_p=0.9,
)
ai_reply = response.choices[0].message.content.strip()
except Exception as e:
ai_reply = "I'm a bit overloaded right now... Please try again in a few seconds."
return ChatResponse(response=ai_reply, book_data=book_data)