Spaces:
Running
Running
| # app_full.py - COMPLETE VERSION WITH OPTIMIZATION & COMPARE ENDPOINT | |
| from flask import Flask, render_template, request, jsonify, session, redirect | |
| from flask_cors import CORS | |
| import os | |
| import uuid | |
| from werkzeug.utils import secure_filename | |
| from detector import AIDetector | |
| from database import Database | |
| from auth import auth_bp | |
| from datetime import datetime | |
| import nltk | |
| # Download NLTK data | |
| try: | |
| nltk.data.find('tokenizers/punkt') | |
| except LookupError: | |
| nltk.download('punkt') | |
| nltk.download('stopwords') | |
| app = Flask(__name__) | |
| app.secret_key = os.environ.get('SECRET_KEY', 'dtector-ai-secret-key-2026-production') | |
| CORS(app) | |
| # Register blueprint | |
| app.register_blueprint(auth_bp) | |
| # Config | |
| app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 | |
| app.config['UPLOAD_FOLDER'] = 'uploads' | |
| ALLOWED_EXTENSIONS = {'pdf', 'txt', 'docx'} | |
| os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True) | |
| detector = AIDetector() | |
| db = Database() | |
| # Optional: Load RoBERTa detector if available | |
| try: | |
| from detector_roberta import RoBERTaDetector | |
| roberta_detector = RoBERTaDetector() | |
| ROBERTA_AVAILABLE = True | |
| except: | |
| ROBERTA_AVAILABLE = False | |
| print("⚠️ RoBERTa detector not available") | |
| def allowed_file(filename): | |
| return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS | |
| def get_current_user(): | |
| user_id = session.get('user_id') | |
| if not user_id: | |
| return None | |
| return {'id': user_id, 'username': session.get('username')} | |
| # ============ PAGE ROUTES ============ | |
| def splash(): | |
| return render_template('splash.html') | |
| def landing(): | |
| return render_template('landing.html') | |
| def login_page(): | |
| return render_template('login.html') | |
| def register_page(): | |
| return render_template('register.html') | |
| def verify_page(): | |
| user_id = request.args.get('user_id') or session.get('pending_user_id') | |
| return render_template('verify.html', user_id=user_id) | |
| def dashboard(): | |
| return render_template('dashboard.html') | |
| def profile_page(): | |
| if not session.get('user_id'): | |
| return redirect('/login') | |
| return render_template('profile.html') | |
| def change_password_page(): | |
| if not session.get('user_id'): | |
| return redirect('/login') | |
| return render_template('change_password.html') | |
| # ============ API ROUTES ============ | |
| def detect_text(): | |
| data = request.get_json() | |
| text = data.get('text', '') | |
| model = data.get('model', 'indobert') | |
| user = get_current_user() | |
| if not text: | |
| return jsonify({'error': 'Text is required'}), 400 | |
| # Pilih model | |
| if model == 'roberta' and ROBERTA_AVAILABLE: | |
| result = roberta_detector.detect(text) | |
| else: | |
| result = detector.detect(text) | |
| # Simpan history hanya jika user login | |
| if not result.get('error') and user: | |
| db.add_detection( | |
| text, result, | |
| user_id=user['id'] if user else None, | |
| file_name=None, | |
| file_type='text' | |
| ) | |
| return jsonify(result) | |
| def detect_file(): | |
| if 'file' not in request.files: | |
| return jsonify({'error': 'No file uploaded'}), 400 | |
| file = request.files['file'] | |
| model = request.form.get('model', 'indobert') | |
| user = get_current_user() | |
| if file.filename == '': | |
| return jsonify({'error': 'Empty filename'}), 400 | |
| if not allowed_file(file.filename): | |
| return jsonify({'error': 'File type not allowed'}), 400 | |
| filename = secure_filename(file.filename) | |
| unique_filename = f"{uuid.uuid4().hex}_{filename}" | |
| filepath = os.path.join(app.config['UPLOAD_FOLDER'], unique_filename) | |
| file.save(filepath) | |
| try: | |
| file_ext = filename.rsplit('.', 1)[1].lower() | |
| if model == 'roberta' and ROBERTA_AVAILABLE: | |
| result = roberta_detector.detect_file(filepath, file_ext) | |
| else: | |
| result = detector.detect_file(filepath, file_ext) | |
| # Simpan history hanya jika user login | |
| if not result.get('error') and user: | |
| text = result.get('preview', '') | |
| db.add_detection( | |
| text, result, | |
| user_id=user['id'] if user else None, | |
| file_name=filename, | |
| file_type=file_ext | |
| ) | |
| return jsonify(result) | |
| except Exception as e: | |
| return jsonify({'error': str(e)}), 500 | |
| finally: | |
| if os.path.exists(filepath): | |
| os.remove(filepath) | |
| def compare_models(): | |
| """Endpoint untuk membandingkan IndoBERT dan RoBERTa secara langsung""" | |
| data = request.get_json() | |
| text = data.get('text', '') | |
| if not text: | |
| return jsonify({'error': 'Text is required'}), 400 | |
| result = { | |
| 'indobert': detector.detect(text), | |
| 'roberta': None | |
| } | |
| if ROBERTA_AVAILABLE: | |
| result['roberta'] = roberta_detector.detect(text) | |
| else: | |
| result['roberta'] = {'error': 'RoBERTa model not available'} | |
| return jsonify(result) | |
| def get_history(): | |
| user = get_current_user() | |
| limit = request.args.get('limit', 50, type=int) | |
| if user: | |
| history = db.get_user_history(user['id'], limit) | |
| else: | |
| return jsonify([]) | |
| result = [] | |
| for item in history: | |
| result.append({ | |
| 'id': item.id, | |
| 'text_preview': item.text_preview, | |
| 'file_name': item.file_name, | |
| 'file_type': item.file_type, | |
| 'ai_probability': item.ai_probability, | |
| 'human_probability': item.human_probability, | |
| 'confidence': item.confidence, | |
| 'is_ai': bool(item.is_ai), | |
| 'is_pinned': item.is_pinned, | |
| 'created_at': item.created_at.strftime('%Y-%m-%d %H:%M:%S') | |
| }) | |
| return jsonify(result) | |
| def delete_detection(detection_id): | |
| user = get_current_user() | |
| if not user: | |
| return jsonify({'error': 'Login required'}), 401 | |
| if db.delete_detection(detection_id, user['id']): | |
| return jsonify({'success': True}) | |
| return jsonify({'error': 'Detection not found'}), 404 | |
| def toggle_pin(detection_id): | |
| user = get_current_user() | |
| if not user: | |
| return jsonify({'error': 'Login required'}), 401 | |
| is_pinned = db.toggle_pin(detection_id, user['id']) | |
| if is_pinned is not None: | |
| return jsonify({'success': True, 'is_pinned': is_pinned}) | |
| return jsonify({'error': 'Detection not found'}), 404 | |
| def get_stats(): | |
| user = get_current_user() | |
| if user: | |
| stats = db.get_user_stats(user['id']) | |
| else: | |
| stats = {'total': 0, 'ai_count': 0, 'human_count': 0, 'avg_confidence': 0} | |
| return jsonify(stats) | |
| def health(): | |
| return jsonify({ | |
| 'status': 'healthy', | |
| 'model_loaded': detector.model is not None, | |
| 'roberta_available': ROBERTA_AVAILABLE, | |
| 'timestamp': datetime.now().isoformat() | |
| }) | |
| if __name__ == '__main__': | |
| port = int(os.environ.get('PORT', 5001)) | |
| app.run(host='0.0.0.0', port=port) |