Spaces:
Build error
Build error
| import streamlit as st | |
| import os | |
| from pycaps import Document | |
| from utils import (go_to_step, reset_all, setup_api_keys, cleanup_api_keys, | |
| handle_unexpected_exception, load_template_files, create_pipeline_builder) | |
| from file_manager import get_random_file_name | |
| from config import TEMPLATE_NAMES, TEMPLATES_INFO | |
| from template_editor import template_editor | |
| def render_step2(): | |
| st.header("Configure & Process") | |
| if 'editing_mode' not in st.session_state: st.session_state.editing_mode = False | |
| if 'edited_templates' not in st.session_state: st.session_state.edited_templates = {} | |
| col1, col2 = st.columns([1, 1]) | |
| with col1: | |
| render_configuration_column() | |
| with col2: | |
| render_preview_column() | |
| def render_configuration_column(): | |
| st.subheader("Configuration") | |
| if st.session_state.preview_generating: | |
| return | |
| if st.session_state.editing_mode: | |
| handle_editing_mode() | |
| else: | |
| handle_preset_selection_mode() | |
| def handle_preset_selection_mode(): | |
| display_names = [ | |
| f"{name} [EDITED]" if (name in st.session_state.edited_templates and st.session_state.edited_templates[name]["modified"]) else name | |
| for name in TEMPLATE_NAMES | |
| ] | |
| current_selection_name = st.session_state.get('selected_template', TEMPLATE_NAMES[0]) | |
| try: | |
| current_index = TEMPLATE_NAMES.index(current_selection_name) | |
| except ValueError: | |
| current_index = 0 | |
| selected_display_name = st.selectbox( | |
| "Choose a Style", display_names, index=current_index | |
| ) | |
| # Extraer el nombre real de la template | |
| template_name = selected_display_name.replace(" [EDITED]", "") | |
| st.session_state.selected_template = template_name | |
| selected_template_info = next((t for t in TEMPLATES_INFO if t["name"] == template_name), None) | |
| if selected_template_info and selected_template_info["ai_features"]: | |
| ai_features_str = ", ".join(selected_template_info["ai_features"]) | |
| if not st.session_state.get('api_key_input'): | |
| st.warning(f"⚠️ This template uses AI features ({ai_features_str}). " | |
| "Please provide an API key in the sidebar to enable them. " | |
| "Otherwise, they will be ignored during processing.") | |
| else: | |
| st.info(f"✨ This template uses AI features: {ai_features_str}.") | |
| st.write("") | |
| if st.button("✍️ Customize template", use_container_width=True): | |
| st.session_state.editing_mode = True | |
| # Si la template no ha sido editada antes, la cargamos desde los archivos originales | |
| if template_name not in st.session_state.edited_templates: | |
| initial_data = load_template_files(template_name) | |
| st.session_state.edited_templates[template_name] = { | |
| "json": initial_data["json"], | |
| "css": initial_data["css"], | |
| "resources_zip": None, | |
| "modified": False | |
| } | |
| st.rerun() | |
| st.divider() | |
| st.session_state.edit_requested = st.checkbox( | |
| "I want to review and edit the processed subtitles before rendering", | |
| value=st.session_state.get('edit_requested', False) | |
| ) | |
| b_next_col, b_back_col = st.columns(2) | |
| with b_next_col: | |
| if st.button("Render Video ➡️", type="primary", use_container_width=True): | |
| process_and_advance() | |
| with b_back_col: | |
| if st.button("⬅️ Start Over", use_container_width=True): | |
| reset_all() | |
| st.rerun() | |
| def handle_editing_mode(): | |
| template_name = st.session_state.selected_template | |
| st.info(f"You are customizing the **'{template_name}'** template.") | |
| current_edit_data = st.session_state.edited_templates[template_name] | |
| editor_result = template_editor( | |
| json=current_edit_data["json"], | |
| css=current_edit_data["css"], | |
| key=f"editor_{template_name}" | |
| ) | |
| if editor_result: | |
| if editor_result.get("action") == "save": | |
| old_json = st.session_state.edited_templates[template_name].get("json", None) | |
| old_css = st.session_state.edited_templates[template_name].get("css", None) | |
| new_json = editor_result["json_content"] | |
| new_css = editor_result["css_content"] | |
| # This is a little bit tricky, but this logic can be executed multiple times for the same preview (because of using st.rerun) | |
| # So, if `was_content_modified` is not used, we are going to remove the preview when this is re-rendered but the code was not changed | |
| # On the other hand, modified must be always "True", since if we use `was_content_modified` here, it will be "False" when this is re-rendered for the same saving | |
| was_content_modified = old_json != new_json or old_css != new_css | |
| st.session_state.edited_templates[template_name]["json"] = new_json | |
| st.session_state.edited_templates[template_name]["css"] = new_css | |
| st.session_state.edited_templates[template_name]["modified"] = True | |
| if template_name in st.session_state.previews and was_content_modified: | |
| del st.session_state.previews[template_name] | |
| st.toast("✅ Template saved!") | |
| st.success("✅ Template saved!") | |
| elif editor_result.get("action") == "error": | |
| st.error(editor_result.get("message", "An error occurred in the editor.")) | |
| st.session_state.edited_templates[template_name]["resources_zip"] = st.file_uploader( | |
| "(Optional) Upload a `.zip` to add or overwrite resources", type=["zip"], | |
| key=f"uploader_{template_name}" | |
| ) | |
| edit_buttons_col1, edit_buttons_col2 = st.columns(2) | |
| with edit_buttons_col1: | |
| if st.button("Back to Templates", use_container_width=True): | |
| st.session_state.editing_mode = False | |
| st.rerun() | |
| with edit_buttons_col2: | |
| if st.button("Reset to Original", help="Discards all edits for this template.", use_container_width=True): | |
| if template_name in st.session_state.edited_templates: | |
| del st.session_state.edited_templates[template_name] | |
| if template_name in st.session_state.previews: | |
| del st.session_state.previews[template_name] | |
| st.toast(f"Template '{template_name}' has been reset to its original state.") | |
| st.success(f"Template '{template_name}' has been reset to its original state.") | |
| st.session_state.editing_mode = False | |
| st.rerun() | |
| def process_and_advance(): | |
| with st.spinner("Applying configuration..."): | |
| try: | |
| builder = create_pipeline_builder() | |
| builder.with_input_video(st.session_state.video_path) | |
| setup_api_keys(st.session_state.api_key_type, st.session_state.api_key_input) | |
| pipeline = builder.build() | |
| pipeline.prepare() | |
| document = Document.from_dict(st.session_state.transcribed_doc) | |
| processed_document = pipeline.process_document(document) | |
| pipeline.close() | |
| st.session_state.processed_doc = processed_document.to_dict() | |
| go_to_step(3) | |
| st.rerun() | |
| except Exception as e: | |
| handle_unexpected_exception(e) | |
| finally: | |
| cleanup_api_keys() | |
| def render_preview_column(): | |
| st.subheader("Live Preview") | |
| st.markdown("Generate a short, low-quality video preview with the selected style. This takes a few seconds.") | |
| st.warning("AI features (auto-emojis, ai tagger) are ignored in the preview.") | |
| preview_container = st.container() | |
| template_name = st.session_state.get('selected_template') | |
| has_preview_for_template = template_name in st.session_state.previews | |
| should_disable_button = has_preview_for_template or st.session_state.preview_generating | |
| if has_preview_for_template: | |
| preview_container.video(st.session_state.previews[template_name]) | |
| if st.button("Generate Preview ⚡", use_container_width=True, disabled=should_disable_button): | |
| st.session_state.preview_generating = True | |
| st.rerun() | |
| if st.session_state.preview_generating: | |
| try: | |
| with st.spinner("Generating preview video... ⚡"): | |
| builder = create_pipeline_builder() | |
| builder.with_input_video(st.session_state.video_path) | |
| pipeline = builder.build(preview_time=(0, 5)) | |
| document = Document.from_dict(st.session_state.transcribed_doc) | |
| pipeline.prepare() | |
| processed_document = pipeline.process_document(document) | |
| pipeline.render(processed_document) | |
| pipeline.close() | |
| preview_output_path = pipeline._output_video_path | |
| if preview_output_path and os.path.exists(preview_output_path): | |
| st.session_state.previews[template_name] = preview_output_path | |
| else: | |
| raise RuntimeError("Could not generate preview.") | |
| except Exception as e: | |
| handle_unexpected_exception(e) | |
| finally: | |
| st.session_state.preview_generating = False | |
| st.rerun() | |