From 678fb94ee4a7d602fc0f743b20b1f84509814feb Mon Sep 17 00:00:00 2001 From: Renato Rosa Date: Wed, 19 Aug 2026 20:22:45 -0300 Subject: [PATCH] Atualizar app/app.py --- app/app.py | 166 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) diff --git a/app/app.py b/app/app.py index 0de0173..e26419c 100644 --- a/app/app.py +++ b/app/app.py @@ -1,3 +1,169 @@ +import os +import json +import requests +from functools import wraps + +from flask import Flask, request, jsonify, redirect, session, url_for +from authlib.integrations.flask_client import OAuth + +from config import Config + +# All comments are in English. + +app = Flask(__name__) +app.config.from_object(Config) + +# Configure session secret key. +app.secret_key = app.config["SECRET_KEY"] + +# Configure OAuth with Google. +oauth = OAuth(app) +google = oauth.register( + name="google", + client_id=app.config["GOOGLE_CLIENT_ID"], + client_secret=app.config["GOOGLE_CLIENT_SECRET"], + access_token_url="https://oauth2.googleapis.com/token", + access_token_params=None, + authorize_url="https://accounts.google.com/o/oauth2/v2/auth", + authorize_params={ + "access_type": "offline", + "prompt": "consent", + }, + api_base_url="https://www.googleapis.com/oauth2/v2/", + client_kwargs={"scope": "openid email profile"}, +) + + +def login_required(f): + """Decorator to ensure the user is authenticated via Google OAuth.""" + + @wraps(f) + def wrapper(*args, **kwargs): + # Check if user info is stored in session. + if "user" not in session: + # Redirect to login if not authenticated. + return redirect(url_for("login")) + return f(*args, **kwargs) + + return wrapper + + +@app.route("/login") +def login(): + """Start Google OAuth login flow.""" + redirect_uri = app.config["GOOGLE_REDIRECT_URI"] + # Use the configured redirect URI for OAuth callback. + return google.authorize_redirect(redirect_uri) + + +@app.route("/oauth/callback") +def oauth_callback(): + """Handle Google OAuth callback and store user session.""" + # Exchange authorization code for tokens. + token = google.authorize_access_token() + # Fetch user info from Google. + resp = google.get("userinfo") + user_info = resp.json() + + # Store minimal user info in session. + session["user"] = { + "email": user_info.get("email"), + "name": user_info.get("name"), + } + + # Redirect to a simple home or API docs page. + return redirect(url_for("home")) + + +@app.route("/") +def home(): + """Simple home endpoint explaining the service.""" + # This endpoint is intentionally simple and easy to understand. + return jsonify( + { + "message": "Ollama Gateway is running.", + "auth": "Google OAuth required for /api/* endpoints.", + "endpoints": { + "health": "/health", + "generate": "/api/generate", + }, + } + ) + + +@app.route("/health") +def health(): + """Health check endpoint.""" + return jsonify({"status": "ok"}) + + +@app.route("/api/generate", methods=["POST"]) +@login_required +def generate(): + """Generate text using a selected Ollama model. + + Expected JSON body: + { + "model": "llama3.2", + "prompt": "Your prompt here" + } + """ + data = request.get_json(silent=True) or {} + + # Extract model and prompt from request. + model_name = data.get("model", "llama3.2") + prompt = data.get("prompt") + + if not prompt: + return jsonify({"error": "Missing 'prompt' field."}), 400 + + # Map user-facing model name to Ollama model identifier. + model_id = app.config["MODEL_MAP"].get(model_name) + if not model_id: + return jsonify({"error": f"Unsupported model '{model_name}'."}), 400 + + # Prepare request to Ollama API. + ollama_url = f"{app.config['OLLAMA_BASE_URL']}/api/generate" + payload = { + "model": model_id, + "prompt": prompt, + # You can add more Ollama-specific parameters here if needed. + } + + try: + # Call Ollama HTTP API. + response = requests.post(ollama_url, json=payload, timeout=60) + response.raise_for_status() + except requests.RequestException as e: + # Handle network or API errors gracefully. + return jsonify({"error": "Failed to call Ollama API.", "details": str(e)}), 502 + + # Parse Ollama response. + try: + ollama_data = response.json() + except json.JSONDecodeError: + return jsonify({"error": "Invalid JSON response from Ollama."}), 502 + + # Extract output text (this depends on Ollama's response format). + output_text = ollama_data.get("response") or ollama_data.get("output") or "" + + return jsonify( + { + "model": model_name, + "output": output_text, + } + ) + + +if __name__ == "__main__": + # This block is mainly for local debugging. + # In production, Gunicorn will run the app. + app.run(host="0.0.0.0", port=8000) + + +# *** + + from flask import Flask, request, jsonify from flask_cors import CORS from db import Base, engine