demo / app.py
VeuReu's picture
Upload 55 files
7449830
raw
history blame
6.2 kB
import os
import yaml
import shutil
from pathlib import Path
import uuid
try:
import tomllib
except ModuleNotFoundError: # Py<3.11
import tomli as tomllib
import streamlit as st
from databases import set_db_path, init_schema, set_blockchain_enabled
from api_client import APIClient
from utils import ensure_dirs
from auth import initialize_auth_system, render_login_form, render_sidebar, require_login
from mobile_verification import render_mobile_verification_screen, get_user_permissions
from compliance_client import compliance_client
from page_modules.process_video import render_process_video_page
from page_modules.analyze_transcriptions import render_analyze_transcriptions_page
from page_modules.statistics import render_statistics_page
from page_modules.validation import render_validation_page
# -- Move DB / vídeos en entorns de desplegament --
os.environ["STREAMLIT_DATA_DIRECTORY"] = "/tmp/.streamlit"
Path("/tmp/.streamlit").mkdir(parents=True, exist_ok=True)
# Vídeos estàtics: prioritzar demo/data/media, caure a demo/videos si cal.
# Es copien a /tmp/data/videos només per a entorns de desplegament; la BD
# principal d'usuaris es fa servir directament des de DATA_DIR/users.db.
runtime_videos = Path("/tmp/data/videos")
if not runtime_videos.exists():
Path("/tmp/data").mkdir(parents=True, exist_ok=True)
base_dir = Path(__file__).parent
candidates = [
base_dir / "data" / "media", # nova ubicació
base_dir / "videos", # compatibilitat enrere
]
static_videos = None
for cand in candidates:
if cand.exists():
static_videos = cand
break
if static_videos is not None:
shutil.copytree(static_videos, runtime_videos, dirs_exist_ok=True)
# --- Config ---
def _load_yaml(path="config.yaml") -> dict:
with open(path, "r", encoding="utf-8") as f:
cfg = yaml.safe_load(f) or {}
# interpolación sencilla de ${VARS} si las usas en el YAML
def _subst(s: str) -> str:
return os.path.expandvars(s) if isinstance(s, str) else s
# aplica sustitución en los campos que te interesan
if "api" in cfg:
cfg["api"]["base_url"] = _subst(cfg["api"].get("base_url", ""))
cfg["api"]["token"] = _subst(cfg["api"].get("token", ""))
cfg["api"]["tts_url"] = _subst(cfg["api"].get("tts_url", ""))
if "storage" in cfg and "root_dir" in cfg["storage"]:
cfg["storage"]["root_dir"] = _subst(cfg["storage"]["root_dir"])
if "sqlite" in cfg and "path" in cfg["sqlite"]:
cfg["sqlite"]["path"] = _subst(cfg["sqlite"]["path"])
return cfg
CFG = _load_yaml("config.yaml")
# Ajuste de variables según tu esquema YAML
# Para la interfaz demo, usaremos siempre la carpeta "temp" local
DATA_DIR = "temp"
BACKEND_BASE_URL = CFG.get("api", {}).get("base_url", "http://localhost:8000")
TTS_URL = "https://veureu-tts.hf.space" # Forzar URL correcta
print(f"🔧 TTS_URL configurada: {TTS_URL}")
print(f"🔧 Tipo de TTS_URL: {type(TTS_URL)}")
print(f"🔧 Longitud de TTS_URL: {len(TTS_URL)}")
print(f"🔧 TTS_URL repr: {repr(TTS_URL)}")
USE_MOCK = bool(CFG.get("app", {}).get("use_mock", False)) # si no la tienes en el yaml, queda False
BLOCKCHAIN_ENABLED = bool(CFG.get("blockchain", {}).get("enabled", False))
API_TOKEN = CFG.get("api", {}).get("token") or os.getenv("API_SHARED_TOKEN")
os.makedirs(DATA_DIR, exist_ok=True)
ensure_dirs(DATA_DIR)
DB_PATH = os.path.join(DATA_DIR, "users.db")
set_db_path(DB_PATH)
# Configurar si els esdeveniments s'han de registrar a SQLite o a AWS QLDB
set_blockchain_enabled(BLOCKCHAIN_ENABLED)
init_schema()
# Initialize authentication system and sync default users
initialize_auth_system(DB_PATH)
api = APIClient(BACKEND_BASE_URL, use_mock=USE_MOCK, data_dir=DATA_DIR, token=API_TOKEN, tts_url=TTS_URL)
# Identificador de sessió per a traça d'esdeveniments
if "session_id" not in st.session_state:
st.session_state.session_id = str(uuid.uuid4())
st.set_page_config(page_title="Veureu — Audiodescripció", page_icon="🎬", layout="wide")
# Initialize session state for user
if "user" not in st.session_state:
st.session_state.user = None
# Render sidebar and get navigation
page, role = render_sidebar()
# Pre-login screen
if not st.session_state.user:
st.title("Veureu — Audiodescripció")
render_login_form()
st.stop()
# Post-login: Verificación por móvil si es necesaria
if st.session_state.user and 'sms_verified' not in st.session_state:
st.session_state.sms_verified = None
permissions = None
if st.session_state.user:
username = st.session_state.user['username']
role = st.session_state.user['role']
# Obtener permisos para ver si requiere SMS
permissions = get_user_permissions(role, st.session_state.get('sms_verified'))
# Si requiere SMS y aún no está verificado/omitido, mostrar pantalla de verificación
if permissions["requires_sms"] and st.session_state.sms_verified is None:
result = render_mobile_verification_screen(username, role)
if result is None:
# Aún en proceso de verificación
st.stop()
# Si result es True o False, ya se ha completado/omitido y continúa
# --- Pages ---
if page == "Processar vídeo nou":
require_login(render_login_form)
permissions = get_user_permissions(role, st.session_state.get('sms_verified'))
if not permissions["procesar_videos"]:
st.error("No tens permisos per processar nous vídeos. Verifica el teu mòbil per obtenir accés complet.")
st.stop()
render_process_video_page(api, BACKEND_BASE_URL)
elif page == "Analitzar video-transcripcions":
require_login(render_login_form)
permissions = get_user_permissions(role, st.session_state.get('sms_verified'))
render_analyze_transcriptions_page(api, permissions)
elif page == "Estadístiques":
require_login(render_login_form)
render_statistics_page()
elif page == "Validació":
require_login(render_login_form)
permissions = get_user_permissions(role, st.session_state.get('sms_verified'))
render_validation_page(compliance_client, runtime_videos, permissions, username)