CoolFace
Apppublic

ArchCoder/llm-excel-plotter-agent

sourceHugging Faceupdated 7mo agoView on Hugging Face
0likes
app.py143 linesDownload Raw Back to root
1from flask import Flask, request, jsonify, send_from_directory2from flask_cors import CORS3from llm_agent import LLM_Agent4from data_processor import DataProcessor5import os6import logging7import time8from dotenv import load_dotenv9from werkzeug.utils import secure_filename10 11load_dotenv()12 13logging.basicConfig(level=logging.INFO)14logging.getLogger('matplotlib').setLevel(logging.WARNING)15logging.getLogger('PIL').setLevel(logging.WARNING)16logging.getLogger('plotly').setLevel(logging.WARNING)17 18BASE_DIR = os.path.dirname(os.path.abspath(__file__))19 20app = Flask(__name__, static_folder=os.path.join(BASE_DIR, 'static'))21 22CORS(app, origins=[23    "https://llm-integrated-excel-plotter-app.vercel.app",24    "http://localhost:8080",25    "http://localhost:3000",26], supports_credentials=False)27 28agent = LLM_Agent()29 30UPLOAD_FOLDER     = os.path.join(BASE_DIR, 'data', 'uploads')31ALLOWED_EXTENSIONS = {'csv', 'xls', 'xlsx'}32MAX_UPLOAD_BYTES   = 10 * 1024 * 1024  # 10 MB33 34app.config['UPLOAD_FOLDER']        = UPLOAD_FOLDER35app.config['MAX_CONTENT_LENGTH']   = MAX_UPLOAD_BYTES36 37os.makedirs(UPLOAD_FOLDER, exist_ok=True)38STARTED_AT = time.time()39 40 41def allowed_file(filename):42    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS43 44 45@app.route('/')46def index():47    return jsonify({48        "status": "ok",49        "message": "AI Data Visualization API",50        "endpoints": ["/health", "/plot", "/upload", "/stats", "/models"]51    })52 53 54@app.route('/health', methods=['GET'])55def health():56    """Lightweight endpoint used by frontend wake-up checks and cron pings."""57    return jsonify({58        "status": "ok",59        "service": "llm-excel-plotter-agent",60        "uptime_seconds": round(time.time() - STARTED_AT, 2),61        "timestamp": int(time.time()),62    })63 64 65@app.route('/models', methods=['GET'])66def models():67    return jsonify({68        "models": [69            {"id": "qwen",   "name": "Qwen2.5-Coder-0.5B", "provider": "Local (transformers)", "free": True},70            {"id": "bart",   "name": "BART (fine-tuned)",   "provider": "Local (transformers)", "free": True},71            {"id": "gemini", "name": "Gemini 2.0 Flash",    "provider": "Google AI (API key)",  "free": False},72            {"id": "grok",   "name": "Grok-3 Mini",         "provider": "xAI (API key)",       "free": False},73        ],74        "default": "qwen"75    })76 77 78@app.route('/plot', methods=['POST'])79def plot():80    t0   = time.time()81    data = request.get_json(force=True)82    if not data or not data.get('query'):83        return jsonify({'error': 'Missing required field: query'}), 40084 85    logging.info(f"Plot request: model={data.get('model','qwen')} query={data.get('query')[:80]}")86    result = agent.process_request(data)87    logging.info(f"Plot completed in {time.time() - t0:.2f}s")88    return jsonify(result)89 90 91@app.route('/static/<path:filename>')92def serve_static(filename):93    resp = send_from_directory(app.static_folder, filename)94    resp.headers['Access-Control-Allow-Origin'] = '*'95    resp.headers['Cache-Control'] = 'public, max-age=300'96    return resp97 98 99@app.route('/upload', methods=['POST'])100def upload_file():101    if 'file' not in request.files:102        return jsonify({'error': 'No file part in request'}), 400103    file = request.files['file']104    if not file.filename:105        return jsonify({'error': 'No file selected'}), 400106    if not allowed_file(file.filename):107        return jsonify({'error': 'File type not allowed. Use CSV, XLS, or XLSX'}), 400108 109    filename  = secure_filename(file.filename)110    file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)111    file.save(file_path)112 113    dp = DataProcessor(file_path)114    return jsonify({115        'message':   'File uploaded successfully',116        'columns':   dp.get_columns(),117        'dtypes':    dp.get_dtypes(),118        'preview':   dp.preview(5),119        'file_path': file_path,120        'row_count': len(dp.data),121    })122 123 124@app.route('/stats', methods=['POST'])125def stats():126    data      = request.get_json(force=True) or {}127    file_path = data.get('file_path')128    dp        = DataProcessor(file_path) if file_path and os.path.exists(file_path) else agent.data_processor129    return jsonify({130        'columns':   dp.get_columns(),131        'dtypes':    dp.get_dtypes(),132        'stats':     dp.get_stats(),133        'row_count': len(dp.data),134    })135 136 137@app.errorhandler(413)138def file_too_large(e):139    return jsonify({'error': f'File too large. Maximum size is {MAX_UPLOAD_BYTES // (1024*1024)} MB'}), 413140 141 142if __name__ == '__main__':143    app.run(host='0.0.0.0', port=7860)