from flask import Flask, request, jsonify from werkzeug.utils import secure_filename import os from datetime import datetime import logging from dotenv import load_dotenv from hf_uploader import upload_file, upload_folder import tempfile import shutil # Load environment variables load_dotenv() # Setup Flask app app = Flask(__name__) app.config['MAX_CONTENT_LENGTH'] = 100 * 1024 * 1024 # 100MB max file size app.config['UPLOAD_FOLDER'] = 'uploads' # Setup logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) # Create uploads folder if not exists if not os.path.exists(app.config['UPLOAD_FOLDER']): os.makedirs(app.config['UPLOAD_FOLDER']) # Allowed file extensions (optional, allow all) ALLOWED_EXTENSIONS = set(['*']) def allowed_file(filename): return True # Allow all files @app.route('/', methods=['GET']) def health_check(): """Health check endpoint""" return jsonify({ 'status': 'ok', 'message': 'Hugging Face File Upload API', 'version': '1.0.0', 'language': 'Python', 'framework': 'Flask', 'endpoints': { 'upload': { 'method': 'POST', 'path': '/api/upload', 'description': 'Upload file ke Hugging Face dataset', 'required': ['file', 'repo_id', 'token'], 'optional': ['subfolder'] } } }) @app.route('/api/upload', methods=['POST']) def upload(): """Upload file to Hugging Face""" try: # Validasi file if 'file' not in request.files: return jsonify({ 'success': False, 'error': 'File tidak ditemukan' }), 400 file = request.files['file'] if file.filename == '': return jsonify({ 'success': False, 'error': 'File tidak dipilih' }), 400 if not allowed_file(file.filename): return jsonify({ 'success': False, 'error': 'File type tidak diizinkan' }), 400 # Get form data repo_id = request.form.get('repo_id') or os.getenv('HF_REPO_ID') token = request.form.get('token') or os.getenv('HF_TOKEN') subfolder = request.form.get('subfolder', '') # Validate required fields if not repo_id or not token: return jsonify({ 'success': False, 'error': 'repo_id dan token diperlukan (kirim via request atau set di .env)', 'required_fields': ['repo_id', 'token'], 'hint': 'Set HF_REPO_ID dan HF_TOKEN di .env atau kirim via form data' }), 400 # Save file temporarily filename = secure_filename(file.filename) temp_dir = tempfile.mkdtemp() file_path = os.path.join(temp_dir, filename) file.save(file_path) file_size = os.path.getsize(file_path) logger.info(f'Uploading {filename} ({file_size} bytes) to {repo_id}') try: # Upload to Hugging Face result = upload_file( file_path=file_path, file_name=filename, repo_id=repo_id, token=token, subfolder=subfolder ) # Cleanup shutil.rmtree(temp_dir) return jsonify({ 'success': True, 'message': 'File berhasil di-upload ke Hugging Face', 'data': { 'file_name': filename, 'file_size': file_size, 'repo_id': repo_id, 'path_prefix': '/u/', 'subfolder': subfolder or 'root', 'url': result['url'], 'file_path': result['file_path'], 'upload_timestamp': datetime.utcnow().isoformat() + 'Z' } }), 200 except Exception as upload_error: # Cleanup on error shutil.rmtree(temp_dir) logger.error(f'Upload error: {str(upload_error)}') error_msg = str(upload_error) if 'Token' in error_msg or 'Unauthorized' in error_msg: return jsonify({ 'success': False, 'error': 'Token tidak valid atau expired' }), 401 elif 'Repository' in error_msg or 'Not found' in error_msg: return jsonify({ 'success': False, 'error': f'Repository tidak ditemukan: {repo_id}' }), 404 else: return jsonify({ 'success': False, 'error': error_msg }), 500 except Exception as error: logger.error(f'Error: {str(error)}') return jsonify({ 'success': False, 'error': 'Internal Server Error', 'message': str(error) }), 500 @app.errorhandler(404) def not_found(error): """404 handler""" return jsonify({ 'success': False, 'error': 'Endpoint tidak ditemukan' }), 404 @app.errorhandler(500) def server_error(error): """500 handler""" return jsonify({ 'success': False, 'error': 'Internal Server Error' }), 500 if __name__ == '__main__': port = int(os.getenv('PORT', 3000)) debug = os.getenv('NODE_ENV', 'development') == 'development' logger.info(f'🚀 API server berjalan di http://localhost:{port}') logger.info(f'📤 Endpoint upload: POST http://localhost:{port}/api/upload') app.run(host='0.0.0.0', port=port, debug=debug)