from flask import Flask, request, jsonify, render_template import os import uuid import time import threading import tiktoken from datetime import datetime, timedelta from collections import defaultdict, deque from detoxify import Detoxify import logging # Flask'in varsayılan logger'ını daha iyi kullanmak için yapılandırma logging.basicConfig(level=logging.INFO) app = Flask(__name__, static_folder='static', template_folder='templates') print("Loading Detoxify model... This may take a moment.") detoxify_model = Detoxify('multilingual') print("Model loaded successfully.") # --- Geliştirilmiş Metrik Takip Sistemi --- request_durations = deque(maxlen=100) request_timestamps = deque(maxlen=1000) daily_requests = defaultdict(int) daily_tokens = defaultdict(int) concurrent_requests = 0 concurrent_requests_lock = threading.Lock() encoding = tiktoken.get_encoding("cl100k_base") def count_tokens(text): return len(encoding.encode(text)) def transform_predictions(prediction_dict): category_keys = [ "toxicity", "severe_toxicity", "obscene", "threat", "insult", "identity_attack", "sexual_explicit" ] scores = {} for key in category_keys: scores[key] = float(prediction_dict.get(key, 0.0)) threshold = 0.5 bool_categories = {key: (scores[key] > threshold) for key in category_keys} flagged = any(bool_categories.values()) return flagged, bool_categories, scores def track_request_metrics(start_time, tokens_count): end_time = time.time() duration = end_time - start_time # --- İSTEK ÜZERİNE GÜNCELLENEN KISIM --- # Sunucu taraflı işlem süresini milisaniye olarak terminale logla. # Bu log, arayüzdeki metriklerle tutarlı olacaktır. app.logger.info(f"Server-side processing for moderation request took {duration * 1000:.2f} ms.") # ------------------------------------------ request_durations.append(duration) request_timestamps.append(datetime.now()) today = datetime.now().strftime("%Y-%m-%d") daily_requests[today] += 1 daily_tokens[today] += tokens_count def get_performance_metrics(): global concurrent_requests with concurrent_requests_lock: current_concurrent = concurrent_requests if not request_durations: avg_request_time = 0 peak_request_time = 0 else: avg_request_time = sum(request_durations) / len(request_durations) peak_request_time = max(request_durations) now = datetime.now() one_minute_ago = now - timedelta(seconds=60) requests_last_minute = sum(1 for ts in request_timestamps if ts > one_minute_ago) today = now.strftime("%Y-%m-%d") today_requests = daily_requests.get(today, 0) today_tokens = daily_tokens.get(today, 0) last_7_days = [] for i in range(7): date = (now - timedelta(days=i)).strftime("%Y-%m-%d") last_7_days.append({ "date": date, "requests": daily_requests.get(date, 0), "tokens": daily_tokens.get(date, 0) }) return { "avg_request_time_ms": avg_request_time * 1000, "peak_request_time_ms": peak_request_time * 1000, "requests_per_minute": requests_last_minute, "concurrent_requests": current_concurrent, "today_requests": today_requests, "today_tokens": today_tokens, "last_7_days": last_7_days } @app.route('/') def home(): return render_template('index.html') @app.route('/v1/moderations', methods=['POST']) def moderations(): global concurrent_requests with concurrent_requests_lock: concurrent_requests += 1 start_time = time.time() total_tokens = 0 response = None try: data = request.get_json() raw_input = data.get('input') if raw_input is None: response = jsonify({"error": "Invalid input, 'input' field is required"}), 400 return response if isinstance(raw_input, str): texts = [raw_input] elif isinstance(raw_input, list): texts = raw_input else: response = jsonify({"error": "Invalid input format, expected string or list of strings"}), 400 return response if not texts: response = jsonify({"error": "Input list cannot be empty"}), 400 return response if len(texts) > 10: response = jsonify({"error": "Too many input items. Maximum 10 allowed."}), 400 return response for text in texts: if not isinstance(text, str) or len(text.encode('utf-8')) > 300000: response = jsonify({"error": "Each input item must be a string with a maximum of 300k bytes."}), 400 return response total_tokens += count_tokens(text) predictions = detoxify_model.predict(texts) results = [] for i in range(len(texts)): single_prediction = {key: value[i] for key, value in predictions.items()} flagged, bool_categories, scores = transform_predictions(single_prediction) results.append({ "flagged": flagged, "categories": bool_categories, "category_scores": scores, }) response_data = { "id": "modr-" + uuid.uuid4().hex[:24], "model": "text-moderation-detoxify-multilingual", "results": results } response = jsonify(response_data) return response except Exception as e: app.logger.error(f"An error occurred: {e}", exc_info=True) response = jsonify({"error": "An internal server error occurred."}), 500 return response finally: # Bu blok her zaman çalışır, response döndürülmeden hemen önce if response and response.status_code < 400: # Sadece başarılı istekleri metrikler için takip et track_request_metrics(start_time, total_tokens) with concurrent_requests_lock: concurrent_requests -= 1 @app.route('/v1/metrics', methods=['GET']) def metrics(): return jsonify(get_performance_metrics()) def create_directories_and_files(): # Bu fonksiyon HTML/CSS içeriği değişmediği için aynı kalabilir. os.makedirs('templates', exist_ok=True) os.makedirs('static', exist_ok=True) index_path = os.path.join('templates', 'index.html') if not os.path.exists(index_path): with open(index_path, 'w', encoding='utf-8') as f: f.write(''' Text Moderation API

Text Moderation API

Performance Metrics

Avg. Response (last 100)

0ms

Requests / Minute

0

Peak Response (last 100)

0ms

Today's Requests

0

Last 7 Days Activity

API Tester

Maximum 10 text inputs allowed

API Documentation

Endpoint

POST /v1/moderations

Request Body

{
  "input": "Text to moderate" 
}

Response

{
  "id": "modr-1234567890abcdef",
  "model": "text-moderation-detoxify-multilingual",
  "results": [
    {
      "flagged": true,
      "categories": {
        "toxicity": true,
        "severe_toxicity": false,
        /* ... other categories */
      },
      "category_scores": {
        "toxicity": 0.95,
        "severe_toxicity": 0.1,
        /* ... other scores */
      }
    }
  ]
}
''') if __name__ == '__main__': create_directories_and_files() port = int(os.getenv('PORT', 7860)) app.run(host='0.0.0.0', port=port, debug=True, use_reloader=False)