File size: 16,169 Bytes
fed9343
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74acfe3
fed9343
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56c210b
 
c38002e
 
 
 
 
 
 
 
 
 
 
 
 
fed9343
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7077f95
fed9343
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import gradio as gr
import pandas as pd
import json
import os
from .dataset_logic import DatasetAgent, save_to_json, load_from_json

# Global instance for UI
agent = DatasetAgent()

def generate_blueprint_handler(topic, depth, breadth, model_name, api_key):
    if not topic:
        return None, None
    df = agent.generate_blueprint(topic, int(depth), int(breadth), model_name=model_name, api_key=api_key or None)
    filepath = save_to_json(df, "blueprint")
    return df, filepath

def generate_qa_handler(blueprint_df, model_name, api_key):
    if blueprint_df is None or blueprint_df.empty:
        return None, None
    # Agent iterates over the tags in the blueprint to generate MCQs
    final_df = agent.generate_qa_batch(blueprint_df, model_name=model_name, api_key=api_key or None)
    filepath = save_to_json(final_df, "full_dataset")
    return final_df, filepath

def load_json_handler(file):
    if file is None: return None
    return load_from_json(file)

def save_json_handler(df, prefix):
    if df is None: return None
    return save_to_json(df, prefix)

def create_ui():
    """
    Constructs the Performance-Aware Model Compression for Circuit Analysis GUI.
    """
    theme = gr.themes.Soft(
        primary_hue="blue", 
        secondary_hue="gray",
        font=[gr.themes.GoogleFont("Outfit"), "sans-serif"]
    )
    
    with gr.Blocks(theme=theme, title="Model Compression Engine") as app:
        gr.Markdown("""
        # πŸ§ͺ Performance-Aware Model Compression for Circuit Analysis
        *A workflow for building hierarchical prerequisite graphs for model compression evaluation.*
        """)
        
        with gr.Accordion("πŸ”‘ API Configuration", open=False):
            api_key_input = gr.Textbox(
                label="OpenAI API Key (Optional, defaults to .env)",
                placeholder="sk-...",
                type="password"
            )
        
        with gr.Tabs():
            # PHASE 1: BLUEPRINTTab
            with gr.TabItem("Phase 1: Dataset Blueprint"):
                with gr.Row():
                    with gr.Column(scale=1):
                        gr.Markdown("### 1. Configuration")
                        model_dropdown = gr.Dropdown(
                            choices=["gpt-4o", "gpt-4o-mini", "gpt-4-turbo", "gpt-3.5-turbo"],
                            value="gpt-4o",
                            label="OpenAI Model for Generation"
                        )
                        topic = gr.Textbox(
                            label="Main Subject / Topic", 
                            placeholder="e.g. Modern Web Infrastructure and Scalability",
                            lines=2
                        )
                        with gr.Row():
                            depth = gr.Slider(1, 5, 2, step=1, label="Graph Depth")
                            breadth = gr.Slider(1, 4, 2, step=1, label="Parent Fan-out")
                        
                        gen_bp_btn = gr.Button("πŸš€ Generate Blueprint", variant="primary")
                        
                        gr.Markdown("---")
                        gr.Markdown("### 2. File Import/Export")
                        upload_bp = gr.File(
                            label="Upload Existing Blueprint (JSON)", 
                            file_types=[".json"]
                        )
                        gr.Examples(
                            examples=[["assets/blueprint_7o054luj.json"]],
                            inputs=upload_bp,
                            label="Blueprint Example"
                        )
                        download_bp_link = gr.File(label="Download Generated Blueprint", interactive=False)

                    with gr.Column(scale=3):
                        gr.Markdown("### 3. Blueprint Editor (Hierarchical Tags)")
                        blueprint_table = gr.Dataframe(
                            interactive=True,
                            wrap=True,
                            label="Edit Tags and Structure before Phase 2"
                        )
                
                gen_bp_btn.click(
                    generate_blueprint_handler, 
                    inputs=[topic, depth, breadth, model_dropdown, api_key_input], 
                    outputs=[blueprint_table, download_bp_link]
                )
                
                upload_bp.change(load_json_handler, inputs=[upload_bp], outputs=[blueprint_table])

            # PHASE 2: Q&A GENERATION
            with gr.TabItem("Phase 2: Question & Answer Generation"):
                gr.Markdown("### Submit the Blueprint for Full Q&A Generation")
                gr.Info("The agent will iterate over every entry's tags and generate specific MCQs using function calling.")
                
                with gr.Row():
                    run_qa_btn = gr.Button("⚑ Generate Questions & Answers", variant="primary", scale=1)
                    save_final_btn = gr.Button("πŸ’Ύ Save Final Dataset Snapshot", variant="secondary", scale=1)

                with gr.Row():
                    with gr.Column(scale=1):
                        upload_final = gr.File(
                            label="Upload Final Dataset (JSON)", 
                            file_types=[".json"]
                        )
                        gr.Examples(
                            examples=[["assets/full_dataset_6hxx81y3.json"]],
                            inputs=upload_final,
                            label="Full Dataset Example"
                        )
                        download_final_link = gr.File(label="Download Full Results", interactive=False)
                        
                    with gr.Column(scale=3):
                        final_table = gr.Dataframe(
                            interactive=True,
                            wrap=True,
                            label="Final Dataset Preview (MCQ & Ground Truth)"
                        )

                run_qa_btn.click(
                    generate_qa_handler,
                    inputs=[blueprint_table, model_dropdown, api_key_input],
                    outputs=[final_table, download_final_link]
                )
                
                save_final_btn.click(
                    save_json_handler,
                    inputs=[final_table, gr.State("final_dataset")],
                    outputs=[download_final_link]
                )
                
                upload_final.change(load_json_handler, inputs=[upload_final], outputs=[final_table])

            # PHASE 3: STRATEGIC EVALUATION
            with gr.TabItem("3. Strategic Evaluation"):
                tag_sets_state = gr.State({}) # Stores computed sets
                full_results_state = gr.State(None) # Stores raw DF for re-calc
                gr.Markdown("### πŸͺœ Hierarchical Model Cascade & DFS Eval")
                gr.Info("""
                This phase runs a 'laddering' evaluation:
                -   Starts with the smallest model.
                -   Tracks **path-cumulative failures**.
                -   **Upgrades** to a larger model if failures exceed the threshold.
                -   Perpetuates the better model for all child descendants.
                """)
                
                with gr.Row():
                    with gr.Column(scale=1):
                        with gr.Group():
                            gr.Markdown("#### Evaluation Config")
                            provider_selection = gr.Radio(
                                choices=["OpenAI", "Ollama"],
                                value="Ollama",
                                label="Model Provider"
                            )
                            model_list = gr.Textbox(
                                label="Sorted Model List (Smallest to Largest)", 
                                value="gemma3:270m, gemma3:1b, gemma3:4b",
                                placeholder="e.g. gpt-4o-mini, gpt-4o"
                            )
                            model_list_examples = gr.Examples(
                                examples=[["gpt-4o-mini, gpt-4o"],
                                          ["gemma3:270m, gemma3:1b, gemma3:4b"]],
                                inputs=model_list,
                                label="Model List Example"
                            )
                            fail_threshold = gr.Slider(0, 5, 1, step=1, label="Path Failure Threshold (Upgrade Trigger)")
                            
                        run_eval_btn = gr.Button("πŸ”Ž Start Strategic Evaluation", variant="primary")
                        
                        gr.Markdown("---")
                        gr.Markdown("#### Output Summary")
                        eval_summary_out = gr.Markdown("No evaluation run yet.")
                        eval_download_link = gr.File(label="Download Final Report", interactive=False)
                        

                    with gr.Column(scale=3):
                        gr.Markdown("---")
                        upload_eval_report = gr.File(label="Upload Existing Eval Report (JSON)", file_types=[".json"])
                        with gr.Row():
                            eval_report_example_file_path = "assets/full_eval_report_2u970ry9.json"
                            gr.Examples(
                                examples=[eval_report_example_file_path],
                                inputs=upload_eval_report,
                                label="Eval Report Example"
                            )
                            example_btn_uploader = gr.Button("Load Example")
                            example_btn_uploader.click(
                                fn = lambda: eval_report_example_file_path,
                                inputs=[],
                                outputs=upload_eval_report
                            )
                        with gr.Tabs():
                            with gr.TabItem("πŸ“ˆ Graph Visualization"):
                                eval_viz_out = gr.Image(label="Dependency & Model Usage Map", type="numpy")
                            with gr.TabItem("🏷️ Tag Set Analysis"):
                                with gr.Row():
                                    set_selector = gr.Dropdown(
                                        choices=[], 
                                        multiselect=True, 
                                        max_choices=3, 
                                        label="Select Sets to Compare (Min 2, Max 3)"
                                    )
                                    update_venn_btn = gr.Button("πŸ”„ Update Venn Diagram")
                                with gr.Row():
                                    monotonic_checkbox = gr.Checkbox(
                                        label="Apply Monotonic Capability Assumption (Small β†’ Large inheritance)",
                                        value=False
                                    )
                                with gr.Row():
                                    venn_img_out = gr.Image(label="Venn Diagram", type="numpy")
                                    venn_report_out = gr.Markdown("Select sets and click update.")
                            with gr.TabItem("πŸ“‹ Full Results Table"):
                                eval_table_out = gr.Dataframe(interactive=False, wrap=False)
                        

                def run_strategic_eval_handler(df, provider, models_str, threshold, api_key):
                    from .eval_logic import EvaluationEngine
                    if df is None or df.empty or not models_str:
                        return "Please provide dataset.", None, None, None, {}, gr.update()
                    
                    # 1. Parse Models
                    models = [m.strip() for m in models_str.split(',')]
                    
                    # 2. Run Engine
                    engine = EvaluationEngine(models, int(threshold), provider=provider, api_key=api_key or None)
                    results_df = engine.run_cascade_eval(df)
                    
                    # 3. Finalize results
                    summary = engine.generate_summary(results_df)
                    viz_img = engine.generate_visualization(results_df)
                    report_path = save_to_json(results_df, "full_eval_report")
                    tag_sets = engine.get_tag_sets(results_df)
                    available_sets = list(tag_sets.keys())
                    
                    import numpy as np
                    from PIL import Image
                    import io
                    img = Image.open(io.BytesIO(viz_img))
                    
                    return summary, report_path, np.array(img), results_df, tag_sets, gr.update(choices=available_sets, value=available_sets[:3] if len(available_sets) >=3 else available_sets)

                def load_eval_report_handler(file):
                    from .eval_logic import EvaluationEngine # load_from_json is already imported in this file and is not available in .eval_logic
                    if file is None: return None, None, None, None, {}, gr.update(choices=[], value=[])
                    
                    results_df = load_from_json(file)
                    if results_df.empty:
                        return "Error loading file.", None, None, None, {}, gr.update(choices=[], value=[])
                    
                    # Instantiate engine with defaults just for viz/summary mapping
                    engine = EvaluationEngine([], 0) 
                    summary = engine.generate_summary(results_df)
                    viz_img = engine.generate_visualization(results_df)
                    tag_sets = engine.get_tag_sets(results_df)
                    available_sets = list(tag_sets.keys())
                    
                    import numpy as np
                    from PIL import Image
                    import io
                    img = Image.open(io.BytesIO(viz_img))
                    
                    return summary, file.name, np.array(img), results_df, tag_sets, gr.update(choices=available_sets, value=available_sets[:3] if len(available_sets) >=3 else available_sets)

                def update_venn_handler(results_df, selected, apply_monotonic):
                    from .eval_logic import EvaluationEngine
                    if results_df is None or len(selected) < 2:
                        return None, "Select at least 2 sets."
                    
                    engine = EvaluationEngine([], 0)
                    tag_sets = engine.get_tag_sets(results_df, apply_monotonic=apply_monotonic)
                    viz_bytes, report = engine.plot_tag_venn(tag_sets, selected)
                    
                    import numpy as np
                    from PIL import Image
                    import io
                    img = Image.open(io.BytesIO(viz_bytes))
                    return np.array(img), report

                run_eval_btn.click(
                    run_strategic_eval_handler,
                    inputs=[final_table, provider_selection, model_list, fail_threshold, api_key_input],
                    outputs=[eval_summary_out, eval_download_link, eval_viz_out, eval_table_out, tag_sets_state, set_selector]
                ).then(
                    lambda df: df, inputs=[eval_table_out], outputs=[full_results_state]
                )
                
                upload_eval_report.change(
                    load_eval_report_handler,
                    inputs=[upload_eval_report],
                    outputs=[eval_summary_out, eval_download_link, eval_viz_out, eval_table_out, tag_sets_state, set_selector]
                ).then(
                    lambda df: df, inputs=[eval_table_out], outputs=[full_results_state]
                )

                update_venn_btn.click(
                    update_venn_handler,
                    inputs=[full_results_state, set_selector, monotonic_checkbox],
                    outputs=[venn_img_out, venn_report_out]
                )

    return app