File size: 9,275 Bytes
d083627
 
6774799
 
 
 
d083627
6774799
d083627
 
 
6774799
 
 
d083627
 
 
6774799
d083627
 
 
6774799
d083627
6774799
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d083627
 
 
6774799
d083627
 
6774799
d083627
 
 
 
 
 
6774799
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d083627
6774799
d083627
 
 
 
 
 
6774799
d083627
 
 
 
 
6774799
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d083627
 
 
 
 
 
6774799
d083627
 
6774799
d083627
6774799
 
 
 
d083627
 
6774799
d083627
 
 
6774799
 
d083627
 
 
 
 
 
 
 
 
 
 
 
6774799
d083627
 
 
 
 
6774799
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
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()