import json from typing import Any import requests import streamlit as st st.set_page_config(page_title="Visione Lab", layout="wide") def api_url(path: str) -> str: return st.session_state.base_url.rstrip("/") + path def headers() -> dict[str, str]: token = st.session_state.get("token", "") return {"Authorization": f"Bearer {token}"} if token else {} def show_response(response: requests.Response) -> None: st.caption(f"{response.request.method} {response.url} -> {response.status_code}") try: st.json(response.json()) except ValueError: st.text(response.text) def json_input(label: str, value: dict[str, Any]) -> dict[str, Any] | None: raw = st.text_area(label, json.dumps(value, indent=2), height=180) try: return json.loads(raw) except json.JSONDecodeError as error: st.error(f"Invalid JSON: {error}") return None if "base_url" not in st.session_state: st.session_state.base_url = "http://127.0.0.1:5555/api/v1" st.title("Visione API Lab") auth_tab, reports_tab, admin_tab, docs_tab = st.tabs( ["Auth", "Reports", "Admin", "Docs"] ) with auth_tab: col1, col2 = st.columns(2) with col1: st.subheader("Password login") email = st.text_input("Email", "admin@visione.local") password = st.text_input("Password", "ChangeMe123!", type="password") if st.button("Login"): response = requests.post( api_url("/auth/login/password"), json={"email": email, "password": password}, timeout=10, ) data = response.json() if response.headers.get("content-type", "").startswith("application/json") else {} token = data.get("token") if token: st.session_state.token = token show_response(response) st.subheader("OTP") otp_email = st.text_input("OTP email", "citizen@example.com") if st.button("Request OTP"): show_response( requests.post( api_url("/auth/otp/request"), json={"email": otp_email}, timeout=10, ) ) otp_code = st.text_input("OTP code") if st.button("Verify OTP"): response = requests.post( api_url("/auth/otp/verify"), json={"email": otp_email, "code": otp_code}, timeout=10, ) data = response.json() if response.headers.get("content-type", "").startswith("application/json") else {} token = data.get("token") if token: st.session_state.token = token show_response(response) with col2: st.subheader("Register citizen") payload = json_input( "Register payload", { "first_name": "Mario", "last_name": "Rossi", "email": "citizen@example.com", "password": "ChangeMe123!", "fiscal_code": "RSSMRA80A01H501U", "phone": "+391234567890", }, ) if st.button("Register") and payload: show_response(requests.post(api_url("/auth/register"), json=payload, timeout=10)) st.subheader("Me") if st.button("GET /me"): show_response(requests.get(api_url("/me"), headers=headers(), timeout=10)) with reports_tab: col1, col2 = st.columns(2) with col1: st.subheader("Create report") report_payload = json_input( "Report payload", { "category_id": 1, "latitude": 41.9028, "longitude": 12.4964, "address": "Via Roma 1", "description": "Lampione non funzionante", }, ) if st.button("Create report") and report_payload: show_response( requests.post( api_url("/reports"), json=report_payload, headers=headers(), timeout=10, ) ) st.subheader("List reports") status = st.text_input("Status filter") params = {"status": status} if status else {} if st.button("GET /reports"): show_response( requests.get( api_url("/reports"), params=params, headers=headers(), timeout=10, ) ) with col2: report_id = st.number_input("Report id", min_value=1, step=1) if st.button("Detail"): show_response( requests.get( api_url(f"/reports/{report_id}"), headers=headers(), timeout=10, ) ) st.subheader("Upload media") files = st.file_uploader( "Images or videos", accept_multiple_files=True, type=["jpg", "jpeg", "png", "webp", "mp4", "webm", "mov"], ) if st.button("Upload") and files: multipart = [ ("file", (file.name, file.getvalue(), file.type or "application/octet-stream")) for file in files ] show_response( requests.post( api_url(f"/reports/{report_id}/media"), headers=headers(), files=multipart, timeout=60, ) ) st.subheader("Workflow") new_status = st.selectbox( "Status", ["UNDER_REVIEW", "ASSIGNED", "IN_PROGRESS", "RESOLVED", "REJECTED", "CLOSED"], ) if st.button("Update status"): show_response( requests.patch( api_url(f"/reports/{report_id}/status"), json={"status": new_status, "note": "Updated from Visione Lab"}, headers=headers(), timeout=10, ) ) with admin_tab: st.subheader("Reference data") endpoint = st.selectbox("Endpoint", ["/admin/categories", "/admin/areas", "/admin/teams", "/admin/stats/overview", "/admin/users"]) if st.button("GET admin endpoint"): show_response(requests.get(api_url(endpoint), headers=headers(), timeout=10)) with docs_tab: st.link_button("Swagger UI", api_url("/docs")) if st.button("Fetch OpenAPI"): show_response(requests.get(api_url("/openapi.json"), timeout=10)) with st.sidebar: st.text_input("Backend API", key="base_url") st.text_input("Bearer token", key="token", type="password") st.link_button("MailHog", "http://127.0.0.1:8025") if st.button("Health check"): show_response(requests.get(api_url("/health"), timeout=5))