import gradio as gr from utils.template_discovery import discover_templates from utils.data_generator import generate_examples from llm_client import ask_llm from utils.evaluation import compute_similarity, validate_answer import asyncio import os print("Scanning for all available Engchain templates...") ALL_TEMPLATES = discover_templates() print("...Scan complete.") def format_name(name): return name.replace("_", " ").replace(".py", "").replace("template ", "").title() def call_llm(question): if not question: return "⚠️ No question provided." return ask_llm(question) with gr.Blocks(theme=gr.themes.Soft(), css=""" .example-card { border: 2px solid var(--border-color-primary); border-radius: 12px; padding: 15px; margin-bottom: 18px; background: var(--block-background-fill); box-shadow: 0 4px 8px rgba(0,0,0,0.07); } .question-box { background: var(--panel-background-fill); padding: 10px; border-radius: 8px; margin-bottom: 10px; color: var(--body-text-color); } .solution-box { background: var(--panel-background-fill); padding: 10px; border-radius: 8px; margin-bottom: 10px; color: var(--body-text-color); } .eval-box { display: flex; gap: 12px; margin-bottom: 10px; } .badge { padding: 6px 12px; border-radius: 8px; font-weight: bold; font-size: 0.9em; display: inline-block; } .badge-blue { background: #e3f2fd; color: #1565c0; } .badge-green { background: #e8f5e9; color: #2e7d32; } .badge-red { background: #ffebee; color: #c62828; } .badge span { color: black; /* text label always black */ } .llm-response { background: var(--panel-background-fill); padding: 14px; border-radius: 8px; border: 1px solid var(--border-color-primary); margin-top: 5px; } .compare-btn { background: linear-gradient(90deg, #6a11cb, #2575fc) !important; color: white !important; font-weight: bold !important; border-radius: 8px !important; padding: 10px 14px !important; border: none !important; box-shadow: 0 2px 6px rgba(0,0,0,0.15) !important; transition: transform 0.1s ease-in-out; } .compare-btn:hover { transform: scale(1.05); } .dropdown-box { border: 1px solid var(--border-color-primary); border-radius: 10px; padding: 12px; margin-bottom: 16px; background: var(--panel-background-fill); } """) as demo: gr.Markdown( """ # 📈 Engchain Template Playground Select a branch, domain, file, and template to generate 10 unique Q&A examples. Compare your solutions against a live LLM and see similarity + correctness checks. """ ) with gr.Group(elem_classes="dropdown-box"): with gr.Row(): branch_dropdown = gr.Dropdown( label="1. Select Branch", choices=[(format_name(b), b) for b in sorted(list(ALL_TEMPLATES.keys()))], ) domain_dropdown = gr.Dropdown(label="2. Select Engineering Domain", interactive=False) file_dropdown = gr.Dropdown(label="3. Select Specific Area / File", interactive=False) template_dropdown = gr.Dropdown(label="4. Select Specific Tool / Template", interactive=False) generate_button = gr.Button("Generate 10 Examples", variant="primary") # Pre-create a slot for template heading template_heading = gr.Markdown("", visible=False, elem_classes="template-heading") # Pre-create 10 example slots example_blocks = [] for i in range(10): with gr.Group(visible=False, elem_classes="example-card") as grp: q_md = gr.Markdown(elem_classes="question-box") s_md = gr.Markdown(elem_classes="solution-box") btn = gr.Button("⚖️ See an LLM's Take on this Question", elem_classes="compare-btn") with gr.Column(visible=False) as llm_group: eval_md = gr.HTML(elem_classes="eval-box") llm_response_md = gr.Markdown(elem_classes="llm-response") example_blocks.append((grp, q_md, s_md, btn, llm_group, eval_md, llm_response_md)) async def reveal_llm(q, s, llm_group=llm_group, eval_md=eval_md, llm_response_md=llm_response_md): await asyncio.sleep(0) yield gr.update(visible=True), gr.update(value=""), gr.update(value="⏳ Fetching LLM response...") response = await asyncio.to_thread(call_llm, q) sim = compute_similarity(s, response) match_flag = validate_answer(s, response) eval_html = ( f"
Textual Similarity: {sim}%
" f"
" f"Final Answer Validation: {'✅ Yes' if match_flag else '❌ No'}
" ) yield gr.update(visible=True), gr.update(value=eval_html), gr.update(value=response) btn.click(reveal_llm, inputs=[q_md, s_md], outputs=[llm_group, eval_md, llm_response_md]) # Dropdown update logic def update_domain_dropdown(branch): if not branch: return gr.update(choices=[], value=None, interactive=False), \ gr.update(choices=[], value=None, interactive=False), \ gr.update(choices=[], value=None, interactive=False) domains = sorted(list(ALL_TEMPLATES.get(branch, {}).keys())) formatted_domains = [(format_name(d), d) for d in domains] return gr.update(choices=formatted_domains, value=None, interactive=True), \ gr.update(choices=[], value=None, interactive=False), \ gr.update(choices=[], value=None, interactive=False) def update_file_dropdown(branch, domain): if not branch or not domain: return ( gr.update(choices=[], value=None, interactive=False), gr.update(choices=[], value=None, interactive=False), ) # get all files for this branch+domain files_dict = ALL_TEMPLATES.get(branch, {}).get(domain, {}) files = sorted(list(files_dict.keys())) # Use only the last part of the path as label formatted_files = [(format_name(os.path.basename(f)), f) for f in files] return ( gr.update(choices=formatted_files, value=None, interactive=True), gr.update(choices=[], value=None, interactive=False), ) def update_template_dropdown(branch, domain, filename): if not branch or not domain or not filename: return gr.update(choices=[], value=None, interactive=False) templates = sorted(ALL_TEMPLATES.get(branch, {}).get(domain, {}).get(filename, [])) formatted_templates = [(format_name(t), t) for t in templates] return gr.update(choices=formatted_templates, value=None, interactive=True) branch_dropdown.change(update_domain_dropdown, branch_dropdown, [domain_dropdown, file_dropdown, template_dropdown]) domain_dropdown.change(update_file_dropdown, [branch_dropdown, domain_dropdown], [file_dropdown, template_dropdown]) file_dropdown.change(update_template_dropdown, [branch_dropdown, domain_dropdown, file_dropdown], template_dropdown) # Populate example slots def render_examples(branch, domain, filename, template_name): if not branch or not domain or not filename or not template_name: heading_text = "
⚠️ Please select a branch, domain, file, and template/tool before generating examples.
" template_heading_update = gr.update(value=heading_text, visible=True) updates = [] for grp, q_md, s_md, btn, llm_group, eval_md, llm_response_md in example_blocks: updates.extend([ gr.update(visible=False), gr.update(value=""), gr.update(value=""), gr.update(visible=False), gr.update(visible=False), gr.update(value=""), gr.update(value=""), ]) return [template_heading_update] + updates examples = generate_examples(branch, domain, filename, template_name) heading_text = f"
Generated Examples for Template: {format_name(template_name)}
" template_heading_update = gr.update(value=heading_text, visible=True) updates = [] for i, (grp, q_md, s_md, btn, llm_group, eval_md, llm_response_md) in enumerate(example_blocks): if i < len(examples): ex = examples[i] updates.extend([ gr.update(visible=True), gr.update(value=f"**❓ Question:** {ex['question']}"), gr.update(value=f"**✅ Solution:** {ex['solution']}"), gr.update(visible=True), gr.update(visible=False), gr.update(value=""), gr.update(value=""), ]) else: updates.extend([ gr.update(visible=False), gr.update(value=""), gr.update(value=""), gr.update(visible=False), gr.update(visible=False), gr.update(value=""), gr.update(value=""), ]) return [template_heading_update] + updates generate_button.click( render_examples, [branch_dropdown, domain_dropdown, file_dropdown, template_dropdown], [template_heading] + sum(([grp, q_md, s_md, btn, llm_group, eval_md, llm_response_md] for (grp, q_md, s_md, btn, llm_group, eval_md, llm_response_md) in example_blocks), []) ) if __name__ == "__main__": print("Launching Gradio app...") demo.launch()