updated skeleton with true data
This commit is contained in:
@ -1 +1,11 @@
|
||||
FROM python:3.11-slim AS builder
|
||||
WORKDIR /app
|
||||
COPY requirements.gateway.txt .
|
||||
RUN pip install -r requirements.gateway.txt
|
||||
COPY . .
|
||||
|
||||
FROM python:3.11-slim
|
||||
WORKDIR /app
|
||||
COPY --from=builder /usr/local /usr/local
|
||||
COPY . .
|
||||
CMD ["python","main.py"]
|
||||
|
||||
7
gateway/api/health.py
Normal file
7
gateway/api/health.py
Normal file
@ -0,0 +1,7 @@
|
||||
from fastapi import APIRouter
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@router.get("/")
|
||||
async def health():
|
||||
return {"status": "ok"}
|
||||
19
gateway/api/openai_speech.py
Normal file
19
gateway/api/openai_speech.py
Normal file
@ -0,0 +1,19 @@
|
||||
from fastapi import APIRouter, Response
|
||||
from pydantic import BaseModel
|
||||
from core.queue_client import push_job, await_result
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
class SpeechRequest(BaseModel):
|
||||
model: str
|
||||
input: str
|
||||
voice: str = "auto"
|
||||
format: str = "wav"
|
||||
voice_sample_url: str | None = None
|
||||
voice_sample_base64: str | None = None
|
||||
|
||||
@router.post("/speech")
|
||||
async def speech(req: SpeechRequest):
|
||||
job_id = push_job(req.dict())
|
||||
audio_bytes, mime = await_result(job_id)
|
||||
return Response(content=audio_bytes, media_type=mime)
|
||||
21
gateway/api/voices.py
Normal file
21
gateway/api/voices.py
Normal file
@ -0,0 +1,21 @@
|
||||
from fastapi import APIRouter
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
router = APIRouter()
|
||||
REG = Path("voices/registry.json")
|
||||
|
||||
@router.post("/register")
|
||||
async def register(data: dict):
|
||||
reg = {}
|
||||
if REG.exists():
|
||||
reg = json.loads(REG.read_text())
|
||||
reg[data["name"]] = data
|
||||
REG.write_text(json.dumps(reg, indent=2))
|
||||
return {"status": "ok", "voices": list(reg.keys())}
|
||||
|
||||
@router.get("/list")
|
||||
async def list_voices():
|
||||
if not REG.exists():
|
||||
return []
|
||||
return json.loads(REG.read_text())
|
||||
1
gateway/core/cache.py
Normal file
1
gateway/core/cache.py
Normal file
@ -0,0 +1 @@
|
||||
# optional cache placeholder
|
||||
1
gateway/core/config.py
Normal file
1
gateway/core/config.py
Normal file
@ -0,0 +1 @@
|
||||
REDIS_HOST='redis'
|
||||
1
gateway/core/logging_config.py
Normal file
1
gateway/core/logging_config.py
Normal file
@ -0,0 +1 @@
|
||||
# logging config placeholder
|
||||
1
gateway/core/models.py
Normal file
1
gateway/core/models.py
Normal file
@ -0,0 +1 @@
|
||||
# pydantic models placeholder
|
||||
25
gateway/core/queue_client.py
Normal file
25
gateway/core/queue_client.py
Normal file
@ -0,0 +1,25 @@
|
||||
import redis, uuid, json, time, os
|
||||
|
||||
REDIS_HOST = os.environ.get("REDIS_HOST", "redis")
|
||||
r = redis.Redis(host=REDIS_HOST, port=6379, db=0)
|
||||
|
||||
QUEUE="tts_queue"
|
||||
RESULT="tts_result"
|
||||
|
||||
def push_job(data: dict) -> str:
|
||||
job_id = str(uuid.uuid4())
|
||||
data["job_id"] = job_id
|
||||
r.lpush(QUEUE, json.dumps(data))
|
||||
return job_id
|
||||
|
||||
def await_result(job_id: str, timeout=30):
|
||||
key = f"{RESULT}:{job_id}"
|
||||
start=time.time()
|
||||
while time.time()-start < timeout:
|
||||
data=r.get(key)
|
||||
if data:
|
||||
r.delete(key)
|
||||
obj=json.loads(data)
|
||||
return bytes.fromhex(obj["audio"]), obj["mime"]
|
||||
time.sleep(0.1)
|
||||
raise TimeoutError("Worker antwortet nicht")
|
||||
@ -1 +1,42 @@
|
||||
print('gateway start')
|
||||
import socket, uvicorn, os
|
||||
from fastapi import FastAPI
|
||||
from api.openai_speech import router as speech_router
|
||||
from api.voices import router as voice_router
|
||||
from api.health import router as health_router
|
||||
from pathlib import Path
|
||||
|
||||
app = FastAPI(title="XTTS2 Gateway")
|
||||
|
||||
app.include_router(speech_router, prefix="/v1/audio")
|
||||
app.include_router(voice_router, prefix="/v1/voices")
|
||||
app.include_router(health_router, prefix="/health")
|
||||
|
||||
PORT_FILE = Path("port.txt")
|
||||
|
||||
def find_free_port(start=8000, end=8100):
|
||||
for port in range(start, end+1):
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
||||
try:
|
||||
s.bind(("0.0.0.0", port))
|
||||
return port
|
||||
except:
|
||||
pass
|
||||
raise RuntimeError("No free port")
|
||||
|
||||
def start():
|
||||
env_port = os.environ.get("GATEWAY_PORT")
|
||||
port = int(env_port) if env_port else 8000
|
||||
|
||||
# check
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
||||
try:
|
||||
s.bind(("0.0.0.0", port))
|
||||
except:
|
||||
port = find_free_port()
|
||||
|
||||
PORT_FILE.write_text(str(port))
|
||||
|
||||
uvicorn.run(app, host="0.0.0.0", port=port)
|
||||
|
||||
if __name__ == "__main__":
|
||||
start()
|
||||
|
||||
@ -1 +1,5 @@
|
||||
fastapi
|
||||
uvicorn
|
||||
redis
|
||||
pydantic
|
||||
requests
|
||||
|
||||
1
gateway/voices/registry.json
Normal file
1
gateway/voices/registry.json
Normal file
@ -0,0 +1 @@
|
||||
{}
|
||||
Reference in New Issue
Block a user