219 lines
9.4 KiB
Python
219 lines
9.4 KiB
Python
import time
|
||
import re
|
||
|
||
# Сохраняем оригинальную функцию time.time
|
||
_real_time = time.time
|
||
# Переопределяем time.time для смещения времени на 1 секунду назад
|
||
time.time = lambda: _real_time() - 1
|
||
|
||
from flask import Flask, request, jsonify
|
||
from flask_cors import CORS
|
||
from google.oauth2 import id_token
|
||
from google.auth.transport import requests
|
||
import logging
|
||
|
||
# Импортируем функцию обработки из model.py
|
||
from model import process_query_with_mistral
|
||
import psycopg2
|
||
from psycopg2.extras import RealDictCursor
|
||
|
||
# Параметры подключения к базе данных
|
||
DATABASE_CONFIG = {
|
||
"dbname": "postgres",
|
||
"user": "postgres",
|
||
"password": "healthai!",
|
||
"host": "health-ai-user-db.cxeum6cmct3r.eu-west-1.rds.amazonaws.com",
|
||
"port": 5432,
|
||
}
|
||
|
||
# Подключение к базе данных
|
||
try:
|
||
conn = psycopg2.connect(**DATABASE_CONFIG)
|
||
print("Подключение к базе данных успешно установлено")
|
||
except Exception as e:
|
||
print(f"Ошибка подключения к базе данных: {e}")
|
||
conn = None
|
||
|
||
logging.basicConfig(level=logging.INFO)
|
||
logger = logging.getLogger(__name__)
|
||
|
||
# Создаем Flask приложение
|
||
app = Flask(__name__)
|
||
CORS(app, resources={r"/api/*": {"origins": "http://localhost:5173"}})
|
||
|
||
# Ваш Google Client ID
|
||
CLIENT_ID = "532143017111-4eqtlp0oejqaovj6rf5l1ergvhrp4vao.apps.googleusercontent.com"
|
||
|
||
def save_user_to_db(name, email, google_id=None, password=None):
|
||
try:
|
||
with conn.cursor(cursor_factory=RealDictCursor) as cur:
|
||
cur.execute(
|
||
"""
|
||
INSERT INTO users (name, email, google_id, password)
|
||
VALUES (%s, %s, %s, %s)
|
||
ON CONFLICT (email) DO NOTHING
|
||
""",
|
||
(name, email, google_id, password)
|
||
)
|
||
conn.commit()
|
||
print(f"User {name} ({email}) saved successfully!")
|
||
except Exception as e:
|
||
print(f"Error saving user to database: {e}")
|
||
|
||
# Эндпоинт для верификации токенов Google OAuth
|
||
@app.route('/api/verify', methods=['POST'])
|
||
def verify_token():
|
||
data = request.get_json()
|
||
token = data.get('token')
|
||
if not token:
|
||
return jsonify({'error': 'No token provided'}), 400
|
||
try:
|
||
id_info = id_token.verify_oauth2_token(token, requests.Request(), CLIENT_ID)
|
||
user_email = id_info.get('email')
|
||
user_name = id_info.get('name')
|
||
google_id = id_info.get('sub') # Уникальный идентификатор пользователя Google
|
||
save_user_to_db(name=user_name, email=user_email, google_id=google_id)
|
||
logger.info(f"User authenticated and saved: {user_name} ({user_email})")
|
||
return jsonify({'message': 'Authentication successful', 'user': {'email': user_email, 'name': user_name}}), 200
|
||
except ValueError as e:
|
||
logger.error(f"Token verification failed: {e}")
|
||
return jsonify({'error': 'Invalid token'}), 400
|
||
|
||
# Эндпоинт для регистрации пользователя с проверкой на дублирование
|
||
@app.route('/api/register', methods=['POST'])
|
||
def register():
|
||
data = request.get_json()
|
||
name = data.get('name')
|
||
email = data.get('email')
|
||
password = data.get('password') # Рекомендуется хэшировать пароль
|
||
if not all([name, email, password]):
|
||
return jsonify({'error': 'All fields are required'}), 400
|
||
try:
|
||
with conn.cursor(cursor_factory=RealDictCursor) as cur:
|
||
cur.execute("SELECT * FROM users WHERE email = %s", (email,))
|
||
existing_user = cur.fetchone()
|
||
if existing_user:
|
||
return jsonify({'error': 'User already exists'}), 409
|
||
save_user_to_db(name=name, email=email, password=password)
|
||
return jsonify({'message': 'User registered successfully'}), 201
|
||
except Exception as e:
|
||
return jsonify({'error': str(e)}), 500
|
||
|
||
# Эндпоинт для логина пользователя
|
||
@app.route('/api/login', methods=['POST'])
|
||
def login():
|
||
data = request.get_json()
|
||
email = data.get('email')
|
||
password = data.get('password')
|
||
if not all([email, password]):
|
||
return jsonify({'error': 'Email and password are required'}), 400
|
||
try:
|
||
with conn.cursor(cursor_factory=RealDictCursor) as cur:
|
||
cur.execute("SELECT * FROM users WHERE email = %s", (email,))
|
||
user = cur.fetchone()
|
||
if not user:
|
||
return jsonify({'error': 'Invalid credentials'}), 401
|
||
if user.get('password') != password:
|
||
return jsonify({'error': 'Invalid credentials'}), 401
|
||
return jsonify({'message': 'Login successful', 'user': {'name': user.get('name'), 'email': user.get('email')}}), 200
|
||
except Exception as e:
|
||
return jsonify({'error': str(e)}), 500
|
||
|
||
# Объединённый эндпоинт для обработки запроса чата
|
||
@app.route('/api/chat', methods=['POST'])
|
||
def chat():
|
||
data = request.get_json()
|
||
query = data.get('query', '')
|
||
user_email = data.get('email') # email пользователя (если передается)
|
||
chat_id = data.get('chatId') # параметр для обновления существующего чата
|
||
|
||
if not query:
|
||
return jsonify({'error': 'No query provided'}), 400
|
||
|
||
# Вызов функции для обработки запроса (например, чат-бота)
|
||
response_obj = process_query_with_mistral(query)
|
||
best_answer = ""
|
||
if isinstance(response_obj, dict):
|
||
best_answer = response_obj.get("best_answer", "")
|
||
else:
|
||
best_answer = str(response_obj)
|
||
|
||
# Форматирование ответа с использованием re.sub
|
||
best_answer = re.sub(r'[*#]', '', best_answer)
|
||
best_answer = re.sub(r'(\d\.\s)', r'\n\n\1', best_answer)
|
||
best_answer = re.sub(r':\s-', r':\n-', best_answer)
|
||
|
||
# Если chatId передан, обновляем существующий чат, иначе создаем новый чат
|
||
if chat_id:
|
||
try:
|
||
with conn.cursor(cursor_factory=RealDictCursor) as cur:
|
||
cur.execute("SELECT chat FROM chat_history WHERE id = %s", (chat_id,))
|
||
existing_chat = cur.fetchone()
|
||
if existing_chat:
|
||
updated_chat = existing_chat['chat'] + f"\nUser: {query}\nBot: {best_answer}"
|
||
cur.execute("UPDATE chat_history SET chat = %s WHERE id = %s", (updated_chat, chat_id))
|
||
conn.commit()
|
||
else:
|
||
with conn.cursor(cursor_factory=RealDictCursor) as cur2:
|
||
cur2.execute(
|
||
"INSERT INTO chat_history (user_email, chat) VALUES (%s, %s) RETURNING id",
|
||
(user_email, f"User: {query}\nBot: {best_answer}")
|
||
)
|
||
new_chat_id = cur2.fetchone()['id']
|
||
conn.commit()
|
||
chat_id = new_chat_id
|
||
except Exception as e:
|
||
return jsonify({'error': str(e)}), 500
|
||
else:
|
||
try:
|
||
with conn.cursor(cursor_factory=RealDictCursor) as cur:
|
||
cur.execute(
|
||
"INSERT INTO chat_history (user_email, chat) VALUES (%s, %s) RETURNING id",
|
||
(user_email, f"User: {query}\nBot: {best_answer}")
|
||
)
|
||
new_chat_id = cur.fetchone()['id']
|
||
conn.commit()
|
||
chat_id = new_chat_id
|
||
except Exception as e:
|
||
return jsonify({'error': str(e)}), 500
|
||
|
||
# Возвращаем текстовый ответ и новый chatId, если чат был создан
|
||
return jsonify({'response': {'best_answer': best_answer, 'model': 'Mistral Small Vector', 'chatId': chat_id}}), 200
|
||
|
||
# Эндпоинт для получения истории чатов конкретного пользователя
|
||
@app.route('/api/chat_history', methods=['GET'])
|
||
def get_chat_history():
|
||
user_email = request.args.get('email')
|
||
if not user_email:
|
||
return jsonify({'error': 'User email is required'}), 400
|
||
try:
|
||
with conn.cursor(cursor_factory=RealDictCursor) as cur:
|
||
cur.execute(
|
||
"SELECT id, chat, created_at FROM chat_history WHERE user_email = %s ORDER BY created_at DESC",
|
||
(user_email,)
|
||
)
|
||
history = cur.fetchall()
|
||
return jsonify({'history': history}), 200
|
||
except Exception as e:
|
||
return jsonify({'error': str(e)}), 500
|
||
|
||
# Эндпоинт для получения деталей чата по ID
|
||
@app.route('/api/chat_history_detail', methods=['GET'])
|
||
def chat_history_detail():
|
||
chat_id = request.args.get('id')
|
||
if not chat_id:
|
||
return jsonify({'error': 'Chat id is required'}), 400
|
||
try:
|
||
with conn.cursor(cursor_factory=RealDictCursor) as cur:
|
||
cur.execute("SELECT id, chat, created_at FROM chat_history WHERE id = %s", (chat_id,))
|
||
chat = cur.fetchone()
|
||
if not chat:
|
||
return jsonify({'error': 'Chat not found'}), 404
|
||
return jsonify({'chat': chat}), 200
|
||
except Exception as e:
|
||
return jsonify({'error': str(e)}), 500
|
||
|
||
if __name__ == '__main__':
|
||
app.run(host='0.0.0.0', port=5000, debug=True)
|
||
|