File size: 8,144 Bytes
74b4a38 c79f28f c7c9904 74b4a38 c79f28f 74b4a38 4d2feb8 4e0481a e2c60fb 867cffa 377660c 490dc38 975ad97 89f66a0 e06a231 74b4a38 c79f28f 74b4a38 18ffd35 c79f28f 74b4a38 c79f28f 758eede 18ffd35 758eede 74b4a38 37590cc 74b4a38 c7c9904 7449830 2231a29 31db8a8 74b4a38 c7c9904 6a4b857 c7c9904 2231a29 74b4a38 f95eaf7 74b4a38 f95eaf7 3df3b6c 74b4a38 c79f28f c7c9904 e2c60fb c79f28f 74b4a38 4e0481a c79f28f f95eaf7 74b4a38 f95eaf7 4e0481a 74b4a38 4e0481a 74b4a38 4e0481a 74b4a38 4e0481a 74b4a38 4e0481a 74b4a38 867cffa 4d2feb8 867cffa 74b4a38 4e0481a 867cffa 74b4a38 f026f25 4e0481a 975ad97 4e0481a 377660c 975ad97 4e0481a 4d2feb8 377660c 4d2feb8 e06a231 86a3c44 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
import os
import yaml
import shutil
from pathlib import Path
import uuid
from datetime import datetime
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 persistent_data_gate import ensure_temp_databases, maybe_publish_monthly_actions_digest
from mobile_verification import render_mobile_verification_screen, get_user_permissions
from compliance_client import compliance_client
from page_modules.new_video_processing import render_process_video_page
from page_modules.analyze_audiodescriptions import render_analyze_audiodescriptions_page
from page_modules.statistics import render_statistics_page
from page_modules.validation import render_validation_page
from page_modules.machine_room import render_machine_room_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 sempre la carpeta "temp" local
DATA_DIR = "temp"
# Backend del engine: primero config.yaml, luego variable de entorno, luego fallback local
BACKEND_BASE_URL = (
CFG.get("api", {}).get("base_url")
or os.getenv("API_BASE_URL")
or "http://localhost:8000"
)
TTS_URL = "https://veureu-tts.hf.space"
USE_MOCK = bool(CFG.get("app", {}).get("use_mock", False)) # si no la tienes en el yaml, queda False
COMPLIANCE_CFG = CFG.get("compliance", {}) or {}
PRIVATE_BLOCKCHAIN_ENABLE = bool(
COMPLIANCE_CFG.get("private_blockchain_enabled",
COMPLIANCE_CFG.get("private_blockchain_enable", False))
)
PUBLIC_BLOCKCHAIN_ENABLE = bool(
COMPLIANCE_CFG.get("public_blockchain_enabled",
COMPLIANCE_CFG.get("public_blockchain_enable", False))
)
MONTHLY_DIGEST_ENABLED = bool(COMPLIANCE_CFG.get("monthly_digest_enabled", False))
# Token compartido: primero config.yaml (api.token), luego variable de entorno API_SHARED_TOKEN
API_TOKEN = CFG.get("api", {}).get("token") or os.getenv("API_SHARED_TOKEN")
# Cliente del backend (engine)
api = APIClient(BACKEND_BASE_URL, use_mock=USE_MOCK, data_dir=DATA_DIR, token=API_TOKEN, tts_url=TTS_URL)
os.makedirs(DATA_DIR, exist_ok=True)
ensure_dirs(DATA_DIR)
base_dir = Path(__file__).parent
ensure_temp_databases(base_dir, api)
DB_PATH = os.path.join(DATA_DIR, "db", "users.db")
set_db_path(DB_PATH)
# Configurar si els esdeveniments s'han de registrar a SQLite o a AWS QLDB
set_blockchain_enabled(PRIVATE_BLOCKCHAIN_ENABLE)
# Si està habilitat el registre públic i el digest mensual, publicar si cal
# el digest mensual sobre actions.db (es calcula al voltant del mes anterior).
maybe_publish_monthly_actions_digest(
base_dir,
compliance_client,
public_blockchain_enabled=PUBLIC_BLOCKCHAIN_ENABLE,
monthly_digest_enabled=MONTHLY_DIGEST_ENABLED,
)
init_schema()
# Initialize authentication system and sync default users
initialize_auth_system(DB_PATH)
# 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())
# Exposar client d'API al session_state per a altres mòduls (p.ex. auth/persistent_data_gate)
st.session_state.api_client = api
st.set_page_config(page_title="Veureu — Audiodescripció", page_icon="🎬", layout="wide")
# Estil global: botons primaris en taronja (en lloc de blau per defecte)
st.markdown(
"""
<style>
.stButton > button[kind="primary"] {
background-color: #f97316;
border-color: #ea580c;
color: white;
}
.stButton > button[kind="primary"]:hover {
background-color: #ea580c;
border-color: #c2410c;
}
</style>
""",
unsafe_allow_html=True,
)
# 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 audiodescripcions":
require_login(render_login_form)
permissions = get_user_permissions(role, st.session_state.get('sms_verified'))
render_analyze_audiodescriptions_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)
elif page == "Sala de màquines":
require_login(render_login_form)
# Només l'usuari 'verd' pot accedir a aquesta pantalla
if st.session_state.user and st.session_state.user.get("username") == "verd":
render_machine_room_page()
else:
st.error("No tens permisos per accedir a aquesta pantalla.")
|