Spaces:
Paused
Paused
Download api.py from matrixcoder/emote-api: direct link, hf CLI and curl.
- Browser
- Download file 12.5 kB
-
https://huggingface.co/spaces/matrixcoder/emote-api/resolve/main/api.py
- Command line
-
hf download hf://spaces/matrixcoder/emote-api/api.py
-
curl -L -o api.py https://huggingface.co/spaces/matrixcoder/emote-api/resolve/main/api.py
12.5 kB
| # ============================================ | |
| # PRODUCTION API WITH WEBSOCKET - api.py | |
| # Real-time team updates, no JSON storage | |
| # ============================================ | |
| from flask import Flask, request, jsonify | |
| from flask_cors import CORS | |
| from flask_sock import Sock | |
| import queue | |
| import json | |
| import time | |
| app = Flask(__name__) | |
| CORS(app) | |
| sock = Sock(app) | |
| command_queue = queue.Queue() | |
| # WebSocket clients list | |
| websocket_clients = [] | |
| # ============================================ | |
| # WEBSOCKET - Real-time Team Updates | |
| # ============================================ | |
| def websocket(ws): | |
| """WebSocket connection for real-time updates""" | |
| print(f"[WS] Client connected") | |
| websocket_clients.append(ws) | |
| try: | |
| # Send initial team status | |
| team_status = get_live_team_status() | |
| ws.send(json.dumps({ | |
| 'type': 'initial', | |
| 'data': team_status | |
| })) | |
| # Keep connection alive | |
| while True: | |
| # Receive messages from client (optional) | |
| message = ws.receive(timeout=30) | |
| if message: | |
| data = json.loads(message) | |
| # Handle client requests | |
| if data.get('type') == 'get_team': | |
| team_status = get_live_team_status() | |
| ws.send(json.dumps({ | |
| 'type': 'team_update', | |
| 'data': team_status | |
| })) | |
| except Exception as e: | |
| print(f"[WS] Client disconnected: {e}") | |
| finally: | |
| if ws in websocket_clients: | |
| websocket_clients.remove(ws) | |
| print(f"[WS] Client removed") | |
| def broadcast_team_update(event_type, data): | |
| """Broadcast team updates to all connected WebSocket clients""" | |
| # DEBUG: Log what we're sending | |
| if event_type in ['member_joined', 'member_left']: | |
| player = data.get('player', {}) | |
| print(f"[WSβ] {event_type}: {player.get('name')} (UID: {player.get('uid')})") | |
| message = json.dumps({ | |
| 'type': event_type, | |
| 'data': data, | |
| 'timestamp': time.time() | |
| }, ensure_ascii=False) # Important for Unicode characters | |
| disconnected = [] | |
| sent_count = 0 | |
| for client in websocket_clients: | |
| try: | |
| client.send(message) | |
| sent_count += 1 | |
| except Exception as e: | |
| print(f"[WSβ] Failed to send to client: {e}") | |
| disconnected.append(client) | |
| if sent_count > 0: | |
| print(f"[WSβ] Sent to {sent_count} client(s)") | |
| # Remove disconnected clients | |
| for client in disconnected: | |
| if client in websocket_clients: | |
| websocket_clients.remove(client) | |
| # ============================================ | |
| # JOIN TEAM API | |
| # ============================================ | |
| def join_team(): | |
| """Join a team using teamcode""" | |
| try: | |
| if request.method == 'GET': | |
| teamcode = request.args.get('teamcode') | |
| else: | |
| data = request.get_json(silent=True) | |
| teamcode = data.get('teamcode') if data else None | |
| if not teamcode: | |
| return jsonify({ | |
| 'success': False, | |
| 'message': 'teamcode is required' | |
| }), 400 | |
| command_queue.put({ | |
| 'type': 'join', | |
| 'teamcode': teamcode | |
| }) | |
| return jsonify({ | |
| 'success': True, | |
| 'message': 'Join command queued', | |
| 'teamcode': teamcode | |
| }) | |
| except Exception as e: | |
| return jsonify({ | |
| 'success': False, | |
| 'message': str(e) | |
| }), 500 | |
| # ============================================ | |
| # EMOTE API | |
| # ============================================ | |
| def send_emote(): | |
| """Send emote to players (bot must be in team)""" | |
| try: | |
| data = request.get_json(silent=True) | |
| if not data: | |
| return jsonify({ | |
| 'success': False, | |
| 'message': 'JSON body required' | |
| }), 400 | |
| uids = data.get('uids') | |
| emote_code = data.get('emote_code') | |
| if not emote_code: | |
| return jsonify({ | |
| 'success': False, | |
| 'message': 'emote_code is required' | |
| }), 400 | |
| if not isinstance(uids, list) or len(uids) == 0: | |
| return jsonify({ | |
| 'success': False, | |
| 'message': 'uids must be a non-empty array' | |
| }), 400 | |
| if len(uids) > 5: | |
| return jsonify({ | |
| 'success': False, | |
| 'message': 'Maximum 5 UIDs allowed per request' | |
| }), 400 | |
| # Check if bot is in team (LIVE CHECK) | |
| team_status = get_live_team_status() | |
| if not team_status['in_team']: | |
| return jsonify({ | |
| 'success': False, | |
| 'message': 'Bot is not in any team. Join a team first.', | |
| 'in_team': False | |
| }), 400 | |
| # Queue emote command | |
| command_queue.put({ | |
| 'type': 'emote', | |
| 'uids': uids, | |
| 'emote_code': emote_code | |
| }) | |
| return jsonify({ | |
| 'success': True, | |
| 'message': f'Emote queued for {len(uids)} player(s)', | |
| 'uids': uids, | |
| 'emote_code': emote_code, | |
| 'in_team': True | |
| }) | |
| except Exception as e: | |
| return jsonify({ | |
| 'success': False, | |
| 'message': str(e) | |
| }), 500 | |
| # ============================================ | |
| # EMOTE ALL TEAM MEMBERS | |
| # ============================================ | |
| def emote_team(): | |
| """Send emote to all team members""" | |
| try: | |
| data = request.get_json(silent=True) | |
| if not data: | |
| return jsonify({ | |
| 'success': False, | |
| 'message': 'JSON body required' | |
| }), 400 | |
| emote_code = data.get('emote_code') | |
| if not emote_code: | |
| return jsonify({ | |
| 'success': False, | |
| 'message': 'emote_code is required' | |
| }), 400 | |
| # Get LIVE team status | |
| team_status = get_live_team_status() | |
| if not team_status['in_team']: | |
| return jsonify({ | |
| 'success': False, | |
| 'message': 'Bot is not in any team', | |
| 'in_team': False | |
| }), 400 | |
| if not team_status.get('members'): | |
| return jsonify({ | |
| 'success': False, | |
| 'message': 'No team members found', | |
| 'in_team': True | |
| }), 400 | |
| uids = [m['uid'] for m in team_status['members']] | |
| # Queue emote for all members | |
| command_queue.put({ | |
| 'type': 'emote', | |
| 'uids': uids, | |
| 'emote_code': emote_code | |
| }) | |
| return jsonify({ | |
| 'success': True, | |
| 'message': f'Emote queued for all {len(uids)} team members', | |
| 'uids': uids, | |
| 'emote_code': emote_code, | |
| 'team_size': len(uids) | |
| }) | |
| except Exception as e: | |
| return jsonify({ | |
| 'success': False, | |
| 'message': str(e) | |
| }), 500 | |
| # ============================================ | |
| # GET TEAM MEMBERS - LIVE DATA | |
| # ============================================ | |
| def get_team_members(): | |
| """Get current team members - LIVE from memory, not JSON""" | |
| try: | |
| team_status = get_live_team_status() | |
| # Bot is NOT in team | |
| if not team_status['in_team']: | |
| return jsonify({ | |
| 'success': False, | |
| 'message': 'Bot is not in any team', | |
| 'in_team': False, | |
| 'members': [], | |
| 'total_members': 0 | |
| }) | |
| # Bot IS in team - return LIVE data | |
| return jsonify({ | |
| 'success': True, | |
| 'message': 'Team members retrieved', | |
| 'in_team': True, | |
| 'total_members': team_status['total_members'], | |
| 'leader_uid': team_status['leader_uid'], | |
| 'members': team_status['members'] | |
| }) | |
| except Exception as e: | |
| return jsonify({ | |
| 'success': False, | |
| 'message': str(e) | |
| }), 500 | |
| # ============================================ | |
| # BOT STATUS | |
| # ============================================ | |
| def bot_status(): | |
| """Get bot connection status""" | |
| try: | |
| from main import online_writer, whisper_writer, key, iv, region | |
| connections = { | |
| 'online': online_writer is not None, | |
| 'chat': whisper_writer is not None, | |
| 'authenticated': key is not None and iv is not None, | |
| 'region': region | |
| } | |
| team_status = get_live_team_status() | |
| return jsonify({ | |
| 'success': True, | |
| 'bot_online': connections['online'] and connections['chat'], | |
| 'connections': connections, | |
| 'team': team_status, | |
| 'queue_size': command_queue.qsize(), | |
| 'ws_clients': len(websocket_clients) | |
| }) | |
| except ImportError: | |
| return jsonify({ | |
| 'success': False, | |
| 'message': 'Bot not running', | |
| 'bot_online': False | |
| }), 503 | |
| # ============================================ | |
| # HOME / API INFO | |
| # ============================================ | |
| def home(): | |
| """API documentation""" | |
| return jsonify({ | |
| 'name': 'FF Emote Bot API', | |
| 'version': '2.0', | |
| 'status': 'online', | |
| 'websocket': 'ws://host:5000/ws', | |
| 'endpoints': { | |
| 'POST /join': 'Join team - Body: {"teamcode": "ABC123"}', | |
| 'POST /emote': 'Send emote - Body: {"uids": ["123"], "emote_code": "909000001"}', | |
| 'POST /emote/team': 'Emote all team - Body: {"emote_code": "909000001"}', | |
| 'GET /team/members': 'Get team members (LIVE)', | |
| 'GET /status': 'Bot status', | |
| 'WS /ws': 'WebSocket for real-time updates' | |
| } | |
| }) | |
| # ============================================ | |
| # HELPER FUNCTIONS - LIVE DATA FROM MEMORY | |
| # ============================================ | |
| def get_live_team_status(): | |
| """Get LIVE team status from bot memory (not JSON file)""" | |
| try: | |
| from main import team_collection_active, team_members_data, current_team_leader | |
| # Check if bot is actually in a team RIGHT NOW | |
| in_team = team_collection_active and len(team_members_data) > 0 | |
| if not in_team: | |
| return { | |
| 'in_team': False, | |
| 'total_members': 0, | |
| 'leader_uid': None, | |
| 'members': [] | |
| } | |
| return { | |
| 'in_team': True, | |
| 'total_members': len(team_members_data), | |
| 'leader_uid': str(current_team_leader) if current_team_leader else None, | |
| 'members': team_members_data | |
| } | |
| except: | |
| return { | |
| 'in_team': False, | |
| 'total_members': 0, | |
| 'leader_uid': None, | |
| 'members': [] | |
| } | |
| # ============================================ | |
| # RUN SERVER | |
| # ============================================ | |
| if __name__ == '__main__': | |
| print(""" | |
| ββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β FF Emote Bot API - Production v2.0 β | |
| β with WebSocket Support β | |
| ββββββββββββββββββββββββββββββββββββββββββββββββ | |
| π‘ HTTP API: http://0.0.0.0:5000 | |
| π WebSocket: ws://0.0.0.0:5000/ws | |
| Endpoints: | |
| β’ POST /join - Join team | |
| β’ POST /emote - Send emote (requires team) | |
| β’ POST /emote/team - Emote all team members | |
| β’ GET /team/members - Get team info (LIVE) | |
| β’ GET /status - Bot status | |
| β’ WS /ws - Real-time updates | |
| """) | |
| app.run(host='0.0.0.0', port=7860, debug=False) |