File size: 29,954 Bytes
2127f72
b8166be
ff33505
 
28f11ce
2127f72
f19e8bd
ff33505
285d72c
025d333
2127f72
 
74db061
285d72c
74db061
334a625
 
 
 
 
 
 
 
f19e8bd
025d333
 
 
 
 
 
 
69cbcdc
025d333
800c4e4
 
 
 
 
 
 
 
 
 
 
 
 
 
025d333
 
285d72c
025d333
 
e832fd0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9e08ef7
 
 
 
800c4e4
69cbcdc
334a625
9e08ef7
 
334a625
550edf4
800c4e4
9e08ef7
800c4e4
 
 
 
 
 
9e08ef7
800c4e4
 
 
 
 
9e08ef7
 
800c4e4
 
 
 
 
 
 
 
 
 
 
 
 
 
9e08ef7
800c4e4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9e08ef7
 
800c4e4
334a625
 
9e08ef7
 
 
 
 
 
7a1f1e8
334a625
 
 
 
69cbcdc
 
 
 
 
 
 
 
 
 
334a625
 
 
 
 
 
 
 
 
69cbcdc
 
 
 
 
 
7a1f1e8
800c4e4
69cbcdc
 
 
 
 
334a625
9e08ef7
69cbcdc
9e08ef7
 
285d72c
 
025d333
285d72c
2127f72
025d333
 
285d72c
 
 
 
 
8338bd9
 
28f11ce
 
 
 
285d72c
025d333
 
 
 
 
285d72c
 
e32ad38
e832fd0
025d333
2127f72
e32ad38
025d333
 
 
 
 
285d72c
 
8e9804e
 
025d333
e832fd0
 
285d72c
025d333
5327ecd
8e9804e
 
 
 
 
 
 
 
 
 
 
 
025d333
 
 
 
285d72c
8e9804e
27a6243
8e9804e
 
 
 
 
 
 
 
 
8338bd9
 
28f11ce
 
 
 
 
 
8338bd9
 
8e9804e
 
 
69cbcdc
8e9804e
 
 
 
 
 
 
5327ecd
8338bd9
8e9804e
 
 
8338bd9
 
 
 
 
 
28f11ce
8338bd9
 
27a6243
 
 
 
 
 
 
 
 
8a1b957
27a6243
 
e32ad38
285d72c
 
69cbcdc
9d13f89
69cbcdc
 
9d13f89
69cbcdc
285d72c
69cbcdc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
285d72c
de4e0ef
 
69cbcdc
 
 
de4e0ef
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
285d72c
f4c5608
3757f89
0255152
58daa96
 
 
 
69cbcdc
58daa96
 
 
0255152
58daa96
 
69cbcdc
58daa96
f4c5608
 
58daa96
 
 
 
 
 
 
 
 
69cbcdc
 
 
 
 
 
58daa96
69cbcdc
58daa96
69cbcdc
 
58daa96
69cbcdc
58daa96
 
 
 
 
0255152
58daa96
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f4c5608
 
58daa96
 
 
 
 
 
69cbcdc
0255152
69cbcdc
 
0255152
3757f89
58daa96
69cbcdc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3757f89
f4c5608
0255152
3757f89
0255152
69cbcdc
 
 
 
 
 
285d72c
 
 
 
 
3aca5a7
285d72c
 
3aca5a7
8338bd9
28f11ce
 
 
 
 
285d72c
3aca5a7
285d72c
 
3aca5a7
28f11ce
025d333
2127f72
 
025d333
b344bb8
285d72c
b8166be
025d333
 
 
f19e8bd
 
e32ad38
025d333
e32ad38
9d13f89
e32ad38
 
e832fd0
f19e8bd
025d333
b8166be
 
f19e8bd
b645eee
f19e8bd
e32ad38
0446082
 
 
 
 
 
 
 
 
 
f19e8bd
025d333
f19e8bd
025d333
 
 
 
 
f19e8bd
025d333
 
 
 
 
 
f19e8bd
025d333
e832fd0
8a1b957
3aca5a7
28f11ce
ff33505
025d333
b8166be
025d333
b8166be
 
 
 
 
 
 
 
 
 
 
 
e32ad38
025d333
2127f72
025d333
 
69cbcdc
0446082
025d333
 
b645eee
025d333
 
 
 
 
 
 
 
 
 
 
2127f72
025d333
b8166be
 
b344bb8
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
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
from typing import Tuple
import gradio as gr
from Project import *
from common_functions_v4 import *
from event_handler import create_step1_render, create_step2a_render, create_step2b_render, create_step2c_render, create_step2d_render, create_step3_render, setup_all_handlers
from google_drive import *
from notion import *
from state import state
from prompt_configs import *
from typing import Dict, Any, Tuple
import pandas as pd
from io import StringIO
import importlib
import prompt_configs

def update_prompts():
    try:
        importlib.reload(prompt_configs)
        global PROMPTS
        PROMPTS = prompt_configs.PROMPTS
        print("PROMPTS updated successfully.")
    except Exception as e:
        print(f"Error updating PROMPTS: {str(e)}")

def create_ui_component(config: UIConfig, prompt: str = None) -> Any:
    if config.component_type == UIComponentType.TEXTBOX:
        return gr.Textbox(
            label=config.label,
            lines=config.lines if config.lines else 1,
            interactive=config.interactive,
            visible=config.visible,
            value=prompt.strip() if prompt else ""
        )
    elif config.component_type == UIComponentType.MARKDOWN:
        return gr.Markdown(
            label=config.label,
            visible=config.visible,
            show_copy_button=config.show_copy_button,
            value=prompt,
            elem_classes=["scrollable-markdown"]
        )
    elif config.component_type == UIComponentType.DATAFRAME:
        return gr.Dataframe(
            label=config.label,
            interactive=config.interactive,
            visible=config.visible
        )
    return None

def create_prompt_editor_components(prompt_config: PromptConfig) -> Dict[str, Any]:
    components = {}
    
    with gr.Row():
        with gr.Column(scale=1):
            editor_key = next((k for k in prompt_config.ui.keys() if k.endswith('_prompt_editor')), None)
            if editor_key:
                lines = prompt_config.prompt.split('\n')
                if lines:
                    min_indent = min((len(line) - len(line.lstrip()) 
                                   for line in lines if line.strip()), 
                                   default=0)
                    formatted_lines = [
                        line[min_indent:] if line.strip() else ''
                        for line in lines
                    ]
                    formatted_prompt = '\n'.join(formatted_lines)
                else:
                    formatted_prompt = ""
                    
                # Create prompt editor in dropdown
                editor = create_ui_component(
                    prompt_config.ui[editor_key],
                    formatted_prompt
                )
                
                # save_button = gr.Button("Save Changes")
                
                # Add save status display
                save_status = gr.Markdown("Ready to save changes...", visible=True)
                
                def save_prompt_changes(new_prompt: str, prompt_key: str) -> str:
                    global PROMPTS
                    try:
                        # Find the correct prompt key
                        prompt_key = None
                        for key, config in PROMPTS.items():
                            if editor_key in config.ui:
                                prompt_key = key
                                break
                        
                        if not prompt_key:
                            return "❌ Error: Could not find matching prompt key"
                        
                        # Update in-memory config
                        PROMPTS[prompt_key].prompt = new_prompt.strip()
                        
                        # Read current file content
                        with open("prompt_configs.py", "r", encoding='utf-8') as f:
                            content = f.read()
                        
                        # Find the start of the prompt section
                        section_start = f'    "{prompt_key}": PromptConfig('
                        start_idx = content.find(section_start)
                        
                        if start_idx == -1:
                            return "❌ Error: Could not locate prompt section in config file"
                        
                        # Find the prompt= part
                        prompt_start = content.find('prompt=', start_idx)
                        if prompt_start == -1:
                            return "❌ Error: Could not locate prompt parameter"
                        
                        # Find the triple quote after prompt=
                        first_quote = content.find('"""', prompt_start)
                        if first_quote == -1:
                            return "❌ Error: Could not locate start of prompt content"
                            
                        # Find the closing triple quote
                        end_quote = content.find('"""', first_quote + 3)
                        if end_quote == -1:
                            return "❌ Error: Could not locate end of prompt content"
                        
                        # Format the new prompt with proper indentation
                        indented_lines = []
                        for line in new_prompt.strip().split('\n'):
                            if line.strip():
                                indented_lines.append(f'        {line.strip()}')
                            else:
                                indented_lines.append('        ')
                        
                        # Create the new section with proper formatting
                        new_section = (
                            'prompt=\n'
                            '        """\n' + 
                            '\n'.join(indented_lines) + 
                            '\n        """'
                        )
                        
                        # Replace just the prompt content
                        new_content = (
                            content[:prompt_start] +
                            new_section +
                            content[end_quote + 3:]
                        )
                        
                        # Write back to file
                        with open("prompt_configs.py", "w", encoding='utf-8') as f:
                            f.write(new_content)
                        
                        
                        return "βœ… Prompt updated successfully"
                        
                    except Exception as e:
                        return f"❌ Error updating prompt: {str(e)}"
                
                
                temp_changes = {}

                def store_changes(new_prompt: str):
                    # Update the temporary changes dictionary
                    # Find the correct prompt key
                    prompt_key = None
                    for key, config in PROMPTS.items():
                        if editor_key in config.ui:
                            prompt_key = key
                            break
                    
                    if not prompt_key:
                        raise ValueError(f"Could not find matching prompt key for editor {editor_key}")
                        
                    temp_changes[prompt_key] = new_prompt
                    return "Changes stored. Click 'Save All' to apply."

                editor.change(
                    fn=store_changes,
                    inputs=[editor],
                    outputs=[save_status]
                )
                
                # def save_all_changes():
                #     # Iterate over all stored changes and save them
                #     for key, new_prompt in temp_changes.items():
                #         save_prompt_changes(new_prompt, key)
                #         update_prompts()
                #     return "βœ… All changes saved and prompts reloaded."

                
                # save_button.click(
                #     fn=save_all_changes,
                #     inputs=[],
                #     outputs=[save_status]
                # )
                
                components[editor_key] = editor
                # components[f"{editor_key}_save_button"] = save_button
                components[f"{editor_key}_save_status"] = save_status

    return components

def create_quotation_generator_section():
    # Initialize all variables at the start
    quotation_cost = None
    page_recalc_btn = None
    page_progress_update = None
    page_upload_drive_btn = None
    page_upload_notion_btn = None
    page_notes_box = None
    page_save_quotation_btn = None
    project_name = None
    step1_results = gr.State()
    step2a_results = gr.State()
    step2b_results = gr.State()
    step2c_results = gr.State()
    step2d_results = gr.State()
    step3_results = gr.State()

    with gr.Tab(label="Quotation Generator"):
        with gr.Row():
            with gr.Column(scale=2):
                gr.Markdown("## ⚠️ Instructions #2")
                for instruction in [
                    "1. **Edit System Prompt**: Navigate to the System Prompts tab to edit prompts.",
                    "2. **Generate Output**: Click generate once ready.",
                    "3. **Upload Final Documentation**: Give a project name and click upload to Google Drive or Notion",
                    "4. **Recalculate Cost**: Recalculate the cost if you want to change the mandays estimate"
                ]:
                    gr.Markdown(instruction) 
                
            with gr.Column(scale=1):
                page_progress_update = gr.Textbox(label="Progress Update", lines=6, interactive=False)

        with gr.Row():
            with gr.Column(scale=4):
                # Organize steps and their outputs
                step_outputs = {}
                sub_steps = {}
                
                for prompt_key, prompt_config in PROMPTS.items():
                    if prompt_config.step == "Chatbot Prompt Editors":
                        continue
                    
                    step = prompt_config.step
                    sub_step = prompt_config.sub_step
                    if step and step.strip():
                        if step not in step_outputs:
                            step_outputs[step] = []
                        step_outputs[step].append(prompt_key)
                        
                        # Track sub-steps if they exist
                        if sub_step:
                            if step not in sub_steps:
                                sub_steps[step] = {}
                            if sub_step not in sub_steps[step]:
                                sub_steps[step][sub_step] = []
                            sub_steps[step][sub_step].append(prompt_key)

                all_components = {}
                step_buttons = {}

                # Create main step accordions
                for step_name, prompt_keys in step_outputs.items():
                    with gr.Accordion(step_name, open=False):
                        if "Step 2" in step_name:
                            with gr.Row():
                                with gr.Column(scale=4):
                                    # Check if this step has sub-steps
                                    if step_name in sub_steps:
                                        # Iterate through sub-steps for this step
                                        for sub_step_name, prompt_keys_list in sub_steps[step_name].items():
                                            button_label = sub_step_name.split(' : ')[1] if ' : ' in sub_step_name else sub_step_name
                                            step_buttons[sub_step_name] = gr.Button(f"βœ… {button_label}")
                                            if "Step 2.1" in sub_step_name:
                                                create_step2a_render(step2a_results)
                                            elif "Step 2.2" in sub_step_name:
                                                create_step2b_render(step2b_results)
                                            elif "Step 2.3" in sub_step_name:
                                                create_step2c_render(step2c_results)
                                            elif "Step 2.4" in sub_step_name:
                                                create_step2d_render(step2d_results)
                                            
                              
                                with gr.Column(scale=1):                 
                                    quotation_cost = gr.Textbox(label="Cost Summary", lines=3, interactive=False)
                                    page_recalc_btn = gr.Button("Recalculate")
                                    # print(f"recalc_btn created: {page_recalc_btn}")  
                
                                    page_notes_box = gr.Textbox(
                                        label="Notes", 
                                        lines=3, 
                                        placeholder="Add your notes here..."
                                    )
                                    page_save_quotation_btn = gr.Button("Save Quotation with Note")
                            
                        elif "Step 1" in step_name:
                            # Regular step button for non-Step 2
                            button_label = step_name.split(' : ')[1] if ' : ' in step_name else step_name
                            step_buttons[step_name] = gr.Button(f"βœ… Generate {button_label}")
                            create_step1_render(step1_results)
                        
                        elif "Step 3" in step_name:
                            # Regular step button for non-Step 2
                            button_label = step_name.split(' : ')[1] if ' : ' in step_name else step_name
                            step_buttons[step_name] = gr.Button(f"βœ… Generate {button_label}")
                            create_step3_render(step3_results)
                            

        with gr.Column(scale=1):
            with gr.Row():
                with gr.Column(scale=2):
                    project_name = gr.Textbox(
                        placeholder="Please enter a project name to be saved in Google Drive and Notion",
                        label="Project Name",
                        lines=1.5,
                        interactive=True
                    )
                with gr.Column(scale=1):
                    page_upload_drive_btn = gr.Button("πŸ“ Upload to Google Drive")
                    page_upload_notion_btn = gr.Button("πŸ“ Upload to Notion")

    # Add system prompts tab
    with gr.Tab(label="System Prompts"):
        with gr.Row():
            refresh_button = gr.Button("πŸ”„ Refresh All Prompts",visible= False)
            bulk_save_button = gr.Button("Save Prompts")
        with gr.Row():
            refresh_status = gr.Markdown("", visible= False)
            bulk_save_status = gr.Markdown("")
        gr.Markdown("Edit the system prompts below to customize the generation process.")
        # Function to refresh all prompts from the database
        def refresh_all_prompts():
            try:
                # Reload configuration from database
                state.quotation_project.load_config_from_db()
                
                # Update all UI components with the latest values
                updated_count = 0
                for prompt_key, prompt_config in state.quotation_project._db_config.items():
                    # print(f"Processing prompt: {prompt_key}")
                    if prompt_key in all_components:
                        print(f"Found components for {prompt_key}: {all_components[prompt_key].keys()}")
                        for sub_key, component in all_components[prompt_key].items():
                            # print(f"Processing component {sub_key}")
                            if sub_key.endswith("_prompt_editor") and hasattr(component, "value"):
                                print(f"Found prompt editor component: {sub_key}")
                                # Format the prompt properly
                                lines = prompt_config.prompt.split('\n')
                                if lines:
                                    min_indent = min((len(line) - len(line.lstrip()) 
                                                for line in lines if line.strip()), 
                                                default=0)
                                    formatted_lines = [
                                        line[min_indent:] if line.strip() else ''
                                        for line in lines
                                    ]
                                    formatted_prompt = '\n'.join(formatted_lines)
                                else:
                                    formatted_prompt = ""
                                
                                # Update the component value
                                print(f"Setting value for {sub_key} to: {formatted_prompt[:100]}...")
                                component.value = formatted_prompt
                                updated_count += 1
                                print(f"Updated count is now: {updated_count}")
                
                return f"βœ… Successfully refreshed {updated_count} prompts from the database"
            except Exception as e:
                print(f"ERROR in refresh_all_prompts: {str(e)}")
                return f"❌ Error refreshing prompts: {str(e)}"
        
        # Group prompts by step
        prompts_by_step = {}
        print("in create_quotation_generator_section: loading config from db to create accordions")
        state.quotation_project.load_config_from_db()
        for prompt_key, prompt_config in state.quotation_project._db_config.items():
            step = prompt_config.step
            if step not in prompts_by_step:
                prompts_by_step[step] = []
            prompts_by_step[step].append((prompt_key, prompt_config))
        
        # Create an accordion for each step
        for step, prompt_configs in prompts_by_step.items():
            with gr.Accordion(step, open=False):
                for prompt_key, prompt_config in prompt_configs:
                    if prompt_config.ui is not None:
                        editor_key = next((k for k in prompt_config.ui.keys() if k.endswith('_prompt_editor')), None)
                        if editor_key:
                            with gr.Accordion(prompt_config.description, open=False):
                                components = create_prompt_editor_components(prompt_config)
                                # Add editor components to all_components
                                if prompt_key in all_components:
                                    all_components[prompt_key].update(components)
                                else:
                                    all_components[prompt_key] = components

        def bulk_save_prompts():
            print("Bulk saving prompts")
            try:
                # Create a backup of current PROMPTS
                original_prompts = {key: prompt_config.prompt for key, prompt_config in PROMPTS.items()}
                
                # Create the output file in prompt_configs_exp.py format
                # print("Starting bulk save prompts function")
                with open("prompt_configs_exp.txt", "w", encoding="utf-8") as f:
                    # Write everything at once instead of line by line
                    output_content = "{\n"
                    
                    # Iterate through all components and update PROMPTS with editor values
                    for prompt_key, prompt_config in PROMPTS.items():
                        # print(f"Processing prompt key: {prompt_key}")
                        
                        # Start the PromptConfig section with $$
                        output_content += f'    $$"{prompt_key}": PromptConfig(\n'
                        output_content += '        prompt="""\n'
                        
                        # Get the updated prompt value if it exists in components
                        updated_prompt = None
                        if prompt_key in all_components:
                            for sub_key, component in all_components[prompt_key].items():
                                if sub_key.endswith("_prompt_editor"):
                                    try:
                                        if hasattr(component, "value"):
                                            updated_prompt = component.value.strip()
                                            if updated_prompt is None:
                                                print(f"Warning: Prompt value is null for {prompt_key}")
                                            else:
                                                # print(f"Found updated prompt for {prompt_key} with value: {updated_prompt[:50]}")
                                                print(f"Found updated prompt for {prompt_key}")
                                    except Exception:
                                        print(f"Could not find updated prompt for {prompt_key}")
                                        pass
                        else:
                            print(f"No components found for {prompt_key}")
                        # Add the prompt content with proper indentation
                        #TODO: check why need indentation
                        prompt_content = updated_prompt if updated_prompt else prompt_config.prompt
                        for line in prompt_content.split('\n'):
                            output_content += f'        {line}\n'
                        
                        output_content += '        """,\n'
                        
                        # Add other PromptConfig attributes
                        output_content += f'        description="{prompt_config.description}",\n'
                        output_content += f'        step="{prompt_config.step if prompt_config.step else ""}",\n'
                        output_content += f'        sub_step="{prompt_config.sub_step if prompt_config.sub_step else ""}",\n'
                        output_content += f'        inputs={prompt_config.inputs},\n'
                        output_content += f'        outputs={prompt_config.outputs},\n'
                        output_content += f'        model={prompt_config.model},\n'
                        
                        # Add thoughts if they exist
                        if prompt_config.thoughts:
                            output_content += f'        thoughts={prompt_config.thoughts},\n'
                        else:
                            output_content += '        thoughts=None,\n'
                        
                        # Add UI config
                        if prompt_config.ui:
                            output_content += '        ui='
                            # Convert UI config to string representation
                            ui_str = str(prompt_config.ui).replace('UIComponentType.', '')
                            output_content += f'{ui_str}\n'
                        else:
                            output_content += '        ui=None,\n'
                        
                        # End PromptConfig section with $$
                        output_content += '    )$$,\n'
                    
                    output_content += '}\n'
                    
                    # Write the entire content at once
                    f.write(output_content)
                    save_prompt_to_db(output_content)
                    load_msg = state.quotation_project.load_config_from_db()
                
                print(f"Successfully updated {len(all_components)} prompts in DB")
                return f"βœ… Prompts updated successfully; {load_msg}"
            except Exception as e:
                print(f"ERROR in bulk_save_prompts: {str(e)}")
                return f"❌ Error updating prompts: {str(e)}"

        # Connect the refresh button to the refresh function
        def wait_and_clear(wait_time=4):
            """Reusable function to wait and clear status messages"""
            time.sleep(wait_time)
            return ""

        refresh_button.click(
            fn=refresh_all_prompts,
            inputs=[],
            outputs=[refresh_status]
        )
        # ).then(
        #     fn=wait_and_clear,
        #     inputs=None,
        #     outputs=refresh_status
        # )

        bulk_save_button.click(
            fn=bulk_save_prompts,
            inputs=[],
            outputs=[bulk_save_status]
        )
        # ).then(
        #     fn=wait_and_clear,
        #     inputs=None,
        #     outputs=bulk_save_status
        # )

    setup_all_handlers(
        step_buttons,
        all_components,
        page_progress_update,
        quotation_cost,
        page_recalc_btn,
        page_upload_drive_btn,
        page_upload_notion_btn,
        project_name,
        step1_results,
        step2a_results,
        step2b_results,
        step2c_results,
        step2d_results,
        step3_results
    )
    
    return (all_components, step_buttons, 
            page_progress_update, page_upload_drive_btn, page_upload_notion_btn, 
            quotation_cost, page_recalc_btn, page_notes_box, page_save_quotation_btn, 
            project_name , step1_results, step2a_results, step2b_results, step2c_results, step2d_results, step3_results)

with open("page_main.css", "r") as file:
    custom_css = file.read()

with gr.Blocks(title="Quotation Chatbot (with SOW)", css=custom_css) as demo:
    gr.Markdown("# Quotation Chatbot with SOW")
    
    all_components = {}
    
    with gr.Tab(label="Page Main"):
        gr.Markdown("## ⚠️ Instructions #1")
        gr.Markdown("### Either select Option 1 or 2 , then scroll down to generate a quotation.")
        gr.Markdown("1. **Start a New Session**: Begin answering questions for a new project at the Edit Area.")
        gr.Markdown("2. **Load an Existing Project**: Navigate to the **Load Project** tab.")
        gr.Markdown("**πŸ‘‡ Note**: You may edit the system prompts for the chatbot as below : ")
               
        with gr.Row():
            start_btn = gr.Button("Start New Session")
        
        with gr.Row():
            current_session_display = gr.Markdown(no_active_session)

        with gr.Row():
            with gr.Column(scale=1):
                current_question = gr.Textbox(label="Edit Area", lines=30, interactive=True)
            with gr.Column(scale=1):
                chatbot = gr.Chatbot(height=580 ,elem_classes=["chatbot-container"])
                gr.ChatInterface(
                    async_process_response,
                    chatbot= chatbot,
                    type="messages",
                    fill_height=True,
                    additional_outputs= [current_question],
                    flagging_mode= "manual"
                    # show_progress= 'minimal',
                    # save_history= True
                )

        gr.Markdown("Below are sample answers you can refer to:")
        with gr.Accordion("Sample AR Answers", open=False):
            sample_answers = [
                {'file': 'q1_answer.txt', 'label': 'Company Background & Industry'},
                {'file': 'q2_answer.txt', 'label': 'Current Challenges & Workflow'},
                {'file': 'q3_answer.txt', 'label': 'Project Requirements & Goals'}
            ]
            
            for i, qa in enumerate(sample_answers, 1):
                with gr.Accordion(f"Q{i}. {qa['label']}", open=False):
                    gr.Markdown(
                        value=open(qa['file'], 'r').read(), 
                        visible=True, 
                        show_copy_button=True
                    )
        
        (all_components, step_buttons, page_progress_update, 
         page_upload_drive_btn, page_upload_notion_btn, 
         quotation_cost, page_recalc_btn, page_notes_box, page_save_quotation_btn, 
         project_name , step1_results , step2a_results, step2b_results, step2c_results, step2d_results, step3_results) = create_quotation_generator_section()

    with gr.Tab(label="Load Project"):
        gr.Markdown("### Past submissions")
        gr.Markdown("Quick hack to load past submissions to regenerate quotations (This page displays Q&A only; previous quotations are not shown yet).")
        gr.Markdown("Use Session ID 15 for test AR")

        with gr.Row():
            session_input = gr.Number(label="Session ID", precision=0)
            message_box = gr.Textbox(label="Message", interactive=False)
            status_box = gr.Textbox(
                label="Project Status", 
                value="",
                interactive=False
            )
        fetch_btn = gr.Button("Fetch Session")
        
        with gr.Tab(label="Requirements"):
            fetched_requirements_box = gr.Markdown(value="")

    def setup_event_handlers():
        start_btn.click(
            fn=start_chat,
            outputs=[current_question, current_session_display]
        )
        

        fetch_btn.click(
            fn=fetch_session,
            inputs=[session_input],
            outputs=[
                status_box, 
                fetched_requirements_box,
                message_box,
                current_session_display,
            ]
        )

    # Call setup_event_handlers after all components are created
    setup_event_handlers()

if __name__ == "__main__":
    demo.launch(share=True)