ParentalControl / server /__main__.py
GitLab CI
Update game build from GitLab CI
6831f1f
raw
history blame
6.1 kB
import io
import json
from flask import Flask, send_from_directory, jsonify, request, abort
import os
import gunicorn.app.base
from flask_cors import CORS
from multiprocessing import Queue
import base64
from typing import Any, Optional, List, Dict, Tuple
from queue import Queue
from server.AudioTranscriber import AudioTranscriber
from server.ActionProcessor import ActionProcessor
# Use a directory in the user's home folder for static files
STATIC_DIR = "/app/server/static" if os.getenv("DEBUG") != "true" else "./server"
audio_queue: "Queue[io.BytesIO]" = Queue()
text_queue: "Queue[str]" = Queue()
action_queue: "Queue[str]" = Queue()
app = Flask(__name__, static_folder=STATIC_DIR)
_ = CORS(
app,
origins=["*"],
methods=["GET", "POST", "OPTIONS"],
allow_headers=["Content-Type", "Authorization"],
)
@app.after_request
def add_header(response):
# Add permissive CORS headers
response.headers["Access-Control-Allow-Origin"] = "*"
response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE, OPTIONS"
response.headers["Access-Control-Allow-Headers"] = "*" # Allow all headers
# Cross-origin isolation headers
response.headers["Cross-Origin-Embedder-Policy"] = "require-corp"
response.headers["Cross-Origin-Opener-Policy"] = "same-origin"
response.headers["Cross-Origin-Resource-Policy"] = "cross-origin"
return response
@app.route("/")
def serve_index():
# Handle logs=container query parameter
if request.args.get("logs") == "container":
files = (
os.listdir(app.static_folder) if os.path.exists(app.static_folder) else []
)
return jsonify(
{
"static_folder": app.static_folder,
"exists": os.path.exists(app.static_folder),
"files": files,
"pwd": os.getcwd(),
"user": os.getenv("USER"),
}
)
try:
response = send_from_directory(app.static_folder, "index.html")
response.headers["Cross-Origin-Opener-Policy"] = "same-origin"
response.headers["Cross-Origin-Embedder-Policy"] = "require-corp"
return response
except FileNotFoundError:
abort(
404,
description=f"Static folder or index.html not found. Static folder: {app.static_folder}",
)
@app.route("/api/data", methods=["GET"])
def get_data():
return jsonify({"message": "Voici vos données", "status": "success"})
@app.route("/api/process", methods=["POST"])
def process_data():
print("Processing data")
try:
# Check content type
content_type = request.headers.get("Content-Type", "")
# Handle different content types
if "application/json" in content_type:
data = request.get_json()
audio_base64 = data.get("audio_chunk")
elif "multipart/form-data" in content_type:
audio_base64 = request.form.get("audio_chunk")
else:
# Try to get raw data
audio_base64 = request.get_data().decode("utf-8")
# Validate the incoming data
if not audio_base64:
return (
jsonify({"error": "Missing audio_chunk in request", "status": "error"}),
400,
)
# Decode the base64 audio chunk
try:
audio_chunk = base64.b64decode(audio_base64)
except Exception as e:
return (
jsonify(
{
"error": f"Failed to decode audio chunk: {str(e)}",
"status": "error",
}
),
400,
)
# Put the audio chunk in the queue for processing
audio_queue.put(io.BytesIO(audio_chunk))
return jsonify(
{
"message": "Audio chunk received and queued for processing",
"status": "success",
}
)
except Exception as e:
return (
jsonify(
{"error": f"Failed to process request: {str(e)}", "status": "error"}
),
500,
)
@app.route("/api/actions", methods=["GET"])
def get_actions() -> Tuple[Dict[str, Any], int]:
"""Retrieve and clear all pending actions from the queue"""
actions: List[Dict[str, Any]] = []
# Drain the queue into our actions list
while not action_queue.empty():
try:
actions.append(action_queue.get_nowait())
except Exception:
break
return jsonify({"actions": json.dumps(actions), "status": "success"}), 200
@app.route("/<path:path>")
def serve_static(path: str):
try:
return send_from_directory(app.static_folder, path)
except FileNotFoundError:
abort(404, description=f"File {path} not found in static folder")
class StandaloneApplication(gunicorn.app.base.BaseApplication):
def __init__(self, app: Flask, options: Optional[Dict[str, Any]] = None):
self.options = options or {}
self.application = app
super().__init__()
def load_config(self):
for key, value in self.options.items():
self.cfg.set(key.lower(), value)
def load(self):
return self.application
if __name__ == "__main__":
print(f"Static folder path: {app.static_folder}")
print(f"Static folder exists: {os.path.exists(app.static_folder)}")
if os.path.exists(app.static_folder):
print(f"Static folder contents: {os.listdir(app.static_folder)}")
os.makedirs(app.static_folder, exist_ok=True)
# Start the audio transcriber thread
transcriber = AudioTranscriber(audio_queue, text_queue)
transcriber.start()
# Start the action processor thread
action_processor = ActionProcessor(text_queue, action_queue)
action_processor.start()
options: Any = {
"bind": "0.0.0.0:7860",
"workers": 3,
"worker_class": "sync",
"timeout": 120,
"forwarded_allow_ips": "*",
}
StandaloneApplication(app, options).run()