|
from flask import Flask, render_template, request, jsonify |
|
from flask_socketio import SocketIO, emit, join_room |
|
from flask_cors import CORS |
|
import os |
|
import requests |
|
import json |
|
import uuid |
|
from datetime import datetime |
|
from dotenv import load_dotenv |
|
import logging |
|
from werkzeug.utils import secure_filename |
|
import random |
|
|
|
|
|
app = Flask(__name__) |
|
CORS(app) |
|
app.config['SECRET_KEY'] = os.urandom(24) |
|
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 |
|
|
|
|
|
socketio = SocketIO(app, |
|
cors_allowed_origins="*", |
|
async_mode='eventlet', |
|
logger=True, |
|
engineio_logger=True |
|
) |
|
|
|
|
|
load_dotenv() |
|
MISTRAL_API_KEY = os.getenv('MISTRAL_API_KEY') |
|
ELEVENLABS_API_KEY = os.getenv('ELEVENLABS_API_KEY') |
|
|
|
|
|
logging.basicConfig(level=logging.INFO) |
|
logger = logging.getLogger(__name__) |
|
|
|
class GameState: |
|
"""Manages all active game sessions with WebSocket room support""" |
|
|
|
def __init__(self): |
|
self.games = {} |
|
self.cleanup_interval = 3600 |
|
|
|
def create_game(self): |
|
game_id = str(uuid.uuid4()) |
|
self.games[game_id] = { |
|
'players': [], |
|
'current_phase': 'setup', |
|
'recordings': {}, |
|
'impostor': None, |
|
'votes': {}, |
|
'question': None, |
|
'impostor_answer': None, |
|
'modified_recording': None, |
|
'round_number': 1, |
|
'start_time': datetime.now().isoformat(), |
|
'completed_rounds': [], |
|
'score': {'impostor_wins': 0, 'player_wins': 0}, |
|
'socket_room': f'game_{game_id}' |
|
} |
|
return game_id |
|
|
|
def cleanup_inactive_games(self): |
|
current_time = datetime.now() |
|
for game_id, game in list(self.games.items()): |
|
if (current_time - datetime.fromisoformat(game['start_time'])).total_seconds() > 7200: |
|
del self.games[game_id] |
|
|
|
game_state = GameState() |
|
|
|
|
|
@socketio.on('connect') |
|
def handle_connect(): |
|
logger.info('Client connected: %s', request.sid) |
|
|
|
@socketio.on('disconnect') |
|
def handle_disconnect(): |
|
logger.info('Client disconnected: %s', request.sid) |
|
|
|
@socketio.on('create_game') |
|
def handle_create_game(): |
|
try: |
|
game_id = game_state.create_game() |
|
emit('game_created', { |
|
'status': 'success', |
|
'gameId': game_id, |
|
'message': 'Game created successfully' |
|
}) |
|
logger.info('Created game: %s', game_id) |
|
except Exception as e: |
|
logger.error('Game creation failed: %s', str(e)) |
|
emit('game_created', { |
|
'status': 'error', |
|
'error': 'Game creation failed', |
|
'details': str(e) |
|
}) |
|
|
|
@socketio.on('join_game') |
|
def handle_join_game(data): |
|
try: |
|
game_id = data.get('game_id') |
|
player_name = data.get('player_name') |
|
|
|
if not game_id or not player_name: |
|
raise ValueError('Missing game ID or player name') |
|
|
|
if game_id not in game_state.games: |
|
raise KeyError('Game not found') |
|
|
|
game = game_state.games[game_id] |
|
|
|
if len(game['players']) >= 5: |
|
raise ValueError('Game is full') |
|
|
|
player_id = len(game['players']) + 1 |
|
new_player = { |
|
'id': player_id, |
|
'name': player_name, |
|
'socket_id': request.sid |
|
} |
|
game['players'].append(new_player) |
|
join_room(game['socket_room']) |
|
|
|
emit('player_joined', { |
|
'status': 'success', |
|
'player': new_player |
|
}, room=game['socket_room']) |
|
|
|
logger.info('Player %s joined game %s', player_name, game_id) |
|
|
|
except Exception as e: |
|
logger.error('Join game error: %s', str(e)) |
|
emit('join_failed', { |
|
'status': 'error', |
|
'error': str(e) |
|
}) |
|
|
|
|
|
@app.route('/') |
|
def home(): |
|
return render_template('index.html') |
|
|
|
@app.route('/api/start_game', methods=['POST']) |
|
def start_game(): |
|
try: |
|
data = request.get_json() |
|
game_id = data.get('game_id') |
|
|
|
if not game_id or game_id not in game_state.games: |
|
return jsonify({'status': 'error', 'error': 'Invalid game ID'}), 400 |
|
|
|
game = game_state.games[game_id] |
|
game['current_phase'] = 'recording' |
|
|
|
socketio.emit('round_start', { |
|
'phase': 'recording', |
|
'duration': 30 |
|
}, room=game['socket_room']) |
|
|
|
return jsonify({'status': 'success', 'message': 'Game started'}) |
|
|
|
except Exception as e: |
|
logger.error('Start game error: %s', str(e)) |
|
return jsonify({'status': 'error', 'error': str(e)}), 500 |
|
|
|
|
|
async def generate_question(): |
|
|
|
pass |
|
|
|
async def generate_impostor_answer(question): |
|
|
|
pass |
|
|
|
async def clone_voice(audio_file): |
|
|
|
pass |
|
|
|
async def generate_cloned_speech(voice_id, text): |
|
|
|
pass |
|
|
|
if __name__ == '__main__': |
|
os.makedirs('temp', exist_ok=True) |
|
socketio.run(app, |
|
host='0.0.0.0', |
|
port=7860, |
|
debug=True, |
|
allow_unsafe_werkzeug=True, |
|
use_reloader=False |
|
) |