| """UI logic for the "Analitzar video-transcripcions" page.""" |
|
|
| from __future__ import annotations |
|
|
| from pathlib import Path |
| from typing import Dict |
|
|
| import streamlit as st |
|
|
| from utils import save_bytes |
|
|
|
|
| def render_analyze_transcriptions_page(api, permissions: Dict[str, bool]) -> None: |
| st.header("Analitzar video-transcripcions") |
| base_dir = Path("/tmp/data/videos") |
|
|
| if not base_dir.exists(): |
| st.info("No s'ha trobat la carpeta **videos**. Crea-la i afegeix-hi subcarpetes amb els teus vídeos.") |
| st.stop() |
|
|
| carpetes = [p.name for p in sorted(base_dir.iterdir()) if p.is_dir() and p.name != "completed"] |
| if not carpetes: |
| st.info("No s'ha trobat la carpeta **videos**. Crea-la i afegeix-hi subcarpetes amb els teus vídeos.") |
| st.stop() |
|
|
| if "current_video" not in st.session_state: |
| st.session_state.current_video = None |
|
|
| seleccio = st.selectbox("Selecciona un vídeo (carpeta):", carpetes, index=None, placeholder="Tria una carpeta…") |
|
|
| if seleccio != st.session_state.current_video: |
| st.session_state.current_video = seleccio |
| if "version_selector" in st.session_state: |
| del st.session_state["version_selector"] |
| st.session_state.add_ad_checkbox = False |
| st.rerun() |
|
|
| if not seleccio: |
| st.stop() |
|
|
| vid_dir = base_dir / seleccio |
| mp4s = sorted(vid_dir.glob("*.mp4")) |
|
|
| col_video, col_txt = st.columns([2, 1], gap="large") |
|
|
| with col_video: |
| subcarpetas_ad = [p.name for p in sorted(vid_dir.iterdir()) if p.is_dir()] |
| default_index_sub = subcarpetas_ad.index("Salamandra") if "Salamandra" in subcarpetas_ad else 0 |
| subcarpeta_seleccio = st.selectbox( |
| "Selecciona una versió d'audiodescripció:", |
| subcarpetas_ad, |
| index=default_index_sub if subcarpetas_ad else None, |
| placeholder="Tria una versió…" if subcarpetas_ad else "No hi ha versions", |
| key="version_selector", |
| ) |
|
|
| video_ad_path = vid_dir / subcarpeta_seleccio / "une_ad.mp4" if subcarpeta_seleccio else None |
| is_ad_video_available = video_ad_path is not None and video_ad_path.exists() |
|
|
| add_ad_video = st.checkbox( |
| "Afegir audiodescripció", |
| disabled=not is_ad_video_available, |
| key="add_ad_checkbox", |
| ) |
|
|
| video_to_show = None |
| if add_ad_video and is_ad_video_available: |
| video_to_show = video_ad_path |
| elif mp4s: |
| video_to_show = mp4s[0] |
|
|
| if video_to_show: |
| st.video(str(video_to_show)) |
| else: |
| st.warning("No s'ha trobat cap fitxer **.mp4** a la carpeta seleccionada.") |
|
|
| st.markdown("---") |
| st.markdown("#### Accions") |
| c1, c2 = st.columns(2) |
| with c1: |
| if st.button("Reconstruir àudio amb narració lliure", use_container_width=True, key="rebuild_free_ad"): |
| if subcarpeta_seleccio: |
| free_ad_path = vid_dir / subcarpeta_seleccio / "free_ad.txt" |
| if free_ad_path.exists(): |
| with st.spinner("Generant àudio de la narració lliure..."): |
| text_content = free_ad_path.read_text(encoding="utf-8") |
| voice = "central/grau" |
| response = api.tts_matxa(text=text_content, voice=voice) |
| if "mp3_bytes" in response: |
| output_path = vid_dir / subcarpeta_seleccio / "free_ad.mp3" |
| save_bytes(output_path, response["mp3_bytes"]) |
| st.success(f"Àudio generat i desat a: {output_path}") |
| else: |
| st.error(f"Error en la generació de l'àudio: {response.get('error', 'Desconegut')}") |
| else: |
| st.warning("No s'ha trobat el fitxer 'free_ad.txt' en aquesta versió.") |
|
|
| with c2: |
| if st.button("Reconstruir vídeo amb audiodescripció", use_container_width=True, key="rebuild_video_ad"): |
| if subcarpeta_seleccio and mp4s: |
| une_srt_path = vid_dir / subcarpeta_seleccio / "une_ad.srt" |
| video_original_path = mp4s[0] |
| if une_srt_path.exists(): |
| with st.spinner( |
| "Reconstruint el vídeo amb l'audiodescripció... Aquesta operació pot trigar una estona." |
| ): |
| response = api.rebuild_video_with_ad( |
| video_path=str(video_original_path), |
| srt_path=str(une_srt_path), |
| ) |
| if "video_bytes" in response: |
| output_path = vid_dir / subcarpeta_seleccio / "video_ad_rebuilt.mp4" |
| save_bytes(output_path, response["video_bytes"]) |
| st.success(f"Vídeo reconstruït i desat a: {output_path}") |
| st.info( |
| "Pots visualitzar-lo activant la casella 'Afegir audiodescripció' i seleccionant el nou fitxer si cal." |
| ) |
| else: |
| st.error(f"Error en la reconstrucció del vídeo: {response.get('error', 'Desconegut')}") |
| else: |
| st.warning("No s'ha trobat el fitxer 'une_ad.srt' en aquesta versió.") |
|
|
| with col_txt: |
| tipus_ad_options = ["narració lliure", "UNE-153010"] |
| tipus_ad_seleccio = st.selectbox("Fitxer d'audiodescripció a editar:", tipus_ad_options) |
|
|
| ad_filename = "free_ad.txt" if tipus_ad_seleccio == "narració lliure" else "une_ad.srt" |
|
|
| text_content = "" |
| ad_path = None |
| if subcarpeta_seleccio: |
| ad_path = vid_dir / subcarpeta_seleccio / ad_filename |
| if ad_path.exists(): |
| try: |
| text_content = ad_path.read_text(encoding="utf-8") |
| except Exception: |
| text_content = ad_path.read_text(errors="ignore") |
| else: |
| st.info(f"No s'ha trobat el fitxer **{ad_filename}**.") |
| else: |
| st.warning("Selecciona una versió per veure els fitxers.") |
|
|
| new_text = st.text_area( |
| f"Contingut de {tipus_ad_seleccio}", |
| value=text_content, |
| height=500, |
| key=f"editor_{seleccio}_{subcarpeta_seleccio}_{ad_filename}", |
| ) |
|
|
| if st.button( |
| "▶️ Reproduir narració", |
| use_container_width=True, |
| disabled=not new_text.strip(), |
| key="play_button_editor", |
| ): |
| with st.spinner("Generant àudio..."): |
| pass |
|
|
| if st.button("Desar canvis", use_container_width=True, type="primary"): |
| if ad_path: |
| try: |
| ad_path.write_text(new_text, encoding="utf-8") |
| st.success(f"Fitxer **{ad_filename}** desat correctament.") |
| st.rerun() |
| except Exception as e: |
| st.error(f"No s'ha pogut desar el fitxer: {e}") |
| else: |
| st.error("No s'ha seleccionat una ruta de fitxer vàlida per desar.") |
|
|
| st.markdown("---") |
| st.subheader("Avaluació de la qualitat de l'audiodescripció") |
|
|
| can_rate = permissions.get("valorar", False) |
| controls_disabled = not can_rate |
|
|
| c1, c2, c3 = st.columns(3) |
| with c1: |
| transcripcio = st.slider("Transcripció", 1, 10, 7, disabled=controls_disabled) |
| identificacio = st.slider("Identificació de personatges", 1, 10, 7, disabled=controls_disabled) |
| with c2: |
| localitzacions = st.slider("Localitzacions", 1, 10, 7, disabled=controls_disabled) |
| activitats = st.slider("Activitats", 1, 10, 7, disabled=controls_disabled) |
| with c3: |
| narracions = st.slider("Narracions", 1, 10, 7, disabled=controls_disabled) |
| expressivitat = st.slider("Expressivitat", 1, 10, 7, disabled=controls_disabled) |
|
|
| comments = st.text_area( |
| "Comentaris (opcional)", |
| placeholder="Escriu els teus comentaris lliures…", |
| height=120, |
| disabled=controls_disabled, |
| ) |
|
|
| if not can_rate: |
| st.info("El teu rol no permet enviar valoracions.") |
| else: |
| if st.button("Enviar valoració", type="primary", use_container_width=True): |
| try: |
| from database import add_feedback_ad |
|
|
| add_feedback_ad( |
| video_name=seleccio, |
| user_id=st.session_state.user["id"], |
| transcripcio=transcripcio, |
| identificacio=identificacio, |
| localitzacions=localitzacions, |
| activitats=activitats, |
| narracions=narracions, |
| expressivitat=expressivitat, |
| comments=comments or None, |
| ) |
| st.success("Gràcies! La teva valoració s'ha desat correctament.") |
| except Exception as e: |
| st.error(f"S'ha produït un error en desar la valoració: {e}") |
|
|