restructure the project for packaging

This commit is contained in:
2025-03-11 11:32:26 +01:00
parent f3bdb6d53f
commit 1485277d66
16 changed files with 489 additions and 294 deletions

248
src/auracaster_webui/app.py Normal file
View File

@@ -0,0 +1,248 @@
"""
Airport Announcement System Streamlit frontend application.
"""
import streamlit as st
# Page setup must be first
st.set_page_config(page_title="Airport Announcement System", page_icon="✈️")
import time
import requests
from api_client.client import (
get_groups, get_available_languages, get_announcement_status,
start_announcement, update_group, get_available_endpoints
)
# Initialize session state for configuration
if "endpoint_groups" not in st.session_state:
try:
st.session_state.endpoint_groups = get_groups()
except requests.exceptions.RequestException as e:
st.error(f"Failed to load endpoint groups: {str(e)}")
st.session_state.endpoint_groups = []
# Initialize session state for available languages
if "available_languages" not in st.session_state:
try:
st.session_state.available_languages = get_available_languages()
except requests.exceptions.RequestException as e:
st.error(f"Failed to load available languages: {str(e)}")
st.session_state.available_languages = ["German", "English"] # Fallback languages
# Initialize session state for announcement text and status tracking
if "announcement_text" not in st.session_state:
st.session_state.announcement_text = "Hallo Welt."
if "show_success_message" not in st.session_state:
st.session_state.show_success_message = False
if "announcement_id" not in st.session_state:
st.session_state.announcement_id = 0
if "status_container_key" not in st.session_state:
st.session_state.status_container_key = 0
def show_announcement_status():
try:
status_data = get_announcement_status()
if status_data["state"] != "Ready":
# Create a container with a unique key for each announcement
# This ensures we get a fresh container for each new announcement
with st.container(key=f"status_container_{st.session_state.status_container_key}"):
# Create the status without a key parameter
status = st.status("**Airport PA System Status**", expanded=True)
with status:
# Progress elements
progress_bar = st.progress(status_data["progress"])
time_col, stage_col = st.columns([1, 3])
# Track last displayed state
last_state = None
# Update loop
while status_data["state"] not in ["Complete", "Error"]:
# Update time elapsed continuously
# Only update stage display if state changed
if status_data["state"] != last_state:
stage_col.write(f"**Stage:** {status_data['state']}")
last_state = status_data["state"]
time_col.write(f"⏱️ Time elapsed: {time.time() - status_data['details']['start_time']:.1f}s")
# Update progress bar
progress_bar.progress(status_data["progress"])
time.sleep(0.3)
# Refresh status data
status_data = get_announcement_status()
# Make sure to update the progress bar one final time with the final state's progress value
progress_bar.progress(status_data["progress"])
# Final state
if status_data["state"] == "Error":
st.error(f"❌ Error: {status_data['error']}")
else:
st.success("✅ Announcement completed successfully")
st.write(f"📢 Announcement made to group {status_data['details']['group']['name']}:")
st.write(f"📡 Endpoints: {', '.join(status_data['details']['group']['endpoints'])}")
st.write(f"🗣️ '{status_data['details']['text']}'")
st.write(f"🌐 Languages: {', '.join(status_data['details']['languages'])}")
# Clear the success message when announcement completes
st.session_state.show_success_message = False
except requests.exceptions.RequestException as e:
st.error(f"Failed to get announcement status: {str(e)}")
# Main interface
st.title("Airport Announcement System ✈️")
# Announcements section
with st.container():
st.header("Announcements")
# Predefined announcements
st.write("**Predefined Announcements** (click to autofill)")
col1, col2, col3 = st.columns(3)
with col1:
if st.button("Final Boarding Call"):
st.session_state.announcement_text = "This is the final boarding call for flight LX-380 to New York"
with col2:
if st.button("Security Reminder"):
st.session_state.announcement_text = "Please keep your luggage with you at all times"
with col3:
if st.button("Delay Notice"):
st.session_state.announcement_text = "We regret to inform you of a 30-minute delay"
# Custom announcement
with st.form("custom_announcement"):
# Get all groups with their names and IDs
group_options = [(g["name"], g["id"]) for g in st.session_state.endpoint_groups]
selected_group_name = st.selectbox(
"Select announcement area",
options=[g[0] for g in group_options]
)
message = st.text_area("Enter announcement text", st.session_state.announcement_text)
if st.form_submit_button("Make Announcement"):
try:
selected_group_id = next(g[1] for g in group_options if g[0] == selected_group_name)
start_announcement(message, selected_group_id)
# Set flag to show success message
st.session_state.show_success_message = True
# Increment announcement ID to ensure a fresh status container
st.session_state.announcement_id += 1
st.session_state.status_container_key = st.session_state.announcement_id
# Clear the announcement text after successful submission
st.session_state.announcement_text = ""
except requests.exceptions.RequestException as e:
st.error(f"Failed to start announcement: {str(e)}")
# Configuration section in sidebar
with st.sidebar:
st.header("Configuration")
with st.expander("Endpoint Groups"):
for i, group in enumerate(st.session_state.endpoint_groups):
cols = st.columns([4, 1])
with cols[0]:
# Use a unique key for the text input
input_key = f"group_name_{i}"
# Initialize the previous value in session state if not present
if f"prev_{input_key}" not in st.session_state:
st.session_state[f"prev_{input_key}"] = group["name"]
new_name = st.text_input(
f"Group Name",
value=group["name"],
key=input_key,
on_change=lambda: None # Prevent automatic callbacks
)
# Only update if the name has changed and it's different from the previous value
if new_name != group["name"] and new_name != st.session_state[f"prev_{input_key}"]:
try:
updated_group = group.copy()
updated_group["name"] = new_name
update_group(group["id"], updated_group)
# Update the session state with the latest groups
st.session_state.endpoint_groups = get_groups()
# Update the previous value before rerunning
st.session_state[f"prev_{input_key}"] = new_name
st.rerun()
except requests.exceptions.RequestException as e:
st.error(f"Failed to update group name: {str(e)}")
try:
available_endpoints = get_available_endpoints()
# Use a unique key for the endpoints multiselect
endpoints_key = f"endpoints_select_{i}"
# Initialize the previous value in session state if not present
if f"prev_{endpoints_key}" not in st.session_state:
st.session_state[f"prev_{endpoints_key}"] = group["endpoints"]
selected_endpoints = st.multiselect(
f"Endpoints",
options=available_endpoints,
default=group["endpoints"],
key=endpoints_key
)
# Only update if endpoints have changed and they're different from previous value
if selected_endpoints != group["endpoints"] and selected_endpoints != st.session_state[f"prev_{endpoints_key}"]:
updated_group = group.copy()
updated_group["endpoints"] = selected_endpoints
update_group(group["id"], updated_group)
# Update the previous value before rerunning
st.session_state[f"prev_{endpoints_key}"] = selected_endpoints
st.session_state.endpoint_groups = get_groups()
st.rerun()
except requests.exceptions.RequestException as e:
st.error(f"Failed to get available endpoints: {str(e)}")
with cols[1]:
if st.button("Delete", key=f"delete_group_{i}"):
try:
# This is assumed to exist in the API client module
from api_client.client import delete_group
delete_group(group["id"])
# Update the session state with the latest groups
st.session_state.endpoint_groups = get_groups()
st.rerun()
except requests.exceptions.RequestException as e:
st.error(f"Failed to delete group: {str(e)}")
# Add new group
st.subheader("Add New Group")
with st.form("add_group_form"):
new_group_name = st.text_input("New Group Name")
try:
available_endpoints = get_available_endpoints()
new_group_endpoints = st.multiselect("Endpoints", options=available_endpoints)
except requests.exceptions.RequestException as e:
st.error(f"Failed to get available endpoints: {str(e)}")
new_group_endpoints = []
if st.form_submit_button("Add Group"):
if new_group_name:
try:
from api_client.client import create_group
new_group = {"name": new_group_name, "endpoints": new_group_endpoints}
create_group(new_group)
# Update the session state with the latest groups
st.session_state.endpoint_groups = get_groups()
st.rerun()
except requests.exceptions.RequestException as e:
st.error(f"Failed to create group: {str(e)}")
else:
st.error("Group name cannot be empty")
# Show the announcement status
show_announcement_status()