Zenkad commited on
Commit
5051bf7
·
verified ·
1 Parent(s): ef509a8

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +380 -33
app.py CHANGED
@@ -5,110 +5,457 @@ import json
5
  import os
6
  from datetime import datetime, date
7
  import requests
 
8
 
9
- app = FastAPI()
10
- app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"])
 
11
 
 
 
 
 
 
 
 
 
 
 
 
12
  DB_PATH = "users.json"
13
  HF_TOKEN = os.getenv("HF_TOKEN", "")
 
 
 
 
 
 
14
 
15
  def load_db():
 
16
  try:
17
  if os.path.exists(DB_PATH):
18
- with open(DB_PATH, "r") as f:
19
  return json.load(f)
20
- except:
 
21
  return {}
22
  return {}
23
 
24
  def save_db(data):
 
25
  try:
26
- with open(DB_PATH, "w") as f:
27
- json.dump(data, f, indent=2)
28
- except:
29
- pass
 
 
30
 
31
- def get_model_response(message):
32
- """Model yanıtı"""
33
  if not HF_TOKEN:
34
- return "Model hazır değil."
 
35
 
36
  try:
 
 
 
37
  response = requests.post(
38
- "https://api-inference.huggingface.co/models/mistralai/Mistral-7B-Instruct-v0.2",
39
- headers={"Authorization": f"Bearer {HF_TOKEN}"},
 
 
 
40
  json={
41
- "inputs": message,
42
- "parameters": {"max_new_tokens": 100}
 
 
 
 
 
 
43
  },
44
  timeout=30
45
  )
46
 
 
 
47
  if response.status_code == 200:
48
  result = response.json()
 
 
 
49
  if isinstance(result, list):
50
- return result[0].get('generated_text', 'Yanıt alınamadı')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
 
52
- return "Model yanıt veremedi."
 
53
 
54
- except:
55
- return "Model hatası."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
 
57
  @app.get("/")
58
  def home():
59
- return {"status": "ok"}
 
 
 
 
 
 
 
 
 
 
60
 
61
  @app.get("/health")
62
  def health():
 
 
 
 
63
  return {
64
- "status": "healthy",
65
- "model": "ready" if HF_TOKEN else "no_token",
66
- "time": datetime.now().isoformat()
 
 
 
67
  }
68
 
69
  @app.post("/api/chat")
70
  async def chat(request: Request):
 
71
  try:
72
  data = await request.json()
73
  email = data.get("email", "").strip().lower()
74
  message = data.get("message", "").strip()
75
 
 
 
 
76
  if not email or "@" not in email:
77
- return JSONResponse(400, {"error": "Email required"})
 
 
 
78
 
79
  if not message:
80
- return JSONResponse(400, {"error": "Message required"})
 
 
 
 
 
 
 
 
 
81
 
 
82
  db = load_db()
 
83
 
84
  if email not in db:
85
  db[email] = {
86
  "count": 0,
87
  "total": 0,
88
- "last_reset": date.today().isoformat()
 
 
89
  }
90
 
91
  user = db[email]
92
 
93
- if user["last_reset"] != date.today().isoformat():
 
94
  user["count"] = 0
95
- user["last_reset"] = date.today().isoformat()
96
 
97
- if user["count"] >= 100:
98
- return JSONResponse(429, {"error": "Daily limit reached"})
 
 
 
 
 
 
 
99
 
100
- # Model yanıtı
 
101
  ai_response = get_model_response(message)
 
102
 
 
 
 
103
  user["count"] += 1
104
  user["total"] += 1
 
 
 
105
  save_db(db)
106
 
 
107
  return {
108
  "response": ai_response,
109
  "status": "success",
110
- "remaining": 100 - user["count"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
  }
112
 
113
  except Exception as e:
114
- return JSONResponse(500, {"error": str(e)})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  import os
6
  from datetime import datetime, date
7
  import requests
8
+ import logging
9
 
10
+ # Logging ayarı
11
+ logging.basicConfig(level=logging.INFO)
12
+ logger = logging.getLogger(__name__)
13
 
14
+ app = FastAPI(title="AI Chat API", version="1.0.0")
15
+
16
+ # CORS ayarları
17
+ app.add_middleware(
18
+ CORSMiddleware,
19
+ allow_origins=["*"],
20
+ allow_methods=["*"],
21
+ allow_headers=["*"],
22
+ )
23
+
24
+ # Dosya yolları ve konfigürasyon
25
  DB_PATH = "users.json"
26
  HF_TOKEN = os.getenv("HF_TOKEN", "")
27
+ MODEL_NAME = "mistralai/Mistral-7B-Instruct-v0.2"
28
+ API_URL = f"https://api-inference.huggingface.co/models/{MODEL_NAME}"
29
+
30
+ # Varsayılan limitler
31
+ DAILY_LIMIT = 100
32
+ MAX_TOKENS = 200
33
 
34
  def load_db():
35
+ """Kullanıcı veritabanını yükle"""
36
  try:
37
  if os.path.exists(DB_PATH):
38
+ with open(DB_PATH, "r", encoding="utf-8") as f:
39
  return json.load(f)
40
+ except Exception as e:
41
+ logger.error(f"Veritabanı yükleme hatası: {e}")
42
  return {}
43
  return {}
44
 
45
  def save_db(data):
46
+ """Kullanıcı veritabanını kaydet"""
47
  try:
48
+ with open(DB_PATH, "w", encoding="utf-8") as f:
49
+ json.dump(data, f, indent=2, ensure_ascii=False)
50
+ return True
51
+ except Exception as e:
52
+ logger.error(f"Veritabanı kaydetme hatası: {e}")
53
+ return False
54
 
55
+ def get_model_response_v1(message):
56
+ """Model yanıtı - V1 (Daha basit format)"""
57
  if not HF_TOKEN:
58
+ logger.warning("HF_TOKEN bulunamadı")
59
+ return "API token bulunamadı. Lütfen HF_TOKEN ortam değişkenini ayarlayın."
60
 
61
  try:
62
+ # Mistral için uygun prompt formatı
63
+ formatted_prompt = f"<s>[INST] {message} [/INST]"
64
+
65
  response = requests.post(
66
+ API_URL,
67
+ headers={
68
+ "Authorization": f"Bearer {HF_TOKEN}",
69
+ "Content-Type": "application/json"
70
+ },
71
  json={
72
+ "inputs": formatted_prompt,
73
+ "parameters": {
74
+ "max_new_tokens": MAX_TOKENS,
75
+ "temperature": 0.7,
76
+ "top_p": 0.95,
77
+ "do_sample": True,
78
+ "return_full_text": False
79
+ }
80
  },
81
  timeout=30
82
  )
83
 
84
+ logger.info(f"API Yanıt Kodu: {response.status_code}")
85
+
86
  if response.status_code == 200:
87
  result = response.json()
88
+ logger.info(f"API Yanıtı: {result}")
89
+
90
+ # Farklı response formatlarını işle
91
  if isinstance(result, list):
92
+ if len(result) > 0:
93
+ if isinstance(result[0], dict):
94
+ # Format 1: [{'generated_text': '...'}]
95
+ if 'generated_text' in result[0]:
96
+ text = result[0]['generated_text']
97
+ # Prompt'u temizle
98
+ if isinstance(text, str):
99
+ text = text.replace(formatted_prompt, "").strip()
100
+ return text
101
+
102
+ # Format 2: [{'generated_text': [{'content': '...'}]}]
103
+ for key in result[0]:
104
+ if isinstance(result[0][key], str):
105
+ text = result[0][key]
106
+ text = text.replace(formatted_prompt, "").strip()
107
+ return text
108
+
109
+ # Direk string dönerse
110
+ if isinstance(result, str):
111
+ return result.replace(formatted_prompt, "").strip()
112
+
113
+ return "Yanıt alındı ancak format beklenmiyor."
114
+
115
+ elif response.status_code == 503:
116
+ logger.warning("Model yükleniyor...")
117
+ return "Model şu anda yükleniyor, lütfen 10-20 saniye sonra tekrar deneyin."
118
+
119
+ elif response.status_code == 429:
120
+ return "Çok fazla istek gönderildi. Lütfen bir süre bekleyin."
121
 
122
+ elif response.status_code == 401:
123
+ return "API token geçersiz. Lütfen token'ı kontrol edin."
124
 
125
+ else:
126
+ logger.error(f"API Hatası: {response.status_code} - {response.text[:200]}")
127
+ return f"API hatası: {response.status_code}"
128
+
129
+ except requests.exceptions.Timeout:
130
+ logger.error("API timeout hatası")
131
+ return "Model yanıt verme süresi aşıldı. Lütfen daha sonra tekrar deneyin."
132
+
133
+ except requests.exceptions.ConnectionError:
134
+ logger.error("API bağlantı hatası")
135
+ return "API'ye bağlanılamadı. Lütfen internet bağlantınızı kontrol edin."
136
+
137
+ except Exception as e:
138
+ logger.error(f"Model iletişim hatası: {str(e)}")
139
+ return f"Beklenmeyen hata: {str(e)}"
140
+
141
+ def get_model_response_v2(message):
142
+ """Model yanıtı - V2 (Alternatif yaklaşım)"""
143
+ if not HF_TOKEN:
144
+ return "API token bulunamadı."
145
+
146
+ try:
147
+ # Daha basit prompt formatı
148
+ formatted_prompt = f"Kullanıcı: {message}\nAsistan:"
149
+
150
+ response = requests.post(
151
+ API_URL,
152
+ headers={"Authorization": f"Bearer {HF_TOKEN}"},
153
+ json={
154
+ "inputs": formatted_prompt,
155
+ "parameters": {
156
+ "max_new_tokens": 150,
157
+ "temperature": 0.8,
158
+ "top_k": 50,
159
+ "return_full_text": False
160
+ }
161
+ },
162
+ timeout=25
163
+ )
164
+
165
+ if response.status_code == 200:
166
+ result = response.json()
167
+
168
+ # Basit format çözümleme
169
+ if isinstance(result, list):
170
+ for item in result:
171
+ if isinstance(item, dict):
172
+ for key, value in item.items():
173
+ if isinstance(value, str):
174
+ # Prompt'u temizle
175
+ cleaned = value.replace(formatted_prompt, "").strip()
176
+ if cleaned:
177
+ return cleaned
178
+ elif isinstance(value, list):
179
+ for sub_item in value:
180
+ if isinstance(sub_item, dict) and 'content' in sub_item:
181
+ return sub_item['content']
182
+
183
+ return "Anlamlı bir yanıt alınamadı."
184
+
185
+ return "Model geçici olarak kullanılamıyor."
186
+
187
+ except Exception:
188
+ return "Bağlantı hatası oluştu."
189
+
190
+ def get_model_response_v3(message):
191
+ """Model yanıtı - V3 (En basit)"""
192
+ if not HF_TOKEN:
193
+ return "Sistem hazır değil. Lütfen daha sonra tekrar deneyin."
194
+
195
+ try:
196
+ # En basit yaklaşım
197
+ response = requests.post(
198
+ API_URL,
199
+ headers={"Authorization": f"Bearer {HF_TOKEN}"},
200
+ json={"inputs": message},
201
+ timeout=20
202
+ )
203
+
204
+ if response.status_code == 200:
205
+ result = response.json()
206
+
207
+ # Çok basit parsing
208
+ if isinstance(result, list):
209
+ return str(result[0]) if result else "Boş yanıt"
210
+ elif isinstance(result, dict):
211
+ for value in result.values():
212
+ if isinstance(value, str) and value.strip():
213
+ return value.strip()
214
+
215
+ return "Yanıt işlenemedi"
216
+
217
+ return f"Hata kodu: {response.status_code}"
218
+
219
+ except Exception:
220
+ return "Servis geçici olarak kullanılamıyor."
221
+
222
+ def get_model_response(message):
223
+ """Ana model yanıt fonksiyonu - Tüm versiyonları dener"""
224
+ logger.info(f"Gelen mesaj: {message}")
225
+
226
+ # Versiyonları sırayla dene
227
+ responses = []
228
+
229
+ # V1'i dene
230
+ response_v1 = get_model_response_v1(message)
231
+ if response_v1 and len(response_v1) > 10 and "token" not in response_v1.lower() and "hata" not in response_v1.lower():
232
+ return response_v1
233
+ responses.append(response_v1)
234
+
235
+ # V2'yi dene
236
+ response_v2 = get_model_response_v2(message)
237
+ if response_v2 and len(response_v2) > 10 and "token" not in response_v2.lower() and "hata" not in response_v2.lower():
238
+ return response_v2
239
+ responses.append(response_v2)
240
+
241
+ # V3'ü dene
242
+ response_v3 = get_model_response_v3(message)
243
+ if response_v3 and len(response_v3) > 10:
244
+ return response_v3
245
+
246
+ # Hiçbiri çalışmazsa en iyi yanıtı seç
247
+ for resp in responses:
248
+ if resp and len(resp) > 5:
249
+ return resp
250
+
251
+ return "Üzgünüm, şu anda yanıt veremiyorum. Lütfen daha sonra tekrar deneyin."
252
 
253
  @app.get("/")
254
  def home():
255
+ """Ana sayfa"""
256
+ return {
257
+ "app": "AI Chat API",
258
+ "version": "1.0.0",
259
+ "status": "active",
260
+ "endpoints": {
261
+ "health": "/health",
262
+ "chat": "/api/chat (POST)",
263
+ "stats": "/api/stats/{email} (GET)"
264
+ }
265
+ }
266
 
267
  @app.get("/health")
268
  def health():
269
+ """Sağlık kontrolü"""
270
+ token_status = "valid" if HF_TOKEN else "missing"
271
+ db_status = "exists" if os.path.exists(DB_PATH) else "missing"
272
+
273
  return {
274
+ "status": "healthy",
275
+ "timestamp": datetime.now().isoformat(),
276
+ "token": token_status,
277
+ "database": db_status,
278
+ "model": MODEL_NAME,
279
+ "daily_limit": DAILY_LIMIT
280
  }
281
 
282
  @app.post("/api/chat")
283
  async def chat(request: Request):
284
+ """Chat endpoint'i"""
285
  try:
286
  data = await request.json()
287
  email = data.get("email", "").strip().lower()
288
  message = data.get("message", "").strip()
289
 
290
+ logger.info(f"Chat isteği - Email: {email}, Mesaj: {message[:50]}...")
291
+
292
+ # Validasyon
293
  if not email or "@" not in email:
294
+ return JSONResponse(
295
+ status_code=400,
296
+ content={"error": "Geçerli bir email adresi giriniz."}
297
+ )
298
 
299
  if not message:
300
+ return JSONResponse(
301
+ status_code=400,
302
+ content={"error": "Mesaj boş olamaz."}
303
+ )
304
+
305
+ if len(message) > 1000:
306
+ return JSONResponse(
307
+ status_code=400,
308
+ content={"error": "Mesaj çok uzun. Maksimum 1000 karakter."}
309
+ )
310
 
311
+ # Veritabanı işlemleri
312
  db = load_db()
313
+ today = date.today().isoformat()
314
 
315
  if email not in db:
316
  db[email] = {
317
  "count": 0,
318
  "total": 0,
319
+ "last_reset": today,
320
+ "created_at": datetime.now().isoformat(),
321
+ "last_used": datetime.now().isoformat()
322
  }
323
 
324
  user = db[email]
325
 
326
+ # Günlük limit kontrolü
327
+ if user["last_reset"] != today:
328
  user["count"] = 0
329
+ user["last_reset"] = today
330
 
331
+ if user["count"] >= DAILY_LIMIT:
332
+ return JSONResponse(
333
+ status_code=429,
334
+ content={
335
+ "error": "Günlük limit doldu",
336
+ "limit": DAILY_LIMIT,
337
+ "reset_date": today
338
+ }
339
+ )
340
 
341
+ # Model yanıtını al
342
+ start_time = datetime.now()
343
  ai_response = get_model_response(message)
344
+ response_time = (datetime.now() - start_time).total_seconds()
345
 
346
+ logger.info(f"Yanıt süresi: {response_time:.2f}s")
347
+
348
+ # Kullanıcı istatistiklerini güncelle
349
  user["count"] += 1
350
  user["total"] += 1
351
+ user["last_used"] = datetime.now().isoformat()
352
+
353
+ # Veritabanını kaydet
354
  save_db(db)
355
 
356
+ # Yanıt
357
  return {
358
  "response": ai_response,
359
  "status": "success",
360
+ "remaining": DAILY_LIMIT - user["count"],
361
+ "used_today": user["count"],
362
+ "total_used": user["total"],
363
+ "response_time": f"{response_time:.2f}s"
364
+ }
365
+
366
+ except json.JSONDecodeError:
367
+ return JSONResponse(
368
+ status_code=400,
369
+ content={"error": "Geçersiz JSON formatı"}
370
+ )
371
+
372
+ except Exception as e:
373
+ logger.error(f"Chat hatası: {str(e)}")
374
+ return JSONResponse(
375
+ status_code=500,
376
+ content={"error": f"Sunucu hatası: {str(e)}"}
377
+ )
378
+
379
+ @app.get("/api/stats/{email}")
380
+ def get_stats(email: str):
381
+ """Kullanıcı istatistiklerini getir"""
382
+ try:
383
+ email = email.strip().lower()
384
+ db = load_db()
385
+
386
+ if email not in db:
387
+ return JSONResponse(
388
+ status_code=404,
389
+ content={"error": "Kullanıcı bulunamadı"}
390
+ )
391
+
392
+ user = db[email]
393
+ today = date.today().isoformat()
394
+
395
+ # Günlük limit sıfırlama kontrolü
396
+ if user["last_reset"] != today:
397
+ user["count"] = 0
398
+ user["last_reset"] = today
399
+ save_db(db)
400
+
401
+ return {
402
+ "email": email,
403
+ "used_today": user["count"],
404
+ "remaining_today": DAILY_LIMIT - user["count"],
405
+ "total_used": user["total"],
406
+ "last_reset": user["last_reset"],
407
+ "last_used": user.get("last_used", "never"),
408
+ "created_at": user.get("created_at", "unknown")
409
  }
410
 
411
  except Exception as e:
412
+ return JSONResponse(
413
+ status_code=500,
414
+ content={"error": str(e)}
415
+ )
416
+
417
+ @app.get("/api/reset-test/{email}")
418
+ def reset_test(email: str):
419
+ """Test için kullanıcı limitini sıfırla"""
420
+ try:
421
+ email = email.strip().lower()
422
+ db = load_db()
423
+
424
+ if email in db:
425
+ db[email]["count"] = 0
426
+ db[email]["last_reset"] = date.today().isoformat()
427
+ save_db(db)
428
+
429
+ return {
430
+ "status": "success",
431
+ "message": f"{email} limiti sıfırlandı"
432
+ }
433
+ else:
434
+ return JSONResponse(
435
+ status_code=404,
436
+ content={"error": "Kullanıcı bulunamadı"}
437
+ )
438
+
439
+ except Exception as e:
440
+ return JSONResponse(
441
+ status_code=500,
442
+ content={"error": str(e)}
443
+ )
444
+
445
+ if __name__ == "__main__":
446
+ import uvicorn
447
+
448
+ logger.info("=" * 50)
449
+ logger.info("AI Chat API Başlatılıyor...")
450
+ logger.info(f"Model: {MODEL_NAME}")
451
+ logger.info(f"Token Durumu: {'Var' if HF_TOKEN else 'Yok'}")
452
+ logger.info(f"Günlük Limit: {DAILY_LIMIT}")
453
+ logger.info("=" * 50)
454
+
455
+ uvicorn.run(
456
+ "app:app",
457
+ host="0.0.0.0",
458
+ port=8000,
459
+ reload=True,
460
+ log_level="info"
461
+ )