Spaces:
Runtime error
Runtime error
GitLab CI
commited on
Commit
·
3d7f69e
1
Parent(s):
9e4dc76
Update game build from GitLab CI
Browse files- server/ActionProcessor.py +20 -6
- server/AudioTranscriber.py +1 -2
- server/StandaloneApplication.py +19 -0
- server/__main__.py +12 -26
- server/static/godot/index.pck +0 -0
server/ActionProcessor.py
CHANGED
|
@@ -1,15 +1,32 @@
|
|
| 1 |
from threading import Thread
|
| 2 |
-
from
|
| 3 |
from typing import Dict, Any
|
| 4 |
import json
|
| 5 |
import re
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
|
| 7 |
|
| 8 |
class ActionProcessor(Thread):
|
| 9 |
-
def __init__(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
super().__init__()
|
| 11 |
self.text_queue = text_queue
|
| 12 |
self.action_queue = action_queue
|
|
|
|
| 13 |
self.daemon = True # Thread will exit when main program exits
|
| 14 |
|
| 15 |
def process_text(self, text: str) -> Dict[str, Any] | None:
|
|
@@ -48,9 +65,6 @@ class ActionProcessor(Thread):
|
|
| 48 |
if action:
|
| 49 |
self.action_queue.put(json.dumps(action))
|
| 50 |
|
| 51 |
-
# Mark the text as processed
|
| 52 |
-
self.text_queue.task_done()
|
| 53 |
-
|
| 54 |
except Exception as e:
|
| 55 |
-
|
| 56 |
continue
|
|
|
|
| 1 |
from threading import Thread
|
| 2 |
+
from multiprocessing import Queue
|
| 3 |
from typing import Dict, Any
|
| 4 |
import json
|
| 5 |
import re
|
| 6 |
+
import logging
|
| 7 |
+
import sys
|
| 8 |
+
|
| 9 |
+
# Configure logging
|
| 10 |
+
logging.basicConfig(
|
| 11 |
+
level=logging.INFO,
|
| 12 |
+
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
| 13 |
+
handlers=[logging.StreamHandler(sys.stdout)],
|
| 14 |
+
)
|
| 15 |
+
|
| 16 |
+
logger = logging.getLogger(__name__)
|
| 17 |
|
| 18 |
|
| 19 |
class ActionProcessor(Thread):
|
| 20 |
+
def __init__(
|
| 21 |
+
self,
|
| 22 |
+
text_queue: "Queue[str]",
|
| 23 |
+
action_queue: "Queue[str]",
|
| 24 |
+
mistral_api_key: str,
|
| 25 |
+
):
|
| 26 |
super().__init__()
|
| 27 |
self.text_queue = text_queue
|
| 28 |
self.action_queue = action_queue
|
| 29 |
+
self.mistral_api_key = mistral_api_key
|
| 30 |
self.daemon = True # Thread will exit when main program exits
|
| 31 |
|
| 32 |
def process_text(self, text: str) -> Dict[str, Any] | None:
|
|
|
|
| 65 |
if action:
|
| 66 |
self.action_queue.put(json.dumps(action))
|
| 67 |
|
|
|
|
|
|
|
|
|
|
| 68 |
except Exception as e:
|
| 69 |
+
logger.error(f"Error processing text: {str(e)}")
|
| 70 |
continue
|
server/AudioTranscriber.py
CHANGED
|
@@ -45,8 +45,7 @@ class AudioTranscriber(threading.Thread):
|
|
| 45 |
self.action_queue.put(segment.text)
|
| 46 |
# Still print for debugging
|
| 47 |
logger.info(
|
| 48 |
-
f"[
|
| 49 |
-
% (segment.start, segment.end, segment.text)
|
| 50 |
)
|
| 51 |
|
| 52 |
except Empty:
|
|
|
|
| 45 |
self.action_queue.put(segment.text)
|
| 46 |
# Still print for debugging
|
| 47 |
logger.info(
|
| 48 |
+
f"[{segment.start:.2f}s -> {segment.end:.2f}s] {segment.text}"
|
|
|
|
| 49 |
)
|
| 50 |
|
| 51 |
except Empty:
|
server/StandaloneApplication.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gunicorn.app.base
|
| 2 |
+
from flask import Flask
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
from typing import Any, Dict
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
class StandaloneApplication(gunicorn.app.base.BaseApplication):
|
| 9 |
+
def __init__(self, app: Flask, options: Optional[Dict[str, Any]] = None):
|
| 10 |
+
self.options = options or {}
|
| 11 |
+
self.application = app
|
| 12 |
+
super().__init__()
|
| 13 |
+
|
| 14 |
+
def load_config(self):
|
| 15 |
+
for key, value in self.options.items():
|
| 16 |
+
self.cfg.set(key.lower(), value)
|
| 17 |
+
|
| 18 |
+
def load(self):
|
| 19 |
+
return self.application
|
server/__main__.py
CHANGED
|
@@ -1,18 +1,17 @@
|
|
| 1 |
import io
|
| 2 |
-
import
|
| 3 |
-
from flask import Flask, send_from_directory, jsonify, request, abort
|
| 4 |
import os
|
| 5 |
-
import gunicorn.app.base
|
| 6 |
from flask_cors import CORS
|
| 7 |
from multiprocessing import Queue
|
| 8 |
import base64
|
| 9 |
-
from typing import Any,
|
| 10 |
-
from
|
| 11 |
import logging
|
| 12 |
import sys
|
| 13 |
|
| 14 |
from server.AudioTranscriber import AudioTranscriber
|
| 15 |
from server.ActionProcessor import ActionProcessor
|
|
|
|
| 16 |
|
| 17 |
# Configure logging
|
| 18 |
logging.basicConfig(
|
|
@@ -42,7 +41,7 @@ _ = CORS(
|
|
| 42 |
|
| 43 |
|
| 44 |
@app.after_request
|
| 45 |
-
def add_header(response):
|
| 46 |
# Add permissive CORS headers
|
| 47 |
response.headers["Access-Control-Allow-Origin"] = "*"
|
| 48 |
response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE, OPTIONS"
|
|
@@ -90,7 +89,6 @@ def get_data():
|
|
| 90 |
|
| 91 |
@app.route("/api/process", methods=["POST"])
|
| 92 |
def process_data():
|
| 93 |
-
logger.info("Processing data")
|
| 94 |
try:
|
| 95 |
# Check content type
|
| 96 |
content_type = request.headers.get("Content-Type", "")
|
|
@@ -145,7 +143,7 @@ def process_data():
|
|
| 145 |
|
| 146 |
|
| 147 |
@app.route("/api/actions", methods=["GET"])
|
| 148 |
-
def get_actions() -> Tuple[
|
| 149 |
"""Retrieve and clear all pending actions from the queue"""
|
| 150 |
actions: List[Dict[str, Any]] = []
|
| 151 |
|
|
@@ -156,7 +154,7 @@ def get_actions() -> Tuple[Dict[str, Any], int]:
|
|
| 156 |
except Exception:
|
| 157 |
break
|
| 158 |
|
| 159 |
-
return jsonify({"actions":
|
| 160 |
|
| 161 |
|
| 162 |
@app.route("/<path:path>")
|
|
@@ -167,23 +165,7 @@ def serve_static(path: str):
|
|
| 167 |
abort(404, description=f"File {path} not found in static folder")
|
| 168 |
|
| 169 |
|
| 170 |
-
class StandaloneApplication(gunicorn.app.base.BaseApplication):
|
| 171 |
-
def __init__(self, app: Flask, options: Optional[Dict[str, Any]] = None):
|
| 172 |
-
self.options = options or {}
|
| 173 |
-
self.application = app
|
| 174 |
-
super().__init__()
|
| 175 |
-
|
| 176 |
-
def load_config(self):
|
| 177 |
-
for key, value in self.options.items():
|
| 178 |
-
self.cfg.set(key.lower(), value)
|
| 179 |
-
|
| 180 |
-
def load(self):
|
| 181 |
-
return self.application
|
| 182 |
-
|
| 183 |
-
|
| 184 |
if __name__ == "__main__":
|
| 185 |
-
logger.info(f"Static folder path: {app.static_folder}")
|
| 186 |
-
logger.info(f"Static folder exists: {os.path.exists(app.static_folder)}")
|
| 187 |
if os.path.exists(app.static_folder):
|
| 188 |
logger.info(f"Static folder contents: {os.listdir(app.static_folder)}")
|
| 189 |
|
|
@@ -194,7 +176,11 @@ if __name__ == "__main__":
|
|
| 194 |
transcriber.start()
|
| 195 |
|
| 196 |
# Start the action processor thread
|
| 197 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 198 |
action_processor.start()
|
| 199 |
|
| 200 |
options: Any = {
|
|
|
|
| 1 |
import io
|
| 2 |
+
from flask import Flask, Response, send_from_directory, jsonify, request, abort
|
|
|
|
| 3 |
import os
|
|
|
|
| 4 |
from flask_cors import CORS
|
| 5 |
from multiprocessing import Queue
|
| 6 |
import base64
|
| 7 |
+
from typing import Any, List, Dict, Tuple
|
| 8 |
+
from multiprocessing import Queue
|
| 9 |
import logging
|
| 10 |
import sys
|
| 11 |
|
| 12 |
from server.AudioTranscriber import AudioTranscriber
|
| 13 |
from server.ActionProcessor import ActionProcessor
|
| 14 |
+
from server.StandaloneApplication import StandaloneApplication
|
| 15 |
|
| 16 |
# Configure logging
|
| 17 |
logging.basicConfig(
|
|
|
|
| 41 |
|
| 42 |
|
| 43 |
@app.after_request
|
| 44 |
+
def add_header(response: Response):
|
| 45 |
# Add permissive CORS headers
|
| 46 |
response.headers["Access-Control-Allow-Origin"] = "*"
|
| 47 |
response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE, OPTIONS"
|
|
|
|
| 89 |
|
| 90 |
@app.route("/api/process", methods=["POST"])
|
| 91 |
def process_data():
|
|
|
|
| 92 |
try:
|
| 93 |
# Check content type
|
| 94 |
content_type = request.headers.get("Content-Type", "")
|
|
|
|
| 143 |
|
| 144 |
|
| 145 |
@app.route("/api/actions", methods=["GET"])
|
| 146 |
+
def get_actions() -> Tuple[Response, int]:
|
| 147 |
"""Retrieve and clear all pending actions from the queue"""
|
| 148 |
actions: List[Dict[str, Any]] = []
|
| 149 |
|
|
|
|
| 154 |
except Exception:
|
| 155 |
break
|
| 156 |
|
| 157 |
+
return jsonify({"actions": actions, "status": "success"}), 200
|
| 158 |
|
| 159 |
|
| 160 |
@app.route("/<path:path>")
|
|
|
|
| 165 |
abort(404, description=f"File {path} not found in static folder")
|
| 166 |
|
| 167 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 168 |
if __name__ == "__main__":
|
|
|
|
|
|
|
| 169 |
if os.path.exists(app.static_folder):
|
| 170 |
logger.info(f"Static folder contents: {os.listdir(app.static_folder)}")
|
| 171 |
|
|
|
|
| 176 |
transcriber.start()
|
| 177 |
|
| 178 |
# Start the action processor thread
|
| 179 |
+
MISTRAL_API_KEY = os.getenv("MISTRAL_API_KEY")
|
| 180 |
+
if not MISTRAL_API_KEY:
|
| 181 |
+
raise ValueError("MISTRAL_API_KEY is not set")
|
| 182 |
+
|
| 183 |
+
action_processor = ActionProcessor(text_queue, action_queue, MISTRAL_API_KEY)
|
| 184 |
action_processor.start()
|
| 185 |
|
| 186 |
options: Any = {
|
server/static/godot/index.pck
CHANGED
|
Binary files a/server/static/godot/index.pck and b/server/static/godot/index.pck differ
|
|
|