Spaces:
Sleeping
Sleeping
# python app.py --port 9090 | |
from flask import Flask, render_template, request, jsonify, session | |
import os | |
import sys | |
import argparse | |
from github_companion import GitHubCompanion | |
from dotenv import load_dotenv | |
import uuid # Using Python's built-in uuid module | |
import logging | |
import time | |
# Configure logging | |
logging.basicConfig(level=logging.INFO) | |
logger = logging.getLogger(__name__) | |
# Load environment variables | |
load_dotenv() | |
app = Flask(__name__) | |
# More explicit session configuration | |
# We set SESSION_COOKIE_SECURE=False because Hugging Face Spaces handles HTTPS termination externally. | |
# If you were running HTTPS directly in Flask, you'd set this to True. | |
app.config.update( | |
SECRET_KEY=os.environ.get("SECRET_KEY", os.urandom(24).hex()), # Ensure SECRET_KEY is loaded | |
SESSION_COOKIE_HTTPONLY=True, # Prevent client-side JS access to the cookie | |
SESSION_COOKIE_SAMESITE='Lax', # Recommended setting for CSRF protection | |
SESSION_COOKIE_SECURE=False, # Set to False as HTTPS is handled externally by HF | |
) | |
app.secret_key = app.config['SECRET_KEY'] # Make sure app.secret_key is set from config | |
# Store active sessions | |
sessions = {} | |
# Rate limiting | |
request_timestamps = {} | |
RATE_LIMIT_WINDOW = 60 # seconds | |
MAX_REQUESTS_PER_WINDOW = 5 | |
def index(): | |
"""Render the main page""" | |
# Generate a unique session ID if one doesn't exist | |
if "session_id" not in session: | |
session["session_id"] = str(uuid.uuid4()) | |
logger.info(f"New session created: {session['session_id']}") # Add logging | |
return render_template("index.html") | |
def is_rate_limited(session_id): | |
"""Check if the session is rate limited""" | |
current_time = time.time() | |
# Initialize timestamps for this session if not exists | |
if session_id not in request_timestamps: | |
request_timestamps[session_id] = [] | |
# Remove timestamps outside the window | |
request_timestamps[session_id] = [ | |
ts for ts in request_timestamps[session_id] | |
if ts > current_time - RATE_LIMIT_WINDOW | |
] | |
# Check if too many requests in the window | |
if len(request_timestamps[session_id]) >= MAX_REQUESTS_PER_WINDOW: | |
return True | |
# Add current timestamp | |
request_timestamps[session_id].append(current_time) | |
return False | |
def chat(): | |
"""Handle chat requests""" | |
data = request.json | |
message = data.get("message", "") | |
# Add logging to see the session state | |
logger.info(f"Chat request received. Current session keys: {list(session.keys())}") | |
session_id = session.get("session_id") | |
if not session_id: | |
logger.error("No valid session ID found in session object.") # Add error logging | |
return jsonify({"error": "No valid session"}), 400 | |
logger.info(f"Valid session ID found: {session_id}") # Add success logging | |
# Check rate limiting | |
if is_rate_limited(session_id): | |
return jsonify({ | |
"response": "You're sending requests too quickly. Please wait a moment before trying again.", | |
"token_count": 0, | |
"rate_limited": True | |
}) | |
try: | |
# Initialize companion if not exists for this session | |
if session_id not in sessions: | |
requesty_api_key = os.environ.get("REQUESTY_API_KEY") | |
logger.info(f"Using API key: {requesty_api_key[:5]}...{requesty_api_key[-5:] if requesty_api_key else ''}") | |
if not requesty_api_key: | |
return jsonify({"error": "Requesty API key not configured. Please check your .env file."}), 500 | |
sessions[session_id] = GitHubCompanion(requesty_api_key=requesty_api_key) | |
companion = sessions[session_id] | |
response = companion.chat(message) | |
# Check if the response contains an error message about rate limiting | |
rate_limited = "rate limit" in response.lower() or "quota" in response.lower() | |
return jsonify({ | |
"response": response, | |
"token_count": companion.token_count if companion.repo_info else 0, | |
"rate_limited": rate_limited | |
}) | |
except Exception as e: | |
logger.error(f"Error in chat: {str(e)}") | |
return jsonify({"error": f"An error occurred: {str(e)}"}), 500 | |
def reset(): | |
"""Reset the conversation""" | |
session_id = session.get("session_id") | |
if session_id and session_id in sessions: | |
try: | |
# Save conversation before resetting | |
sessions[session_id].save_conversation(f"conversation_{session_id}.json") | |
# Remove the session | |
del sessions[session_id] | |
except Exception as e: | |
logger.error(f"Error in reset: {str(e)}") | |
# Create new session ID | |
session["session_id"] = str(uuid.uuid4()) | |
return jsonify({"status": "success", "message": "Conversation reset"}) | |
def health(): | |
"""Health check endpoint""" | |
return jsonify({"status": "ok"}) | |
if __name__ == "__main__": | |
# Parse command line arguments | |
parser = argparse.ArgumentParser(description="GitHub Navigator Web App") | |
parser.add_argument("--port", type=int, help="Port to run the server on") | |
args = parser.parse_args() | |
# Ensure the templates directory exists | |
os.makedirs("templates", exist_ok=True) | |
# Priority: 1. Command line argument, 2. Environment variable, 3. Default (8080) | |
port = args.port if args.port else int(os.environ.get("PORT", 8080)) | |
logger.info(f"Starting GitHub Navigator on port {port}") | |
# Run the app | |
app.run(host="0.0.0.0", port=port, debug=True) |