|
|
|
|
|
"""
|
|
|
Flask App with Gunicorn for Deep Modal Files
|
|
|
Economics Chat Application using Qwen2 model
|
|
|
"""
|
|
|
|
|
|
from flask import Flask, request, jsonify, render_template_string
|
|
|
import torch
|
|
|
from transformers import AutoTokenizer, AutoModelForCausalLM
|
|
|
import os
|
|
|
import logging
|
|
|
|
|
|
|
|
|
logging.basicConfig(level=logging.INFO)
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
app = Flask(__name__)
|
|
|
|
|
|
|
|
|
model = None
|
|
|
tokenizer = None
|
|
|
|
|
|
|
|
|
HTML_TEMPLATE = """
|
|
|
<!DOCTYPE html>
|
|
|
<html>
|
|
|
<head>
|
|
|
<title>AEGIS Economics AI</title>
|
|
|
<meta charset="utf-8">
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
|
<style>
|
|
|
body { font-family: Arial, sans-serif; margin: 0; padding: 20px; background: #f5f5f5; }
|
|
|
.container { max-width: 800px; margin: 0 auto; background: white; padding: 20px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
|
|
|
.header { text-align: center; margin-bottom: 30px; }
|
|
|
.chat-container { border: 1px solid #ddd; border-radius: 5px; height: 400px; overflow-y: auto; padding: 10px; margin-bottom: 20px; background: #fafafa; }
|
|
|
.message { margin: 10px 0; padding: 10px; border-radius: 5px; }
|
|
|
.user-message { background: #007bff; color: white; margin-left: 20%; }
|
|
|
.ai-message { background: #e9ecef; color: #333; margin-right: 20%; }
|
|
|
.input-group { display: flex; gap: 10px; }
|
|
|
.input-field { flex: 1; padding: 10px; border: 1px solid #ddd; border-radius: 5px; }
|
|
|
.send-btn { padding: 10px 20px; background: #007bff; color: white; border: none; border-radius: 5px; cursor: pointer; }
|
|
|
.send-btn:hover { background: #0056b3; }
|
|
|
.loading { text-align: center; color: #666; font-style: italic; }
|
|
|
</style>
|
|
|
</head>
|
|
|
<body>
|
|
|
<div class="container">
|
|
|
<div class="header">
|
|
|
<h1>🏛️ AEGIS Economics AI</h1>
|
|
|
<p>Advanced Economic Analysis & Policy Insights</p>
|
|
|
</div>
|
|
|
|
|
|
<div id="chat-container" class="chat-container">
|
|
|
<div class="message ai-message">
|
|
|
Hello! I'm AEGIS Economics AI. Ask me about economic policies, market analysis, or financial strategies.
|
|
|
<div id="model-status" style="font-size: 0.8em; color: #666; margin-top: 5px;">
|
|
|
Checking model status...
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<div class="input-group">
|
|
|
<input type="text" id="user-input" class="input-field" placeholder="Ask about economics, policy, markets..." onkeypress="handleKeyPress(event)">
|
|
|
<button onclick="sendMessage()" class="send-btn">Send</button>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<script>
|
|
|
// Check model status on page load
|
|
|
async function checkModelStatus() {
|
|
|
try {
|
|
|
const response = await fetch('/health');
|
|
|
const data = await response.json();
|
|
|
const statusDiv = document.getElementById('model-status');
|
|
|
|
|
|
if (data.model_loaded) {
|
|
|
statusDiv.textContent = '✅ Model loaded and ready!';
|
|
|
statusDiv.style.color = '#28a745';
|
|
|
} else {
|
|
|
statusDiv.textContent = '⏳ Model loading... Please wait.';
|
|
|
statusDiv.style.color = '#ffc107';
|
|
|
// Try to load model
|
|
|
setTimeout(tryLoadModel, 2000);
|
|
|
}
|
|
|
} catch (error) {
|
|
|
const statusDiv = document.getElementById('model-status');
|
|
|
statusDiv.textContent = '❌ Connection error';
|
|
|
statusDiv.style.color = '#dc3545';
|
|
|
}
|
|
|
}
|
|
|
|
|
|
async function tryLoadModel() {
|
|
|
try {
|
|
|
const response = await fetch('/load_model', { method: 'POST' });
|
|
|
const data = await response.json();
|
|
|
|
|
|
if (data.success) {
|
|
|
const statusDiv = document.getElementById('model-status');
|
|
|
statusDiv.textContent = '✅ Model loaded successfully!';
|
|
|
statusDiv.style.color = '#28a745';
|
|
|
} else {
|
|
|
setTimeout(checkModelStatus, 5000); // Check again in 5 seconds
|
|
|
}
|
|
|
} catch (error) {
|
|
|
setTimeout(checkModelStatus, 5000);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// Call on page load
|
|
|
window.onload = checkModelStatus;
|
|
|
|
|
|
function handleKeyPress(event) {
|
|
|
if (event.key === 'Enter') {
|
|
|
sendMessage();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
function addMessage(content, isUser) {
|
|
|
const chatContainer = document.getElementById('chat-container');
|
|
|
const messageDiv = document.createElement('div');
|
|
|
messageDiv.className = `message ${isUser ? 'user-message' : 'ai-message'}`;
|
|
|
messageDiv.textContent = content;
|
|
|
chatContainer.appendChild(messageDiv);
|
|
|
chatContainer.scrollTop = chatContainer.scrollHeight;
|
|
|
}
|
|
|
|
|
|
function showLoading() {
|
|
|
const chatContainer = document.getElementById('chat-container');
|
|
|
const loadingDiv = document.createElement('div');
|
|
|
loadingDiv.className = 'loading';
|
|
|
loadingDiv.id = 'loading';
|
|
|
loadingDiv.textContent = 'AI is thinking...';
|
|
|
chatContainer.appendChild(loadingDiv);
|
|
|
chatContainer.scrollTop = chatContainer.scrollHeight;
|
|
|
}
|
|
|
|
|
|
function hideLoading() {
|
|
|
const loading = document.getElementById('loading');
|
|
|
if (loading) {
|
|
|
loading.remove();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
async function sendMessage() {
|
|
|
const input = document.getElementById('user-input');
|
|
|
const message = input.value.trim();
|
|
|
|
|
|
if (!message) return;
|
|
|
|
|
|
addMessage(message, true);
|
|
|
input.value = '';
|
|
|
showLoading();
|
|
|
|
|
|
try {
|
|
|
const response = await fetch('/chat', {
|
|
|
method: 'POST',
|
|
|
headers: {
|
|
|
'Content-Type': 'application/json',
|
|
|
},
|
|
|
body: JSON.stringify({ message: message })
|
|
|
});
|
|
|
|
|
|
const data = await response.json();
|
|
|
hideLoading();
|
|
|
|
|
|
if (data.response) {
|
|
|
addMessage(data.response, false);
|
|
|
} else {
|
|
|
addMessage('Sorry, I encountered an error. Please try again.', false);
|
|
|
}
|
|
|
} catch (error) {
|
|
|
hideLoading();
|
|
|
addMessage('Connection error. Please try again.', false);
|
|
|
}
|
|
|
}
|
|
|
</script>
|
|
|
</body>
|
|
|
</html>
|
|
|
"""
|
|
|
|
|
|
def load_model():
|
|
|
"""Load the Qwen2 model and tokenizer from HF repository"""
|
|
|
global model, tokenizer
|
|
|
|
|
|
try:
|
|
|
logger.info("Loading model and tokenizer from Hugging Face...")
|
|
|
|
|
|
|
|
|
model_repo = "Gaston895/Aegisecon1"
|
|
|
|
|
|
logger.info(f"Loading tokenizer from {model_repo}...")
|
|
|
tokenizer = AutoTokenizer.from_pretrained(
|
|
|
model_repo,
|
|
|
trust_remote_code=True,
|
|
|
use_auth_token=False
|
|
|
)
|
|
|
|
|
|
logger.info(f"Loading model from {model_repo}...")
|
|
|
model = AutoModelForCausalLM.from_pretrained(
|
|
|
model_repo,
|
|
|
torch_dtype=torch.float16,
|
|
|
device_map="cpu",
|
|
|
trust_remote_code=True,
|
|
|
use_auth_token=False,
|
|
|
low_cpu_mem_usage=True
|
|
|
)
|
|
|
|
|
|
logger.info("Model loaded successfully from HF repository!")
|
|
|
return True
|
|
|
|
|
|
except Exception as e:
|
|
|
logger.error(f"Error loading model from HF: {str(e)}")
|
|
|
|
|
|
try:
|
|
|
logger.info("Trying alternative loading method...")
|
|
|
tokenizer = AutoTokenizer.from_pretrained(
|
|
|
"Qwen/Qwen2-1.5B",
|
|
|
trust_remote_code=True
|
|
|
)
|
|
|
model = AutoModelForCausalLM.from_pretrained(
|
|
|
"Qwen/Qwen2-1.5B",
|
|
|
torch_dtype=torch.float16,
|
|
|
device_map="cpu",
|
|
|
trust_remote_code=True,
|
|
|
low_cpu_mem_usage=True
|
|
|
)
|
|
|
logger.info("Fallback model loaded successfully!")
|
|
|
return True
|
|
|
except Exception as e2:
|
|
|
logger.error(f"Fallback loading also failed: {str(e2)}")
|
|
|
return False
|
|
|
|
|
|
def generate_response(prompt):
|
|
|
"""Generate response using the loaded model"""
|
|
|
try:
|
|
|
if model is None or tokenizer is None:
|
|
|
return "Model is still loading, please wait a moment and try again..."
|
|
|
|
|
|
|
|
|
system_prompt = """You are AEGIS Economics AI, an expert economic analyst and policy advisor.
|
|
|
Provide clear, accurate, and insightful responses about economics, finance, markets, and policy.
|
|
|
Focus on practical analysis and actionable insights."""
|
|
|
|
|
|
full_prompt = f"{system_prompt}\n\nUser: {prompt}\nAssistant:"
|
|
|
|
|
|
|
|
|
inputs = tokenizer(full_prompt, return_tensors="pt", truncation=True, max_length=1024)
|
|
|
|
|
|
|
|
|
with torch.no_grad():
|
|
|
outputs = model.generate(
|
|
|
inputs.input_ids,
|
|
|
max_new_tokens=256,
|
|
|
temperature=0.7,
|
|
|
do_sample=True,
|
|
|
pad_token_id=tokenizer.eos_token_id,
|
|
|
repetition_penalty=1.1,
|
|
|
no_repeat_ngram_size=3
|
|
|
)
|
|
|
|
|
|
|
|
|
response = tokenizer.decode(outputs[0], skip_special_tokens=True)
|
|
|
|
|
|
|
|
|
if "Assistant:" in response:
|
|
|
response = response.split("Assistant:")[-1].strip()
|
|
|
|
|
|
return response
|
|
|
|
|
|
except Exception as e:
|
|
|
logger.error(f"Error generating response: {str(e)}")
|
|
|
return "I apologize, but I'm having trouble processing your request right now. Please try again in a moment."
|
|
|
|
|
|
@app.route('/')
|
|
|
def home():
|
|
|
"""Serve the main chat interface"""
|
|
|
return render_template_string(HTML_TEMPLATE)
|
|
|
|
|
|
@app.route('/chat', methods=['POST'])
|
|
|
def chat():
|
|
|
"""Handle chat messages"""
|
|
|
try:
|
|
|
data = request.get_json()
|
|
|
user_message = data.get('message', '')
|
|
|
|
|
|
if not user_message:
|
|
|
return jsonify({'error': 'No message provided'}), 400
|
|
|
|
|
|
|
|
|
ai_response = generate_response(user_message)
|
|
|
|
|
|
return jsonify({'response': ai_response})
|
|
|
|
|
|
except Exception as e:
|
|
|
logger.error(f"Error in chat endpoint: {str(e)}")
|
|
|
return jsonify({'error': 'Internal server error'}), 500
|
|
|
|
|
|
@app.route('/health')
|
|
|
def health():
|
|
|
"""Health check endpoint"""
|
|
|
return jsonify({
|
|
|
'status': 'healthy',
|
|
|
'model_loaded': model is not None,
|
|
|
'tokenizer_loaded': tokenizer is not None,
|
|
|
'model_info': 'Gaston895/Aegisecon1' if model is not None else 'Not loaded'
|
|
|
})
|
|
|
|
|
|
@app.route('/load_model', methods=['POST'])
|
|
|
def load_model_endpoint():
|
|
|
"""Endpoint to trigger model loading"""
|
|
|
try:
|
|
|
success = load_model()
|
|
|
return jsonify({
|
|
|
'success': success,
|
|
|
'model_loaded': model is not None,
|
|
|
'tokenizer_loaded': tokenizer is not None
|
|
|
})
|
|
|
except Exception as e:
|
|
|
return jsonify({'error': str(e)}), 500
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
|
logger.info("Starting AEGIS Economics AI...")
|
|
|
|
|
|
|
|
|
logger.info("Attempting to load model...")
|
|
|
model_loaded = load_model()
|
|
|
|
|
|
if model_loaded:
|
|
|
logger.info("Model loaded successfully, starting server...")
|
|
|
else:
|
|
|
logger.warning("Model failed to load, starting server anyway. Model can be loaded via /load_model endpoint.")
|
|
|
|
|
|
app.run(host='0.0.0.0', port=7860, debug=False) |