small layout changes, refractoring

This commit is contained in:
2025-03-11 10:54:04 +01:00
parent 8fab59a493
commit f3bdb6d53f
6 changed files with 269 additions and 137 deletions

View File

@@ -1,5 +1,6 @@
from fastapi import FastAPI, HTTPException
from mock_backend.mock_backend import announcement_system, EndpointGroup
from mock_backend.mock_backend import announcement_system
from api_models import EndpointGroup
from typing import List
import uvicorn
@@ -45,22 +46,15 @@ def start_announcement(text: str, group_id: int):
@app.get("/announcements/status")
def get_announcement_status():
process = announcement_system.current_process
return {
"state": process.current_state.value,
"progress": process.progress,
"error": process.error,
"details": {
"text": process.details.text,
"languages": process.details.languages,
"group": process.details.group,
"start_time": process.details.start_time
}
}
return announcement_system.get_announcement_status()
@app.get("/endpoints")
def get_available_endpoints():
return announcement_system.available_endpoints
return announcement_system.get_available_endpoints()
@app.get("/languages")
def get_available_languages():
return announcement_system.get_available_languages()
if __name__ == "__main__":
uvicorn.run('mock_backend.mock_api:app', host="0.0.0.0", port=7999, reload=True)

View File

@@ -1,42 +1,16 @@
import time
import threading
from enum import Enum
from pydantic import BaseModel, Field
from typing import Optional, List
ENDPOINTS = [f"endpoint{i}" for i in range(1, 4)] # Predefined endpoints
from api_models import EndpointGroup, AnnouncementStates
class AnnouncementStates(Enum):
IDLE: str = "Ready"
TRANSLATING: str = "Translating"
GENERATING_VOICE: str = "Generating voice synthesis"
ROUTING: str = "Routing to endpoints"
ACTIVE: str = "Broadcasting announcement"
COMPLETE: str = "Complete"
ERROR: str = "Error"
class EndpointGroup(BaseModel):
id: int
name: str
endpoints: List[str]
languages: List[str]
class AnnouncementDetails(BaseModel):
text: str
languages: List[str]
group: EndpointGroup
start_time: float
class AnnouncementProgress(BaseModel):
current_state: str = AnnouncementStates.IDLE
error: Optional[str] = None
details: AnnouncementDetails
progress: float = Field(default=0.0, ge=0.0, le=1.0)
description: str = Field(default="Ready")
AVAILABLE_ENDPOINTS = [f"endpoint{i}" for i in range(1, 4)] # Predefined endpoints
AVAILABLE_LANGUAGES = ["German", "English", "French", "Spanish", "Italian"]
class AnnouncementSystem:
def __init__(self):
self.available_endpoints = ENDPOINTS
self.available_endpoints = AVAILABLE_ENDPOINTS
self.available_languages = AVAILABLE_LANGUAGES
self.endpoint_groups = [
EndpointGroup(
id=1,
@@ -51,56 +25,69 @@ class AnnouncementSystem:
languages=["German", "English"]
)
]
self.current_process = AnnouncementProgress(
details=AnnouncementDetails(
text="",
languages=[],
group=EndpointGroup(
id=0,
name="",
endpoints=[],
languages=[]
),
start_time=0.0
)
)
self.active_group_id = None
self._thread = None
self.last_completed_group_id = None
def start_announcement(self, text, group):
if self.current_process.current_state not in [AnnouncementStates.IDLE, AnnouncementStates.COMPLETE]:
raise Exception("Announcement already in progress")
def start_announcement(self, text: str, group: EndpointGroup):
# Find the group in our list to ensure we're working with the actual instance
target_group = self.get_endpoint_group(group.id)
if not target_group:
raise ValueError(f"Group with ID {group.id} not found")
self.current_process.details.text = text
self.current_process.details.group = group
# Set the languages from the group
self.current_process.details.languages = group.languages
self._thread = threading.Thread(target=self._run_process)
# Check if this group has an announcement in progress
if target_group.progress.current_state not in [AnnouncementStates.IDLE.value, AnnouncementStates.COMPLETE.value]:
raise Exception("Announcement already in progress for this group")
# Check if any other announcement is in progress
for g in self.endpoint_groups:
if g.progress.current_state not in [AnnouncementStates.IDLE.value, AnnouncementStates.COMPLETE.value]:
raise Exception("Another announcement is already in progress")
# If this group was the last completed group, clear that reference
if self.last_completed_group_id == target_group.id:
self.last_completed_group_id = None
# Reset the group to IDLE state if it was in COMPLETE state
if target_group.progress.current_state == AnnouncementStates.COMPLETE.value:
target_group.progress.current_state = AnnouncementStates.IDLE.value
target_group.progress.progress = 0.0
# Set up the announcement parameters
target_group.parameters.text = text
target_group.parameters.languages = target_group.languages.copy()
target_group.parameters.start_time = time.time()
self.active_group_id = target_group.id
# Start the announcement process in a separate thread
self._thread = threading.Thread(target=self._run_process, args=(target_group,))
self._thread.start()
def _run_process(self):
self.current_process.details.start_time = time.time()
def _run_process(self, group: EndpointGroup):
try:
self._update_state(AnnouncementStates.TRANSLATING)
self._update_state(group, AnnouncementStates.TRANSLATING)
time.sleep(1) # Simulate translation
self._update_state(AnnouncementStates.GENERATING_VOICE)
self._update_state(group, AnnouncementStates.GENERATING_VOICE)
time.sleep(1) # Voice synthesis
self._update_state(AnnouncementStates.ROUTING)
time.sleep(len(self.current_process.details.group.endpoints) * 0.5)
self._update_state(group, AnnouncementStates.ROUTING)
time.sleep(len(group.endpoints) * 0.5)
self._update_state(AnnouncementStates.ACTIVE)
self._update_state(group, AnnouncementStates.ACTIVE)
time.sleep(1) # Simulate broadcast
self._update_state(AnnouncementStates.COMPLETE)
self._update_state(group, AnnouncementStates.COMPLETE)
self.last_completed_group_id = group.id
self.active_group_id = None
except Exception as e:
self.current_process.error = str(e)
self._update_state(AnnouncementStates.ERROR)
group.progress.error = str(e)
self._update_state(group, AnnouncementStates.ERROR)
self.active_group_id = None
def _update_state(self, new_state):
self.current_process.current_state = new_state
def _update_state(self, group: EndpointGroup, new_state: AnnouncementStates):
group.progress.current_state = new_state.value
# Progress based on state transitions
state_progress = {
@@ -111,7 +98,7 @@ class AnnouncementSystem:
AnnouncementStates.COMPLETE: 1.0,
AnnouncementStates.ERROR: 0
}
self.current_process.progress = state_progress[new_state]
group.progress.progress = state_progress[new_state]
def get_endpoint_groups(self) -> List[EndpointGroup]:
return self.endpoint_groups
@@ -133,6 +120,7 @@ class AnnouncementSystem:
if not group:
raise ValueError(f"Group with ID {group_id} not found")
# Update only the editable fields, not the state fields
group.name = updated_group.name
group.endpoints = updated_group.endpoints
group.languages = updated_group.languages
@@ -142,7 +130,78 @@ class AnnouncementSystem:
group = self.get_endpoint_group(group_id)
if not group:
raise ValueError(f"Group with ID {group_id} not found")
# Cannot delete a group with an active announcement
if group.progress.current_state not in [AnnouncementStates.IDLE.value, AnnouncementStates.COMPLETE.value]:
raise ValueError(f"Cannot delete group with an active announcement")
self.endpoint_groups = [g for g in self.endpoint_groups if g.id != group_id]
def get_available_languages(self) -> List[str]:
"""Get the list of available languages for announcements."""
return self.available_languages
def get_available_endpoints(self) -> List[str]:
"""Get the list of available endpoints for announcements."""
return self.available_endpoints
def get_announcement_status(self) -> dict:
"""Get the status of the current announcement."""
if self.active_group_id is not None:
active_group = self.get_endpoint_group(self.active_group_id)
return {
"state": active_group.progress.current_state,
"progress": active_group.progress.progress,
"error": active_group.progress.error,
"details": {
"text": active_group.parameters.text,
"languages": active_group.parameters.languages or active_group.languages,
"group": {
"id": active_group.id,
"name": active_group.name,
"endpoints": active_group.endpoints,
"languages": active_group.languages
},
"start_time": active_group.parameters.start_time
}
}
elif self.last_completed_group_id is not None:
# Return the last completed announcement
completed_group = self.get_endpoint_group(self.last_completed_group_id)
return {
"state": completed_group.progress.current_state,
"progress": completed_group.progress.progress,
"error": completed_group.progress.error,
"details": {
"text": completed_group.parameters.text,
"languages": completed_group.parameters.languages or completed_group.languages,
"group": {
"id": completed_group.id,
"name": completed_group.name,
"endpoints": completed_group.endpoints,
"languages": completed_group.languages
},
"start_time": completed_group.parameters.start_time
}
}
else:
# No active or completed announcements
return {
"state": AnnouncementStates.IDLE.value,
"progress": 0.0,
"error": None,
"details": {
"text": "",
"languages": [],
"group": {
"id": 0,
"name": "",
"endpoints": [],
"languages": []
},
"start_time": 0.0
}
}
# Singleton instance
announcement_system = AnnouncementSystem()