from fastapi import FastAPI, Request, HTTPException from fastapi.responses import JSONResponse, HTMLResponse from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles import json import os import socket from datetime import datetime, date import requests import logging import threading # Logging ayarı logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' ) logger = logging.getLogger(__name__) app = FastAPI( title="AI Chat API", version="2.0.0", docs_url="/docs", redoc_url="/redoc" ) # TÜM CORS izinleri - Telefondan erişim için app.add_middleware( CORSMiddleware, allow_origins=["*"], # Tüm domain'lere izin ver allow_credentials=True, allow_methods=["*"], allow_headers=["*"], expose_headers=["*"] ) # Dosya yolları DB_PATH = "users.json" HF_TOKEN = os.getenv("HF_TOKEN", "") MODEL_NAME = "mistralai/Mistral-7B-Instruct-v0.2" API_URL = f"https://api-inference.huggingface.co/models/{MODEL_NAME}" # Limitler DAILY_LIMIT = 100 MAX_TOKENS = 150 def get_local_ip(): """Bilgisayarın IP adresini bul""" try: # İnternet bağlantısı olan bir socket oluştur s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(("8.8.8.8", 80)) # Google DNS ip = s.getsockname()[0] s.close() return ip except: return "127.0.0.1" # Sunucu bilgileri SERVER_IP = get_local_ip() SERVER_PORT = 8000 BASE_URL = f"http://{SERVER_IP}:{SERVER_PORT}" # QR kodu oluşturmak için def generate_qr_code_url(): """Telefonda açmak için QR kodu URL'si""" import urllib.parse html_url = f"{BASE_URL}/test" qr_url = f"https://api.qrserver.com/v1/create-qr-code/?size=200x200&data={urllib.parse.quote(html_url)}" return qr_url def load_db(): """Kullanıcı veritabanını yükle""" try: if os.path.exists(DB_PATH): with open(DB_PATH, "r", encoding="utf-8") as f: return json.load(f) except Exception as e: logger.error(f"Veritabanı yükleme hatası: {e}") return {} return {} def save_db(data): """Kullanıcı veritabanını kaydet""" try: with open(DB_PATH, "w", encoding="utf-8") as f: json.dump(data, f, indent=2, ensure_ascii=False) return True except Exception as e: logger.error(f"Veritabanı kaydetme hatası: {e}") return False def get_model_response_simple(message): """Basit model yanıtı - Hata toleranslı""" if not HF_TOKEN: return "🔑 API token bulunamadı. Lütfen HF_TOKEN ayarlayın." try: # Daha kısa ve basit prompt prompt = f"Kullanıcı soruyor: {message}\nYanıt:" response = requests.post( API_URL, headers={ "Authorization": f"Bearer {HF_TOKEN}", "Content-Type": "application/json" }, json={ "inputs": prompt, "parameters": { "max_new_tokens": MAX_TOKENS, "temperature": 0.7, "top_p": 0.9, "do_sample": True, "return_full_text": False } }, timeout=15 ) logger.info(f"API Status: {response.status_code}") if response.status_code == 200: result = response.json() # Farklı formatları işle if isinstance(result, list): for item in result: if isinstance(item, dict): # Format: [{'generated_text': '...'}] if 'generated_text' in item: text = item['generated_text'] if isinstance(text, str): # Prompt'u temizle text = text.replace(prompt, "").strip() if text: return text # Diğer formatlar for key, value in item.items(): if isinstance(value, str) and len(value) > 10: cleaned = value.replace(prompt, "").strip() if cleaned: return cleaned return "🤖 Yanıt alındı ancak işlenemedi." elif response.status_code == 503: return "⏳ Model yükleniyor, lütfen 15 saniye bekleyin..." elif response.status_code == 429: return "🚫 Çok fazla istek, lütfen bekleyin." else: return f"❌ API hatası: {response.status_code}" except requests.exceptions.Timeout: return "⏱️ Zaman aşımı, lütfen daha kısa soru sorun." except Exception as e: logger.error(f"Model hatası: {e}") return f"⚠️ Teknik hata: {str(e)[:50]}" @app.get("/", response_class=HTMLResponse) async def home(): """Ana sayfa - QR kodu ve bağlantılar""" html_content = f""" AI Chat API - Telefon Erişimi

🤖 AI Chat API

Telefonunuzdan bağlanmak için:

Model Durumu: {'✅ Hazır' if HF_TOKEN else '⚠️ Token Eksik'}

📱 Telefon ile Bağlan

Telefon kameranızla bu QR kodu tarayın:

veya bağlantıya tıklayın

🔗 Bağlantılar:

📋 Bilgiler:

IP Adresi: {SERVER_IP}

Port: {SERVER_PORT}

Model: {MODEL_NAME}

Günlük Limit: {DAILY_LIMIT} sorgu/kullanıcı

""" return HTMLResponse(content=html_content) @app.get("/health") async def health(): """Sağlık kontrolü - JSON formatında""" db_status = "exists" if os.path.exists(DB_PATH) else "missing" token_exists = bool(HF_TOKEN) return { "status": "healthy" if token_exists else "no_token", "timestamp": datetime.now().isoformat(), "server_ip": SERVER_IP, "port": SERVER_PORT, "model": MODEL_NAME, "token": "valid" if token_exists else "missing", "database": db_status, "daily_limit": DAILY_LIMIT, "api_url": f"http://{SERVER_IP}:{SERVER_PORT}", "test_url": f"http://{SERVER_IP}:{SERVER_PORT}/test" } @app.get("/test", response_class=HTMLResponse) async def test_page(): """Test arayüzü sayfası""" with open("test.html", "r", encoding="utf-8") as f: html_content = f.read() # API URL'sini dinamik olarak ayarla html_content = html_content.replace( 'const API_BASE_URL = \'http://localhost:8000\';', f'const API_BASE_URL = \'http://{SERVER_IP}:{SERVER_PORT}\';' ) return HTMLResponse(content=html_content) @app.post("/api/chat") async def chat(request: Request): """Chat endpoint'i""" try: data = await request.json() email = data.get("email", "").strip().lower() message = data.get("message", "").strip() logger.info(f"Chat isteği: {email} - {message[:30]}...") # Validasyon if not email or "@" not in email: raise HTTPException(400, "Geçerli email gerekli") if not message: raise HTTPException(400, "Mesaj boş olamaz") if len(message) > 500: raise HTTPException(400, "Mesaj çok uzun (max 500 karakter)") # Veritabanı db = load_db() today = date.today().isoformat() if email not in db: db[email] = { "count": 0, "total": 0, "last_reset": today, "created": datetime.now().isoformat() } user = db[email] # Limit kontrol if user["last_reset"] != today: user["count"] = 0 user["last_reset"] = today if user["count"] >= DAILY_LIMIT: raise HTTPException(429, f"Günlük limit ({DAILY_LIMIT}) doldu") # Model yanıtı ai_response = get_model_response_simple(message) user["count"] += 1 user["total"] += 1 save_db(db) return { "response": ai_response, "status": "success", "remaining": DAILY_LIMIT - user["count"], "used_today": user["count"], "total_used": user["total"], "timestamp": datetime.now().isoformat() } except HTTPException: raise except Exception as e: logger.error(f"Chat hatası: {e}") raise HTTPException(500, f"Sunucu hatası: {str(e)}") @app.get("/api/stats/{email}") async def get_stats(email: str): """İstatistikler""" email = email.strip().lower() db = load_db() if email not in db: raise HTTPException(404, "Kullanıcı bulunamadı") user = db[email] today = date.today().isoformat() if user["last_reset"] != today: user["count"] = 0 user["last_reset"] = today save_db(db) return { "email": email, "used_today": user["count"], "remaining_today": DAILY_LIMIT - user["count"], "total_used": user["total"], "last_reset": user["last_reset"], "created": user.get("created", "unknown") } @app.get("/api/reset/{email}") async def reset_limit(email: str): """Limit sıfırlama (test için)""" email = email.strip().lower() db = load_db() if email in db: db[email]["count"] = 0 db[email]["last_reset"] = date.today().isoformat() save_db(db) return {"status": "success", "message": f"{email} limiti sıfırlandı"} else: raise HTTPException(404, "Kullanıcı bulunamadı") @app.get("/api/info") async def api_info(): """API bilgileri""" return { "api_name": "AI Chat API", "version": "2.0.0", "model": MODEL_NAME, "server_ip": SERVER_IP, "port": SERVER_PORT, "base_url": f"http://{SERVER_IP}:{SERVER_PORT}", "endpoints": { "home": "/", "test_ui": "/test", "chat": "POST /api/chat", "health": "GET /health", "stats": "GET /api/stats/{email}", "reset": "GET /api/reset/{email}", "docs": "/docs" } } if __name__ == "__main__": import uvicorn logger.info("=" * 60) logger.info("🤖 AI Chat API Başlatılıyor...") logger.info(f"📡 Sunucu IP: {SERVER_IP}") logger.info(f"🔌 Port: {SERVER_PORT}") logger.info(f"🧠 Model: {MODEL_NAME}") logger.info(f"🔑 Token: {'✅ Var' if HF_TOKEN else '❌ Yok'}") logger.info(f"📊 Günlük Limit: {DAILY_LIMIT}") logger.info("=" * 60) logger.info("📱 Telefon bağlantıları:") logger.info(f" • Test Arayüzü: http://{SERVER_IP}:{SERVER_PORT}/test") logger.info(f" • API Doküman: http://{SERVER_IP}:{SERVER_PORT}/docs") logger.info(f" • Health Check: http://{SERVER_IP}:{SERVER_PORT}/health") logger.info("=" * 60) # Uvicorn'u başlat uvicorn.run( app, host="0.0.0.0", # Tüm ağlardan erişime izin ver port=SERVER_PORT, reload=True, log_level="info", access_log=True )