restructure the project for packaging
This commit is contained in:
248
src/auracaster_webui/app.py
Normal file
248
src/auracaster_webui/app.py
Normal 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()
|
||||
Reference in New Issue
Block a user