Utiric commited on
Commit
36026df
·
verified ·
1 Parent(s): bb1a9b2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +43 -29
app.py CHANGED
@@ -7,6 +7,10 @@ import tiktoken
7
  from datetime import datetime, timedelta
8
  from collections import defaultdict, deque
9
  from detoxify import Detoxify
 
 
 
 
10
 
11
  app = Flask(__name__, static_folder='static', template_folder='templates')
12
 
@@ -17,9 +21,7 @@ print("Model loaded successfully.")
17
  API_KEY = os.getenv('API_KEY', 'your-api-key-here')
18
 
19
  # --- Geliştirilmiş Metrik Takip Sistemi ---
20
- # Son 100 isteğin süresini tutarak daha dinamik bir ortalama elde ederiz
21
  request_durations = deque(maxlen=100)
22
- # Son 10 dakika içindeki isteklerin zaman damgalarını tutarak RPM hesaplarız
23
  request_timestamps = deque(maxlen=1000)
24
 
25
  daily_requests = defaultdict(int)
@@ -40,20 +42,24 @@ def transform_predictions(prediction_dict):
40
 
41
  scores = {}
42
  for key in category_keys:
43
- # Değerleri float'a çevirerek JSON uyumluluğunu garantiliyoruz
44
  scores[key] = float(prediction_dict.get(key, 0.0))
45
 
46
  threshold = 0.5
47
  bool_categories = {key: (scores[key] > threshold) for key in category_keys}
48
- cat_applied_input_types = {key: (["text"] if scores[key] > 0 else []) for key in category_keys}
49
  flagged = any(bool_categories.values())
50
 
51
- return flagged, bool_categories, scores, cat_applied_input_types
52
 
53
  def track_request_metrics(start_time, tokens_count):
54
  end_time = time.time()
55
  duration = end_time - start_time
56
 
 
 
 
 
 
 
57
  request_durations.append(duration)
58
  request_timestamps.append(datetime.now())
59
 
@@ -66,7 +72,6 @@ def get_performance_metrics():
66
  with concurrent_requests_lock:
67
  current_concurrent = concurrent_requests
68
 
69
- # Ortalama ve Zirve Yanıt Süresi (Son 100 istek üzerinden)
70
  if not request_durations:
71
  avg_request_time = 0
72
  peak_request_time = 0
@@ -74,7 +79,6 @@ def get_performance_metrics():
74
  avg_request_time = sum(request_durations) / len(request_durations)
75
  peak_request_time = max(request_durations)
76
 
77
- # RPM (Requests Per Minute) - Dakikadaki İstek Sayısı
78
  now = datetime.now()
79
  one_minute_ago = now - timedelta(seconds=60)
80
  requests_last_minute = sum(1 for ts in request_timestamps if ts > one_minute_ago)
@@ -116,46 +120,52 @@ def moderations():
116
  start_time = time.time()
117
  total_tokens = 0
118
 
 
119
  try:
120
  auth_header = request.headers.get('Authorization')
121
  if not auth_header or not auth_header.startswith("Bearer "):
122
- return jsonify({"error": "Unauthorized"}), 401
 
123
 
124
  provided_api_key = auth_header.split(" ")[1]
125
  if provided_api_key != API_KEY:
126
- return jsonify({"error": "Unauthorized"}), 401
 
127
 
128
  data = request.get_json()
129
  raw_input = data.get('input')
130
 
131
  if raw_input is None:
132
- return jsonify({"error": "Invalid input, 'input' field is required"}), 400
 
133
 
134
  if isinstance(raw_input, str):
135
  texts = [raw_input]
136
  elif isinstance(raw_input, list):
137
  texts = raw_input
138
  else:
139
- return jsonify({"error": "Invalid input format, expected string or list of strings"}), 400
 
140
 
141
  if not texts:
142
- return jsonify({"error": "Input list cannot be empty"}), 400
 
143
 
144
  if len(texts) > 10:
145
- return jsonify({"error": "Too many input items. Maximum 10 allowed."}), 400
 
146
 
147
  for text in texts:
148
  if not isinstance(text, str) or len(text.encode('utf-8')) > 300000:
149
- return jsonify({"error": "Each input item must be a string with a maximum of 300k bytes."}), 400
 
150
  total_tokens += count_tokens(text)
151
 
152
- results = []
153
- # Detoxify'a tüm listeyi tek seferde vermek performansı artırır
154
  predictions = detoxify_model.predict(texts)
155
- # Predictions'ı her metin için ayrı bir sözlüğe dönüştür
156
  for i in range(len(texts)):
157
  single_prediction = {key: value[i] for key, value in predictions.items()}
158
- flagged, bool_categories, scores, cat_applied_input_types = transform_predictions(single_prediction)
159
 
160
  results.append({
161
  "flagged": flagged,
@@ -163,20 +173,25 @@ def moderations():
163
  "category_scores": scores,
164
  })
165
 
166
- track_request_metrics(start_time, total_tokens)
167
-
168
  response_data = {
169
  "id": "modr-" + uuid.uuid4().hex[:24],
170
  "model": "text-moderation-detoxify-multilingual",
171
  "results": results
172
  }
173
 
174
- return jsonify(response_data)
 
175
 
176
  except Exception as e:
177
- print(f"An error occurred: {e}")
178
- return jsonify({"error": "An internal server error occurred."}), 500
 
179
  finally:
 
 
 
 
 
180
  with concurrent_requests_lock:
181
  concurrent_requests -= 1
182
 
@@ -193,6 +208,7 @@ def metrics():
193
  return jsonify(get_performance_metrics())
194
 
195
  def create_directories_and_files():
 
196
  os.makedirs('templates', exist_ok=True)
197
  os.makedirs('static', exist_ok=True)
198
 
@@ -384,7 +400,7 @@ def create_directories_and_files():
384
  <div class="flex justify-between items-center mb-4">
385
  <h3 class="text-lg font-semibold">Summary</h3>
386
  <div class="text-sm text-gray-500 dark:text-gray-400">
387
- <i class="fas fa-clock mr-1"></i> Response time: <span id="responseTime">0ms</span>
388
  </div>
389
  </div>
390
 
@@ -405,7 +421,7 @@ def create_directories_and_files():
405
  <h3 class="text-lg font-semibold mb-4">Request Body</h3>
406
  <div class="bg-gray-100 dark:bg-gray-700 p-4 rounded-lg mb-6 overflow-x-auto">
407
  <pre class="text-sm"><code>{
408
- "input": "Text to moderate"
409
  }</code></pre>
410
  </div>
411
  <h3 class="text-lg font-semibold mb-4">Response</h3>
@@ -441,6 +457,7 @@ def create_directories_and_files():
441
  </footer>
442
 
443
  <script>
 
444
  const darkModeToggle = document.getElementById('darkModeToggle');
445
  const html = document.documentElement;
446
 
@@ -647,7 +664,7 @@ def create_directories_and_files():
647
  initActivityChart();
648
  document.getElementById('refreshMetrics').addEventListener('click', fetchMetrics);
649
  fetchMetrics();
650
- setInterval(fetchMetrics, 15000); // Refresh metrics every 15 seconds
651
  });
652
  </script>
653
  </body>
@@ -656,7 +673,4 @@ def create_directories_and_files():
656
  if __name__ == '__main__':
657
  create_directories_and_files()
658
  port = int(os.getenv('PORT', 7860))
659
- # debug=True'yu production ortamında False yapın.
660
- # Modelin yüklenmesi uzun sürdüğü için `use_reloader=False` eklemek,
661
- # geliştirme sırasında her dosya değişikliğinde modeli tekrar yüklemesini engeller.
662
  app.run(host='0.0.0.0', port=port, debug=True, use_reloader=False)
 
7
  from datetime import datetime, timedelta
8
  from collections import defaultdict, deque
9
  from detoxify import Detoxify
10
+ import logging
11
+
12
+ # Flask'in varsayılan logger'ını daha iyi kullanmak için yapılandırma
13
+ logging.basicConfig(level=logging.INFO)
14
 
15
  app = Flask(__name__, static_folder='static', template_folder='templates')
16
 
 
21
  API_KEY = os.getenv('API_KEY', 'your-api-key-here')
22
 
23
  # --- Geliştirilmiş Metrik Takip Sistemi ---
 
24
  request_durations = deque(maxlen=100)
 
25
  request_timestamps = deque(maxlen=1000)
26
 
27
  daily_requests = defaultdict(int)
 
42
 
43
  scores = {}
44
  for key in category_keys:
 
45
  scores[key] = float(prediction_dict.get(key, 0.0))
46
 
47
  threshold = 0.5
48
  bool_categories = {key: (scores[key] > threshold) for key in category_keys}
 
49
  flagged = any(bool_categories.values())
50
 
51
+ return flagged, bool_categories, scores
52
 
53
  def track_request_metrics(start_time, tokens_count):
54
  end_time = time.time()
55
  duration = end_time - start_time
56
 
57
+ # --- İSTEK ÜZERİNE GÜNCELLENEN KISIM ---
58
+ # Sunucu taraflı işlem süresini milisaniye olarak terminale logla.
59
+ # Bu log, arayüzdeki metriklerle tutarlı olacaktır.
60
+ app.logger.info(f"Server-side processing for moderation request took {duration * 1000:.2f} ms.")
61
+ # ------------------------------------------
62
+
63
  request_durations.append(duration)
64
  request_timestamps.append(datetime.now())
65
 
 
72
  with concurrent_requests_lock:
73
  current_concurrent = concurrent_requests
74
 
 
75
  if not request_durations:
76
  avg_request_time = 0
77
  peak_request_time = 0
 
79
  avg_request_time = sum(request_durations) / len(request_durations)
80
  peak_request_time = max(request_durations)
81
 
 
82
  now = datetime.now()
83
  one_minute_ago = now - timedelta(seconds=60)
84
  requests_last_minute = sum(1 for ts in request_timestamps if ts > one_minute_ago)
 
120
  start_time = time.time()
121
  total_tokens = 0
122
 
123
+ response = None
124
  try:
125
  auth_header = request.headers.get('Authorization')
126
  if not auth_header or not auth_header.startswith("Bearer "):
127
+ response = jsonify({"error": "Unauthorized"}), 401
128
+ return response
129
 
130
  provided_api_key = auth_header.split(" ")[1]
131
  if provided_api_key != API_KEY:
132
+ response = jsonify({"error": "Unauthorized"}), 401
133
+ return response
134
 
135
  data = request.get_json()
136
  raw_input = data.get('input')
137
 
138
  if raw_input is None:
139
+ response = jsonify({"error": "Invalid input, 'input' field is required"}), 400
140
+ return response
141
 
142
  if isinstance(raw_input, str):
143
  texts = [raw_input]
144
  elif isinstance(raw_input, list):
145
  texts = raw_input
146
  else:
147
+ response = jsonify({"error": "Invalid input format, expected string or list of strings"}), 400
148
+ return response
149
 
150
  if not texts:
151
+ response = jsonify({"error": "Input list cannot be empty"}), 400
152
+ return response
153
 
154
  if len(texts) > 10:
155
+ response = jsonify({"error": "Too many input items. Maximum 10 allowed."}), 400
156
+ return response
157
 
158
  for text in texts:
159
  if not isinstance(text, str) or len(text.encode('utf-8')) > 300000:
160
+ response = jsonify({"error": "Each input item must be a string with a maximum of 300k bytes."}), 400
161
+ return response
162
  total_tokens += count_tokens(text)
163
 
 
 
164
  predictions = detoxify_model.predict(texts)
165
+ results = []
166
  for i in range(len(texts)):
167
  single_prediction = {key: value[i] for key, value in predictions.items()}
168
+ flagged, bool_categories, scores = transform_predictions(single_prediction)
169
 
170
  results.append({
171
  "flagged": flagged,
 
173
  "category_scores": scores,
174
  })
175
 
 
 
176
  response_data = {
177
  "id": "modr-" + uuid.uuid4().hex[:24],
178
  "model": "text-moderation-detoxify-multilingual",
179
  "results": results
180
  }
181
 
182
+ response = jsonify(response_data)
183
+ return response
184
 
185
  except Exception as e:
186
+ app.logger.error(f"An error occurred: {e}", exc_info=True)
187
+ response = jsonify({"error": "An internal server error occurred."}), 500
188
+ return response
189
  finally:
190
+ # Bu blok her zaman çalışır, response döndürülmeden hemen önce
191
+ if response and response.status_code < 400:
192
+ # Sadece başarılı istekleri metrikler için takip et
193
+ track_request_metrics(start_time, total_tokens)
194
+
195
  with concurrent_requests_lock:
196
  concurrent_requests -= 1
197
 
 
208
  return jsonify(get_performance_metrics())
209
 
210
  def create_directories_and_files():
211
+ # Bu fonksiyon HTML/CSS içeriği değişmediği için aynı kalabilir.
212
  os.makedirs('templates', exist_ok=True)
213
  os.makedirs('static', exist_ok=True)
214
 
 
400
  <div class="flex justify-between items-center mb-4">
401
  <h3 class="text-lg font-semibold">Summary</h3>
402
  <div class="text-sm text-gray-500 dark:text-gray-400">
403
+ <i class="fas fa-stopwatch mr-1"></i> Round-trip time: <span id="responseTime">0ms</span>
404
  </div>
405
  </div>
406
 
 
421
  <h3 class="text-lg font-semibold mb-4">Request Body</h3>
422
  <div class="bg-gray-100 dark:bg-gray-700 p-4 rounded-lg mb-6 overflow-x-auto">
423
  <pre class="text-sm"><code>{
424
+ "input": "Text to moderate"
425
  }</code></pre>
426
  </div>
427
  <h3 class="text-lg font-semibold mb-4">Response</h3>
 
457
  </footer>
458
 
459
  <script>
460
+ // JS kodu değişmediği için aynı kalabilir.
461
  const darkModeToggle = document.getElementById('darkModeToggle');
462
  const html = document.documentElement;
463
 
 
664
  initActivityChart();
665
  document.getElementById('refreshMetrics').addEventListener('click', fetchMetrics);
666
  fetchMetrics();
667
+ setInterval(fetchMetrics, 15000);
668
  });
669
  </script>
670
  </body>
 
673
  if __name__ == '__main__':
674
  create_directories_and_files()
675
  port = int(os.getenv('PORT', 7860))
 
 
 
676
  app.run(host='0.0.0.0', port=port, debug=True, use_reloader=False)