Engchain / app.py
usmansafdarktk
fix(UI): improve dropdowns and update UI
ff9e41b
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"<div class='badge badge-blue'><span>Textual Similarity:</span> {sim}%</div>"
f"<div class='badge {'badge-green' if match_flag else 'badge-red'}'>"
f"<span>Final Answer Validation:</span> {'✅ Yes' if match_flag else '❌ No'}</div>"
)
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 = "<div style='margin-top:24px; font-size: 20px; color: red;'>⚠️ Please select a branch, domain, file, and template/tool before generating examples.</div>"
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"<div style='margin-top:24px; font-size: 24px;'>Generated Examples for Template: <b>{format_name(template_name)}</b></div>"
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()