Spaces:
Running
Running
| from fastapi import FastAPI, Request | |
| from pydantic import BaseModel | |
| from transformers import AutoModelForCausalLM, AutoTokenizer | |
| import torch | |
| from datetime import datetime | |
| from zoneinfo import ZoneInfo | |
| import httpx | |
| from functools import lru_cache | |
| app = FastAPI() | |
| # --- Tải model --- | |
| MODEL_NAME = "Qwen/Qwen2.5-1.5B-Instruct" | |
| tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, trust_remote_code=True) | |
| model = AutoModelForCausalLM.from_pretrained( | |
| MODEL_NAME, | |
| torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32, | |
| device_map="auto" | |
| ) | |
| # --- Request body --- | |
| class GenerateRequest(BaseModel): | |
| prompt: str | list[str] | |
| # --- Cache IP info --- | |
| def cache_location(ip: str, city: str, country: str, timezone: str): | |
| return city, country, timezone | |
| # --- Hàm lấy vị trí từ IP --- | |
| async def get_location_from_ip(ip: str): | |
| try: | |
| async with httpx.AsyncClient(timeout=3) as client: | |
| res = await client.get(f"https://ipinfo.io/{ip}?token=2d478668dc5662") | |
| data = res.json() | |
| city = data.get("city", "Ho Chi Minh City") | |
| country = data.get("country", "VN") | |
| timezone = data.get("timezone", "Asia/Ho_Chi_Minh") | |
| cache_location(ip, city, country, timezone) | |
| return city, country, timezone | |
| except: | |
| return "Ho Chi Minh City", "VN", "Asia/Ho_Chi_Minh" | |
| # --- Cache thời tiết --- | |
| def cache_weather(city: str, desc: str, temp: float): | |
| return desc, temp | |
| async def get_weather(city: str): | |
| try: | |
| api_key = "b7d49ff5de091794a9adc8ea62ef0ac7" | |
| async with httpx.AsyncClient(timeout=3) as client: | |
| url = f"http://api.openweathermap.org/data/2.5/weather?q={city}&appid={api_key}&units=metric&lang=vi" | |
| res = await client.get(url) | |
| data = res.json() | |
| temp = data["main"]["temp"] | |
| desc = data["weather"][0]["description"] | |
| cache_weather(city, desc, temp) | |
| return desc, temp | |
| except: | |
| return None, None | |
| def home(): | |
| return {"message": "API FastAI đã sẵn sàng phục vụ Túc chủ 👑"} | |
| async def generate(req: GenerateRequest, request: Request): | |
| prompt = req.prompt | |
| if isinstance(prompt, list): | |
| prompt = " ".join(prompt) | |
| # Lấy IP từ request | |
| client_ip = request.client.host | |
| city, country, timezone = await get_location_from_ip(client_ip) | |
| # --- Logic đặc biệt --- | |
| # 1. Thời gian hiện tại | |
| if "mấy giờ" in prompt or "thời gian" in prompt: | |
| tz = ZoneInfo(timezone) | |
| current_time = datetime.now(tz).strftime("%H:%M") | |
| return {"response": f"Bây giờ ở {city} là {current_time}"} | |
| # 2. Ngày hôm nay | |
| if "ngày hôm nay" in prompt or "hôm nay là ngày" in prompt: | |
| tz = ZoneInfo(timezone) | |
| today = datetime.now(tz).strftime("%d/%m/%Y") | |
| return {"response": f"Hôm nay ở {city} là ngày {today}"} | |
| # 3. Thời tiết | |
| if "thời tiết" in prompt: | |
| desc, temp = await get_weather(city) | |
| if desc and temp: | |
| return {"response": f"Thời tiết ở {city}: {desc}, nhiệt độ {temp}°C"} | |
| else: | |
| return {"response": "Không lấy được dữ liệu thời tiết."} | |
| # --- Fallback sang mô hình --- | |
| final_prompt = f"Trả lời bằng tiếng Việt, ngắn gọn, đầy đủ câu, không lặp lại câu hỏi và tiêu đề trang trích dẫn: {prompt}" | |
| inputs = tokenizer(final_prompt, return_tensors="pt").to(model.device) | |
| outputs = model.generate( | |
| **inputs, | |
| max_new_tokens=250, # Giảm để tăng tốc | |
| temperature=0.5, | |
| top_p=0.8, | |
| do_sample=True, | |
| repetition_penalty=1.3, | |
| eos_token_id=tokenizer.eos_token_id, | |
| pad_token_id=tokenizer.pad_token_id | |
| ) | |
| result = tokenizer.decode(outputs[0], skip_special_tokens=True) | |
| clean_result = result[len(final_prompt):].strip() | |
| if not clean_result.endswith((".", "!", "?")): | |
| clean_result += "..." | |
| return {"response": clean_result} |