Utiric commited on
Commit
4ad9ac6
·
verified ·
1 Parent(s): f192c7a

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +222 -3
index.html CHANGED
@@ -1,4 +1,216 @@
1
- <!DOCTYPE html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  <html lang="en">
3
  <head>
4
  <meta charset="UTF-8">
@@ -613,7 +825,7 @@
613
  ${flaggedBadge}
614
  </div>
615
  <div class="mb-4 p-3 bg-gray-50 dark:bg-gray-700 rounded-lg text-sm">
616
- ${data.input ? data.input[index] : 'Text content not available'}
617
  </div>
618
  <div class="category-card">
619
  <h5 class="font-medium mb-2">Categories</h5>
@@ -645,4 +857,11 @@
645
  });
646
  </script>
647
  </body>
648
- </html>
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, jsonify, render_template, send_from_directory
2
+ import os
3
+ import uuid
4
+ import time
5
+ import threading
6
+ 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
+
13
+ # Load the detoxify model
14
+ detoxify_model = Detoxify('multilingual')
15
+
16
+ # API key from environment variable
17
+ API_KEY = os.getenv('API_KEY', 'your-api-key-here')
18
+
19
+ # Performance metrics tracking
20
+ request_times = deque(maxlen=1000) # Store last 1000 request times
21
+ daily_requests = defaultdict(int)
22
+ daily_tokens = defaultdict(int)
23
+ concurrent_requests = 0
24
+ concurrent_requests_lock = threading.Lock()
25
+
26
+ # Token encoding for counting tokens
27
+ encoding = tiktoken.get_encoding("cl100k_base")
28
+
29
+ def count_tokens(text):
30
+ """Count tokens in the given text using tiktoken."""
31
+ return len(encoding.encode(text))
32
+
33
+ def transform_predictions(prediction_dict):
34
+ """
35
+ Transform predictions to OpenAI-style format.
36
+ Returns: flagged, categories, category_scores, category_applied_input_types
37
+ """
38
+ # Define the categories we want to track
39
+ category_keys = [
40
+ "toxicity", "severe_toxicity", "obscene", "threat",
41
+ "insult", "identity_attack", "sexual_explicit"
42
+ ]
43
+
44
+ # Map detoxify output to our categories
45
+ scores = {}
46
+ for key in category_keys:
47
+ scores[key] = prediction_dict.get(key, 0.0)
48
+
49
+ # Set threshold for flagging content
50
+ threshold = 0.5
51
+ bool_categories = {key: (scores[key] > threshold) for key in category_keys}
52
+ cat_applied_input_types = {key: (["text"] if scores[key] > 0 else []) for key in category_keys}
53
+ flagged = any(bool_categories.values())
54
+
55
+ return flagged, bool_categories, scores, cat_applied_input_types
56
+
57
+ def track_request_metrics(start_time, tokens_count):
58
+ """Track performance metrics for requests."""
59
+ end_time = time.time()
60
+ request_time = end_time - start_time
61
+ request_times.append(request_time)
62
+
63
+ today = datetime.now().strftime("%Y-%m-%d")
64
+ daily_requests[today] += 1
65
+ daily_tokens[today] += tokens_count
66
+
67
+ def get_performance_metrics():
68
+ """Get current performance metrics."""
69
+ global concurrent_requests
70
+ with concurrent_requests_lock:
71
+ current_concurrent = concurrent_requests
72
+
73
+ # Calculate average request time
74
+ avg_request_time = sum(request_times) / len(request_times) if request_times else 0
75
+
76
+ # Get today's date
77
+ today = datetime.now().strftime("%Y-%m-%d")
78
+
79
+ # Calculate requests per second (based on last 100 requests)
80
+ recent_requests = list(request_times)[-100:] if len(request_times) >= 100 else list(request_times)
81
+ requests_per_second = len(recent_requests) / sum(recent_requests) if recent_requests and sum(recent_requests) > 0 else 0
82
+
83
+ # Get daily stats
84
+ today_requests = daily_requests.get(today, 0)
85
+ today_tokens = daily_tokens.get(today, 0)
86
+
87
+ # Get last 7 days stats
88
+ last_7_days = []
89
+ for i in range(7):
90
+ date = (datetime.now() - timedelta(days=i)).strftime("%Y-%m-%d")
91
+ last_7_days.append({
92
+ "date": date,
93
+ "requests": daily_requests.get(date, 0),
94
+ "tokens": daily_tokens.get(date, 0)
95
+ })
96
+
97
+ return {
98
+ "avg_request_time": avg_request_time,
99
+ "requests_per_second": requests_per_second,
100
+ "concurrent_requests": current_concurrent,
101
+ "today_requests": today_requests,
102
+ "today_tokens": today_tokens,
103
+ "last_7_days": last_7_days
104
+ }
105
+
106
+ @app.route('/')
107
+ def home():
108
+ return render_template('index.html')
109
+
110
+ @app.route('/v1/moderations', methods=['POST'])
111
+ def moderations():
112
+ global concurrent_requests
113
+
114
+ # Track concurrent requests
115
+ with concurrent_requests_lock:
116
+ concurrent_requests += 1
117
+
118
+ start_time = time.time()
119
+ total_tokens = 0
120
+
121
+ try:
122
+ # Check authorization
123
+ auth_header = request.headers.get('Authorization')
124
+ if not auth_header or not auth_header.startswith("Bearer "):
125
+ return jsonify({"error": "Unauthorized"}), 401
126
+
127
+ provided_api_key = auth_header.split(" ")[1]
128
+ if provided_api_key != API_KEY:
129
+ return jsonify({"error": "Unauthorized"}), 401
130
+
131
+ # Get input data
132
+ data = request.get_json()
133
+ raw_input = data.get('input') or data.get('texts')
134
+
135
+ if raw_input is None:
136
+ return jsonify({"error": "Invalid input, expected 'input' or 'texts' field"}), 400
137
+
138
+ # Handle both string and list inputs
139
+ if isinstance(raw_input, str):
140
+ texts = [raw_input]
141
+ elif isinstance(raw_input, list):
142
+ texts = raw_input
143
+ else:
144
+ return jsonify({"error": "Invalid input format, expected string or list of strings"}), 400
145
+
146
+ # Validate input size
147
+ if len(texts) > 10:
148
+ return jsonify({"error": "Too many input items. Maximum 10 allowed."}), 400
149
+
150
+ for text in texts:
151
+ if not isinstance(text, str) or len(text) > 100000:
152
+ return jsonify({"error": "Each input item must be a string with a maximum of 100k characters."}), 400
153
+ total_tokens += count_tokens(text)
154
+
155
+ # Process each text
156
+ results = []
157
+ for text in texts:
158
+ pred = detoxify_model.predict([text])
159
+ prediction = {k: v[0] for k, v in pred.items()}
160
+ flagged, bool_categories, scores, cat_applied_input_types = transform_predictions(prediction)
161
+
162
+ results.append({
163
+ "flagged": flagged,
164
+ "categories": bool_categories,
165
+ "category_scores": scores,
166
+ "category_applied_input_types": cat_applied_input_types
167
+ })
168
+
169
+ # Track metrics
170
+ track_request_metrics(start_time, total_tokens)
171
+
172
+ # Prepare response
173
+ response_data = {
174
+ "id": "modr-" + uuid.uuid4().hex[:24],
175
+ "model": "unitaryai/detoxify-multilingual",
176
+ "results": results,
177
+ "object": "moderation",
178
+ "usage": {
179
+ "total_tokens": total_tokens
180
+ }
181
+ }
182
+
183
+ return jsonify(response_data)
184
+
185
+ finally:
186
+ # Decrement concurrent requests counter
187
+ with concurrent_requests_lock:
188
+ concurrent_requests -= 1
189
+
190
+ @app.route('/v1/metrics', methods=['GET'])
191
+ def metrics():
192
+ """Endpoint to get performance metrics."""
193
+ auth_header = request.headers.get('Authorization')
194
+ if not auth_header or not auth_header.startswith("Bearer "):
195
+ return jsonify({"error": "Unauthorized"}), 401
196
+
197
+ provided_api_key = auth_header.split(" ")[1]
198
+ if provided_api_key != API_KEY:
199
+ return jsonify({"error": "Unauthorized"}), 401
200
+
201
+ return jsonify(get_performance_metrics())
202
+
203
+ # Create a simple file-based approach for the HTML template
204
+ def create_directories_and_files():
205
+ """Create necessary directories and files if they don't exist."""
206
+ os.makedirs('templates', exist_ok=True)
207
+ os.makedirs('static', exist_ok=True)
208
+
209
+ # Create index.html if it doesn't exist
210
+ index_path = os.path.join('templates', 'index.html')
211
+ if not os.path.exists(index_path):
212
+ with open(index_path, 'w') as f:
213
+ f.write('''<!DOCTYPE html>
214
  <html lang="en">
215
  <head>
216
  <meta charset="UTF-8">
 
825
  ${flaggedBadge}
826
  </div>
827
  <div class="mb-4 p-3 bg-gray-50 dark:bg-gray-700 rounded-lg text-sm">
828
+ ${texts[index]}
829
  </div>
830
  <div class="category-card">
831
  <h5 class="font-medium mb-2">Categories</h5>
 
857
  });
858
  </script>
859
  </body>
860
+ </html>''')
861
+
862
+ if __name__ == '__main__':
863
+ # Create directories and files
864
+ create_directories_and_files()
865
+
866
+ port = int(os.getenv('PORT', 7860))
867
+ app.run(host='0.0.0.0', port=port, debug=True)