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.")