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