Atualizar app/app.py
This commit is contained in:
+166
@@ -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 import Flask, request, jsonify
|
||||||
from flask_cors import CORS
|
from flask_cors import CORS
|
||||||
from db import Base, engine
|
from db import Base, engine
|
||||||
|
|||||||
Reference in New Issue
Block a user