Spaces:
Running
Running
Jatin Mehra
commited on
Commit
·
4bf6c32
1
Parent(s):
431214c
feat: enhance API documentation with detailed endpoint descriptions and usage examples
Browse files- src/crawlgpt/ui/app.py +193 -18
src/crawlgpt/ui/app.py
CHANGED
@@ -1,9 +1,26 @@
|
|
1 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
from flask_cors import CORS
|
3 |
import asyncio
|
4 |
import time
|
5 |
from datetime import datetime
|
6 |
-
import json
|
7 |
import jwt
|
8 |
from functools import wraps
|
9 |
import os
|
@@ -14,7 +31,7 @@ from src.crawlgpt.core.database import save_chat_message, get_chat_history, dele
|
|
14 |
from src.crawlgpt.utils.monitoring import MetricsCollector, Metrics
|
15 |
from src.crawlgpt.utils.data_manager import DataManager
|
16 |
from src.crawlgpt.utils.content_validator import ContentValidator
|
17 |
-
from src.crawlgpt.ui.login import authenticate_user, create_user
|
18 |
|
19 |
app = Flask(__name__)
|
20 |
CORS(app)
|
@@ -35,8 +52,19 @@ user_sessions = {}
|
|
35 |
RATE_LIMIT = 10 # requests per minute
|
36 |
rate_limit_data = defaultdict(list) # stores timestamps of requests by user_id
|
37 |
|
38 |
-
# Rate limiter decorator for AI-intensive endpoints
|
39 |
def rate_limit(f):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
40 |
@wraps(f)
|
41 |
def decorated(current_user_id, *args, **kwargs):
|
42 |
# Get current time
|
@@ -80,8 +108,19 @@ def rate_limit(f):
|
|
80 |
|
81 |
return decorated
|
82 |
|
83 |
-
# Authentication decorator
|
84 |
def token_required(f):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
85 |
@wraps(f)
|
86 |
def decorated(*args, **kwargs):
|
87 |
token = None
|
@@ -108,14 +147,29 @@ def token_required(f):
|
|
108 |
return f(current_user_id, *args, **kwargs)
|
109 |
return decorated
|
110 |
|
111 |
-
#
|
|
|
112 |
@app.route('/', methods=['GET'])
|
113 |
def welcome():
|
|
|
|
|
|
|
|
|
|
|
|
|
114 |
return jsonify({'message': 'Welcome to the Crawlgpt API!'})
|
115 |
|
116 |
-
# USER REGISTRATION
|
117 |
@app.route('/api/register', methods=['POST'])
|
118 |
def register():
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
119 |
data = request.json
|
120 |
username = data.get('username')
|
121 |
password = data.get('password')
|
@@ -132,9 +186,16 @@ def register():
|
|
132 |
return jsonify({'message': 'User created successfully!'})
|
133 |
|
134 |
|
135 |
-
# Login endpoint
|
136 |
@app.route('/api/login', methods=['POST'])
|
137 |
def login():
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
138 |
auth = request.json
|
139 |
|
140 |
if not auth or not auth.get('username') or not auth.get('password'):
|
@@ -155,11 +216,24 @@ def login():
|
|
155 |
|
156 |
return jsonify({'token': token, 'user': {'id': user.id, 'username': user.username}})
|
157 |
|
158 |
-
#
|
|
|
159 |
@app.route('/api/process-url', methods=['POST'])
|
160 |
@token_required
|
161 |
@rate_limit
|
162 |
def process_url(current_user_id):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
163 |
data = request.json
|
164 |
url = data.get('url')
|
165 |
|
@@ -222,11 +296,22 @@ def process_url(current_user_id):
|
|
222 |
except Exception as e:
|
223 |
return jsonify({'success': False, 'message': f"Error processing URL: {str(e)}"}), 500
|
224 |
|
225 |
-
# Chat endpoint
|
226 |
@app.route('/api/chat', methods=['POST'])
|
227 |
@token_required
|
228 |
@rate_limit
|
229 |
def chat_endpoint(current_user_id):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
230 |
data = request.json
|
231 |
user_message = data.get('message')
|
232 |
temperature = data.get('temperature', 0.7)
|
@@ -288,10 +373,22 @@ def chat_endpoint(current_user_id):
|
|
288 |
)
|
289 |
return jsonify({'success': False, 'message': f"Error generating response: {str(e)}"}), 500
|
290 |
|
291 |
-
#
|
|
|
292 |
@app.route('/api/chat/history', methods=['GET'])
|
293 |
@token_required
|
294 |
def get_history(current_user_id):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
295 |
try:
|
296 |
# Load chat history from database
|
297 |
history = get_chat_history(current_user_id)
|
@@ -306,10 +403,20 @@ def get_history(current_user_id):
|
|
306 |
except Exception as e:
|
307 |
return jsonify({'success': False, 'message': f"Error fetching history: {str(e)}"}), 500
|
308 |
|
309 |
-
# Clear chat history
|
310 |
@app.route('/api/chat/clear', methods=['POST'])
|
311 |
@token_required
|
312 |
def clear_history(current_user_id):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
313 |
try:
|
314 |
delete_user_chat_history(current_user_id)
|
315 |
user_sessions[current_user_id]['url_processed'] = False
|
@@ -318,10 +425,21 @@ def clear_history(current_user_id):
|
|
318 |
except Exception as e:
|
319 |
return jsonify({'success': False, 'message': f"Error clearing history: {str(e)}"}), 500
|
320 |
|
321 |
-
# Restore chat history and context
|
322 |
@app.route('/api/chat/restore', methods=['POST'])
|
323 |
@token_required
|
324 |
def restore_history(current_user_id):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
325 |
try:
|
326 |
user_session = user_sessions[current_user_id]
|
327 |
model = user_session['model']
|
@@ -351,10 +469,22 @@ def restore_history(current_user_id):
|
|
351 |
except Exception as e:
|
352 |
return jsonify({'success': False, 'message': f"Restoration failed: {str(e)}"}), 500
|
353 |
|
354 |
-
#
|
|
|
355 |
@app.route('/api/metrics', methods=['GET'])
|
356 |
@token_required
|
357 |
def get_metrics(current_user_id):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
358 |
try:
|
359 |
user_session = user_sessions[current_user_id]
|
360 |
metrics = user_session['metrics'].metrics.to_dict()
|
@@ -363,10 +493,21 @@ def get_metrics(current_user_id):
|
|
363 |
except Exception as e:
|
364 |
return jsonify({'success': False, 'message': f"Error fetching metrics: {str(e)}"}), 500
|
365 |
|
366 |
-
# Export data
|
367 |
@app.route('/api/export', methods=['GET'])
|
368 |
@token_required
|
369 |
def export_data(current_user_id):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
370 |
try:
|
371 |
user_session = user_sessions[current_user_id]
|
372 |
model = user_session['model']
|
@@ -390,10 +531,21 @@ def export_data(current_user_id):
|
|
390 |
except Exception as e:
|
391 |
return jsonify({'success': False, 'message': f"Export failed: {str(e)}"}), 500
|
392 |
|
393 |
-
# Import data
|
394 |
@app.route('/api/import', methods=['POST'])
|
395 |
@token_required
|
396 |
def import_data(current_user_id):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
397 |
try:
|
398 |
user_session = user_sessions[current_user_id]
|
399 |
model = user_session['model']
|
@@ -439,10 +591,22 @@ def import_data(current_user_id):
|
|
439 |
except Exception as e:
|
440 |
return jsonify({'success': False, 'message': f"Import failed: {str(e)}"}), 500
|
441 |
|
442 |
-
#
|
|
|
443 |
@app.route('/api/settings', methods=['POST'])
|
444 |
@token_required
|
445 |
def update_settings(current_user_id):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
446 |
data = request.json
|
447 |
user_session = user_sessions[current_user_id]
|
448 |
|
@@ -456,10 +620,20 @@ def update_settings(current_user_id):
|
|
456 |
except Exception as e:
|
457 |
return jsonify({'success': False, 'message': f"Error updating settings: {str(e)}"}), 500
|
458 |
|
459 |
-
# Clear all data
|
460 |
@app.route('/api/clear-all', methods=['POST'])
|
461 |
@token_required
|
462 |
def clear_all_data(current_user_id):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
463 |
try:
|
464 |
user_session = user_sessions[current_user_id]
|
465 |
model = user_session['model']
|
@@ -475,4 +649,5 @@ def clear_all_data(current_user_id):
|
|
475 |
return jsonify({'success': False, 'message': f"Error clearing data: {str(e)}"}), 500
|
476 |
|
477 |
if __name__ == '__main__':
|
|
|
478 |
app.run(debug=True)
|
|
|
1 |
+
"""
|
2 |
+
CrawlGPT API Server
|
3 |
+
|
4 |
+
This module implements a Flask-based REST API that serves as the backend for the CrawlGPT application.
|
5 |
+
It provides endpoints for user authentication, URL content extraction, chat interaction with LLM,
|
6 |
+
and various data management operations.
|
7 |
+
|
8 |
+
The server implements:
|
9 |
+
- User authentication with JWT tokens
|
10 |
+
- Rate limiting for resource-intensive endpoints
|
11 |
+
- Per-user session management
|
12 |
+
- URL content extraction and processing
|
13 |
+
- Chat interface with LLM models
|
14 |
+
- History management and persistence
|
15 |
+
- Metrics collection
|
16 |
+
- Data import/export capabilities
|
17 |
+
"""
|
18 |
+
|
19 |
+
from flask import Flask, request, jsonify
|
20 |
from flask_cors import CORS
|
21 |
import asyncio
|
22 |
import time
|
23 |
from datetime import datetime
|
|
|
24 |
import jwt
|
25 |
from functools import wraps
|
26 |
import os
|
|
|
31 |
from src.crawlgpt.utils.monitoring import MetricsCollector, Metrics
|
32 |
from src.crawlgpt.utils.data_manager import DataManager
|
33 |
from src.crawlgpt.utils.content_validator import ContentValidator
|
34 |
+
from src.crawlgpt.ui.login import authenticate_user, create_user
|
35 |
|
36 |
app = Flask(__name__)
|
37 |
CORS(app)
|
|
|
52 |
RATE_LIMIT = 10 # requests per minute
|
53 |
rate_limit_data = defaultdict(list) # stores timestamps of requests by user_id
|
54 |
|
|
|
55 |
def rate_limit(f):
|
56 |
+
"""
|
57 |
+
Decorator that implements rate limiting for API endpoints.
|
58 |
+
|
59 |
+
Limits each user to RATE_LIMIT requests per minute and adds appropriate
|
60 |
+
rate limit headers to the response.
|
61 |
+
|
62 |
+
Args:
|
63 |
+
f: The function to decorate
|
64 |
+
|
65 |
+
Returns:
|
66 |
+
Decorated function with rate limiting applied
|
67 |
+
"""
|
68 |
@wraps(f)
|
69 |
def decorated(current_user_id, *args, **kwargs):
|
70 |
# Get current time
|
|
|
108 |
|
109 |
return decorated
|
110 |
|
|
|
111 |
def token_required(f):
|
112 |
+
"""
|
113 |
+
Decorator that enforces JWT authentication for API endpoints.
|
114 |
+
|
115 |
+
Extracts and validates JWT token from Authorization header.
|
116 |
+
Creates a user session if one doesn't exist.
|
117 |
+
|
118 |
+
Args:
|
119 |
+
f: The function to decorate
|
120 |
+
|
121 |
+
Returns:
|
122 |
+
Decorated function with authentication required
|
123 |
+
"""
|
124 |
@wraps(f)
|
125 |
def decorated(*args, **kwargs):
|
126 |
token = None
|
|
|
147 |
return f(current_user_id, *args, **kwargs)
|
148 |
return decorated
|
149 |
|
150 |
+
# ----- PUBLIC ENDPOINTS -----
|
151 |
+
|
152 |
@app.route('/', methods=['GET'])
|
153 |
def welcome():
|
154 |
+
"""
|
155 |
+
Welcome endpoint that confirms the API is running.
|
156 |
+
|
157 |
+
Returns:
|
158 |
+
JSON response with welcome message
|
159 |
+
"""
|
160 |
return jsonify({'message': 'Welcome to the Crawlgpt API!'})
|
161 |
|
|
|
162 |
@app.route('/api/register', methods=['POST'])
|
163 |
def register():
|
164 |
+
"""
|
165 |
+
User registration endpoint.
|
166 |
+
|
167 |
+
Expects JSON with username, password, and email fields.
|
168 |
+
Validates inputs and creates a new user if one doesn't exist.
|
169 |
+
|
170 |
+
Returns:
|
171 |
+
JSON response indicating success or failure
|
172 |
+
"""
|
173 |
data = request.json
|
174 |
username = data.get('username')
|
175 |
password = data.get('password')
|
|
|
186 |
return jsonify({'message': 'User created successfully!'})
|
187 |
|
188 |
|
|
|
189 |
@app.route('/api/login', methods=['POST'])
|
190 |
def login():
|
191 |
+
"""
|
192 |
+
User login endpoint.
|
193 |
+
|
194 |
+
Authenticates user credentials and issues a JWT token for API access.
|
195 |
+
|
196 |
+
Returns:
|
197 |
+
JSON with token and user information on success, error message on failure
|
198 |
+
"""
|
199 |
auth = request.json
|
200 |
|
201 |
if not auth or not auth.get('username') or not auth.get('password'):
|
|
|
216 |
|
217 |
return jsonify({'token': token, 'user': {'id': user.id, 'username': user.username}})
|
218 |
|
219 |
+
# ----- PROTECTED ENDPOINTS -----
|
220 |
+
|
221 |
@app.route('/api/process-url', methods=['POST'])
|
222 |
@token_required
|
223 |
@rate_limit
|
224 |
def process_url(current_user_id):
|
225 |
+
"""
|
226 |
+
URL content extraction endpoint.
|
227 |
+
|
228 |
+
Extracts and processes content from the provided URL using the LLM-based crawler.
|
229 |
+
Content is stored in the user's session for future chat interactions.
|
230 |
+
|
231 |
+
Args:
|
232 |
+
current_user_id: User ID from the authentication decorator
|
233 |
+
|
234 |
+
Returns:
|
235 |
+
JSON indicating success/failure and appropriate messages
|
236 |
+
"""
|
237 |
data = request.json
|
238 |
url = data.get('url')
|
239 |
|
|
|
296 |
except Exception as e:
|
297 |
return jsonify({'success': False, 'message': f"Error processing URL: {str(e)}"}), 500
|
298 |
|
|
|
299 |
@app.route('/api/chat', methods=['POST'])
|
300 |
@token_required
|
301 |
@rate_limit
|
302 |
def chat_endpoint(current_user_id):
|
303 |
+
"""
|
304 |
+
Chat interaction endpoint.
|
305 |
+
|
306 |
+
Processes user message and generates LLM response based on the previously
|
307 |
+
extracted content. Saves both user message and response to chat history.
|
308 |
+
|
309 |
+
Args:
|
310 |
+
current_user_id: User ID from the authentication decorator
|
311 |
+
|
312 |
+
Returns:
|
313 |
+
JSON with AI response or error message
|
314 |
+
"""
|
315 |
data = request.json
|
316 |
user_message = data.get('message')
|
317 |
temperature = data.get('temperature', 0.7)
|
|
|
373 |
)
|
374 |
return jsonify({'success': False, 'message': f"Error generating response: {str(e)}"}), 500
|
375 |
|
376 |
+
# ----- HISTORY MANAGEMENT ENDPOINTS -----
|
377 |
+
|
378 |
@app.route('/api/chat/history', methods=['GET'])
|
379 |
@token_required
|
380 |
def get_history(current_user_id):
|
381 |
+
"""
|
382 |
+
Chat history retrieval endpoint.
|
383 |
+
|
384 |
+
Fetches the user's chat history from the database.
|
385 |
+
|
386 |
+
Args:
|
387 |
+
current_user_id: User ID from the authentication decorator
|
388 |
+
|
389 |
+
Returns:
|
390 |
+
JSON with chat messages array or error message
|
391 |
+
"""
|
392 |
try:
|
393 |
# Load chat history from database
|
394 |
history = get_chat_history(current_user_id)
|
|
|
403 |
except Exception as e:
|
404 |
return jsonify({'success': False, 'message': f"Error fetching history: {str(e)}"}), 500
|
405 |
|
|
|
406 |
@app.route('/api/chat/clear', methods=['POST'])
|
407 |
@token_required
|
408 |
def clear_history(current_user_id):
|
409 |
+
"""
|
410 |
+
Chat history clearing endpoint.
|
411 |
+
|
412 |
+
Deletes all chat history for the current user and resets URL processing state.
|
413 |
+
|
414 |
+
Args:
|
415 |
+
current_user_id: User ID from the authentication decorator
|
416 |
+
|
417 |
+
Returns:
|
418 |
+
JSON indicating success/failure
|
419 |
+
"""
|
420 |
try:
|
421 |
delete_user_chat_history(current_user_id)
|
422 |
user_sessions[current_user_id]['url_processed'] = False
|
|
|
425 |
except Exception as e:
|
426 |
return jsonify({'success': False, 'message': f"Error clearing history: {str(e)}"}), 500
|
427 |
|
|
|
428 |
@app.route('/api/chat/restore', methods=['POST'])
|
429 |
@token_required
|
430 |
def restore_history(current_user_id):
|
431 |
+
"""
|
432 |
+
Chat history and context restoration endpoint.
|
433 |
+
|
434 |
+
Rebuilds the model's internal state from previously saved chat history.
|
435 |
+
Reconstructs vector database from context for retrieval.
|
436 |
+
|
437 |
+
Args:
|
438 |
+
current_user_id: User ID from the authentication decorator
|
439 |
+
|
440 |
+
Returns:
|
441 |
+
JSON indicating success/failure
|
442 |
+
"""
|
443 |
try:
|
444 |
user_session = user_sessions[current_user_id]
|
445 |
model = user_session['model']
|
|
|
469 |
except Exception as e:
|
470 |
return jsonify({'success': False, 'message': f"Restoration failed: {str(e)}"}), 500
|
471 |
|
472 |
+
# ----- METRICS AND DATA MANAGEMENT ENDPOINTS -----
|
473 |
+
|
474 |
@app.route('/api/metrics', methods=['GET'])
|
475 |
@token_required
|
476 |
def get_metrics(current_user_id):
|
477 |
+
"""
|
478 |
+
Usage metrics retrieval endpoint.
|
479 |
+
|
480 |
+
Provides performance and usage statistics for the current user.
|
481 |
+
|
482 |
+
Args:
|
483 |
+
current_user_id: User ID from the authentication decorator
|
484 |
+
|
485 |
+
Returns:
|
486 |
+
JSON with metrics data or error message
|
487 |
+
"""
|
488 |
try:
|
489 |
user_session = user_sessions[current_user_id]
|
490 |
metrics = user_session['metrics'].metrics.to_dict()
|
|
|
493 |
except Exception as e:
|
494 |
return jsonify({'success': False, 'message': f"Error fetching metrics: {str(e)}"}), 500
|
495 |
|
|
|
496 |
@app.route('/api/export', methods=['GET'])
|
497 |
@token_required
|
498 |
def export_data(current_user_id):
|
499 |
+
"""
|
500 |
+
Data export endpoint.
|
501 |
+
|
502 |
+
Exports all user data including chat history, metrics, and vector database
|
503 |
+
for backup or transfer purposes.
|
504 |
+
|
505 |
+
Args:
|
506 |
+
current_user_id: User ID from the authentication decorator
|
507 |
+
|
508 |
+
Returns:
|
509 |
+
JSON with complete application state or error message
|
510 |
+
"""
|
511 |
try:
|
512 |
user_session = user_sessions[current_user_id]
|
513 |
model = user_session['model']
|
|
|
531 |
except Exception as e:
|
532 |
return jsonify({'success': False, 'message': f"Export failed: {str(e)}"}), 500
|
533 |
|
|
|
534 |
@app.route('/api/import', methods=['POST'])
|
535 |
@token_required
|
536 |
def import_data(current_user_id):
|
537 |
+
"""
|
538 |
+
Data import endpoint.
|
539 |
+
|
540 |
+
Imports previously exported data, restoring application state.
|
541 |
+
Validates data structure before import to ensure integrity.
|
542 |
+
|
543 |
+
Args:
|
544 |
+
current_user_id: User ID from the authentication decorator
|
545 |
+
|
546 |
+
Returns:
|
547 |
+
JSON indicating success/failure
|
548 |
+
"""
|
549 |
try:
|
550 |
user_session = user_sessions[current_user_id]
|
551 |
model = user_session['model']
|
|
|
591 |
except Exception as e:
|
592 |
return jsonify({'success': False, 'message': f"Import failed: {str(e)}"}), 500
|
593 |
|
594 |
+
# ----- SETTINGS AND CONFIGURATION ENDPOINTS -----
|
595 |
+
|
596 |
@app.route('/api/settings', methods=['POST'])
|
597 |
@token_required
|
598 |
def update_settings(current_user_id):
|
599 |
+
"""
|
600 |
+
User settings update endpoint.
|
601 |
+
|
602 |
+
Updates configurable options for the current user session.
|
603 |
+
|
604 |
+
Args:
|
605 |
+
current_user_id: User ID from the authentication decorator
|
606 |
+
|
607 |
+
Returns:
|
608 |
+
JSON indicating success/failure
|
609 |
+
"""
|
610 |
data = request.json
|
611 |
user_session = user_sessions[current_user_id]
|
612 |
|
|
|
620 |
except Exception as e:
|
621 |
return jsonify({'success': False, 'message': f"Error updating settings: {str(e)}"}), 500
|
622 |
|
|
|
623 |
@app.route('/api/clear-all', methods=['POST'])
|
624 |
@token_required
|
625 |
def clear_all_data(current_user_id):
|
626 |
+
"""
|
627 |
+
Complete data reset endpoint.
|
628 |
+
|
629 |
+
Clears all user data including model state, chat history, and metrics.
|
630 |
+
|
631 |
+
Args:
|
632 |
+
current_user_id: User ID from the authentication decorator
|
633 |
+
|
634 |
+
Returns:
|
635 |
+
JSON indicating success/failure
|
636 |
+
"""
|
637 |
try:
|
638 |
user_session = user_sessions[current_user_id]
|
639 |
model = user_session['model']
|
|
|
649 |
return jsonify({'success': False, 'message': f"Error clearing data: {str(e)}"}), 500
|
650 |
|
651 |
if __name__ == '__main__':
|
652 |
+
# Run the Flask application in debug mode (not for production)
|
653 |
app.run(debug=True)
|