Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| # --------------------------------------------------------------------------- | |
| # MODULE 1 — UI Module | |
| # --------------------------------------------------------------------------- | |
| CUSTOM_CSS = """ | |
| @import url('https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&family=DM+Sans:ital,wght@0,300;0,400;0,500;0,600;1,400&display=swap'); | |
| *, *::before, *::after { box-sizing: border-box; } | |
| body, .gradio-container { | |
| font-family: 'DM Sans', sans-serif !important; | |
| background: #0D0F14 !important; | |
| color: #E8EAF0 !important; | |
| } | |
| .gradio-container { | |
| max-width: 1140px !important; | |
| margin: 0 auto !important; | |
| padding: 32px 24px !important; | |
| } | |
| .eval-header { | |
| display: flex; | |
| align-items: center; | |
| gap: 16px; | |
| padding: 0 0 28px; | |
| border-bottom: 1px solid #2E3140; | |
| margin-bottom: 28px; | |
| } | |
| .eval-header .logo { | |
| width: 44px; height: 44px; | |
| border-radius: 10px; | |
| background: linear-gradient(135deg, #534AB7 0%, #1D9E75 100%); | |
| display: flex; align-items: center; justify-content: center; | |
| flex-shrink: 0; | |
| font-size: 22px; line-height: 1; | |
| } | |
| .eval-header h1 { | |
| font-size: 20px !important; | |
| font-weight: 600 !important; | |
| letter-spacing: -0.3px !important; | |
| color: #E8EAF0 !important; | |
| margin: 0 !important; | |
| } | |
| .eval-header p { | |
| font-size: 13px !important; | |
| color: #9DA0B0 !important; | |
| margin: 2px 0 0 !important; | |
| } | |
| .eval-header .model-badge { | |
| margin-left: auto; | |
| font-family: 'Space Mono', monospace; | |
| font-size: 10px; | |
| background: #1E2028; | |
| border: 1px solid #3A3E52; | |
| color: #6A6E80; | |
| padding: 4px 10px; | |
| border-radius: 4px; | |
| letter-spacing: 1.5px; | |
| white-space: nowrap; | |
| } | |
| .gradio-textbox textarea, | |
| .gradio-code textarea, | |
| .gradio-textbox input { | |
| background: #161820 !important; | |
| border: 1px solid #2E3140 !important; | |
| border-radius: 10px !important; | |
| color: #E8EAF0 !important; | |
| font-family: 'DM Sans', sans-serif !important; | |
| font-size: 13.5px !important; | |
| line-height: 1.7 !important; | |
| padding: 14px 16px !important; | |
| transition: border-color 0.15s !important; | |
| resize: vertical !important; | |
| } | |
| .gradio-textbox textarea:focus, | |
| .gradio-code textarea:focus { | |
| border-color: #534AB7 !important; | |
| outline: none !important; | |
| box-shadow: 0 0 0 3px rgba(83, 74, 183, 0.15) !important; | |
| } | |
| .gradio-textbox textarea::placeholder { | |
| color: #4A4E60 !important; | |
| } | |
| #code-input { | |
| min-height: 300px; | |
| } | |
| #code-input .cm-editor { | |
| min-height: 300px; | |
| } | |
| .gradio-textbox label span, | |
| .gradio-code label span { | |
| font-family: 'DM Sans', sans-serif !important; | |
| font-size: 13px !important; | |
| font-weight: 700 !important; | |
| color: #E8EAF0 !important; | |
| text-transform: uppercase !important; | |
| letter-spacing: 0.8px !important; | |
| } | |
| #eval-btn { | |
| background: #534AB7 !important; | |
| border: none !important; | |
| color: #fff !important; | |
| font-family: 'DM Sans', sans-serif !important; | |
| font-size: 14px !important; | |
| font-weight: 500 !important; | |
| padding: 12px 32px !important; | |
| border-radius: 8px !important; | |
| cursor: pointer !important; | |
| transition: background 0.15s, transform 0.1s !important; | |
| letter-spacing: -0.1px !important; | |
| } | |
| #eval-btn:hover { | |
| background: #7F77DD !important; | |
| transform: translateY(-1px) !important; | |
| } | |
| #eval-btn:active { | |
| transform: translateY(0) !important; | |
| } | |
| #clear-btn { | |
| background: transparent !important; | |
| border: 1px solid #3A3E52 !important; | |
| color: #9DA0B0 !important; | |
| font-family: 'DM Sans', sans-serif !important; | |
| font-size: 13px !important; | |
| padding: 12px 20px !important; | |
| border-radius: 8px !important; | |
| cursor: pointer !important; | |
| transition: border-color 0.15s, color 0.15s !important; | |
| } | |
| #clear-btn:hover { | |
| border-color: #7F77DD !important; | |
| color: #E8EAF0 !important; | |
| } | |
| .results-heading { | |
| font-size: 11px !important; | |
| font-weight: 500 !important; | |
| color: #6A6E80 !important; | |
| text-transform: uppercase !important; | |
| letter-spacing: 1px !important; | |
| padding: 0 0 16px !important; | |
| border-bottom: 1px solid #2E3140 !important; | |
| margin-bottom: 20px !important; | |
| } | |
| #verdict-out textarea { | |
| background: #161820 !important; | |
| border: 1px solid #2E3140 !important; | |
| border-radius: 10px !important; | |
| font-family: 'Space Mono', monospace !important; | |
| font-size: 26px !important; | |
| font-weight: 700 !important; | |
| text-align: center !important; | |
| padding: 20px !important; | |
| color: #E8EAF0 !important; | |
| cursor: default !important; | |
| } | |
| #accuracy-out textarea { | |
| background: #161820 !important; | |
| border: 1px solid #2E3140 !important; | |
| border-radius: 10px !important; | |
| font-family: 'Space Mono', monospace !important; | |
| font-size: 26px !important; | |
| font-weight: 700 !important; | |
| text-align: center !important; | |
| padding: 20px !important; | |
| color: #E8EAF0 !important; | |
| cursor: default !important; | |
| } | |
| #summary-out textarea { | |
| background: #161820 !important; | |
| border: 1px solid #2E3140 !important; | |
| border-radius: 10px !important; | |
| font-family: 'DM Sans', sans-serif !important; | |
| font-size: 13.5px !important; | |
| line-height: 1.7 !important; | |
| padding: 16px !important; | |
| color: #C0C3D0 !important; | |
| cursor: default !important; | |
| } | |
| #issues-out textarea { | |
| background: #161820 !important; | |
| border: 1px solid #2E3140 !important; | |
| border-radius: 10px !important; | |
| font-family: 'DM Sans', sans-serif !important; | |
| font-size: 13.5px !important; | |
| line-height: 1.8 !important; | |
| padding: 16px !important; | |
| color: #C0C3D0 !important; | |
| cursor: default !important; | |
| min-height: 120px !important; | |
| } | |
| #error-out textarea { | |
| background: #1A0E0E !important; | |
| border: 1px solid #5a2020 !important; | |
| border-radius: 10px !important; | |
| font-family: 'DM Sans', sans-serif !important; | |
| font-size: 13.5px !important; | |
| padding: 14px 16px !important; | |
| color: #F0997B !important; | |
| cursor: default !important; | |
| } | |
| .divider { | |
| height: 1px; | |
| background: #2E3140; | |
| margin: 20px 0; | |
| } | |
| footer { display: none !important; } | |
| .gradio-container > .wrap > footer { display: none !important; } | |
| ::-webkit-scrollbar { width: 6px; height: 6px; } | |
| ::-webkit-scrollbar-track { background: transparent; } | |
| ::-webkit-scrollbar-thumb { background: #3A3E52; border-radius: 3px; } | |
| ::-webkit-scrollbar-thumb:hover { background: #534AB7; } | |
| """ | |
| HEADER_HTML = """ | |
| <div class="eval-header"> | |
| <div class="logo">🔍</div> | |
| <div> | |
| <h1>Python Code Evaluator</h1> | |
| </div> | |
| <div class="model-badge">Gemini 2.5 Flash</div> | |
| </div> | |
| """ | |
| RESULTS_HEADING_HTML = """ | |
| <div class="divider"></div> | |
| <div class="results-heading">⬡ Evaluation Results</div> | |
| """ | |
| INPUT_HINT_HTML = """ | |
| <div style="font-size:12px;color:#4A4E60;margin-top:-4px;padding-bottom:4px;"> | |
| Tip — paste your description and code above, then click <strong style="color:#7F77DD">Evaluate</strong>. | |
| </div> | |
| """ | |
| ##----------- | |
| ## Build UI | |
| ##----------- | |
| def build_ui(evaluate_fn): | |
| ##----------- | |
| ## THE _ui_evaluate FUNCTION | |
| ##----------- | |
| def _split_metrics(metrics_str: str): | |
| acc, summary = "", "" | |
| if not metrics_str: | |
| return acc, summary | |
| for line in metrics_str.splitlines(): | |
| if line.startswith("Accuracy:"): | |
| acc = line.replace("Accuracy:", "").strip() | |
| elif line.startswith("Summary:"): | |
| summary = line.replace("Summary:", "").strip() | |
| return acc, summary | |
| def _ui_evaluate(description: str, code: str): | |
| verdict, metrics, issues, error = evaluate_fn(description, code) | |
| accuracy, summary = _split_metrics(metrics) | |
| if "PASS" in verdict.upper(): | |
| verdict_display = "✅ PASS" | |
| elif "FAIL" in verdict.upper(): | |
| verdict_display = "❌ FAIL" | |
| else: | |
| verdict_display = verdict or "" | |
| return verdict_display, accuracy, summary, issues, error | |
| with gr.Blocks(title="Python Code Evaluator") as ui: | |
| gr.HTML(HEADER_HTML) | |
| ##----------- | |
| ## Inputs | |
| ##----------- | |
| with gr.Row(equal_height=True): | |
| description_input = gr.Textbox( | |
| label="Requirements Description", | |
| placeholder=( | |
| "Describe what the Python code is supposed to do…\n\n" | |
| "Example: Write a function that accepts a list of integers " | |
| "and returns the sum of all even numbers. It should handle " | |
| "empty lists by returning 0 and ignore non-integer values." | |
| "\n\n" | |
| "The Python code entered should be in the format:\n" | |
| "def function name (parameter1, parameter2):\n" | |
| "\t# Function body (code to execute)\n" | |
| "\tresult = parameter1 + parameter2\n" | |
| "\treturn result # Optional: sends a value back to the caller" | |
| ), | |
| lines=10, | |
| max_lines=20, | |
| elem_id="desc-input", | |
| ) | |
| code_input = gr.Code( | |
| label="Python Code", | |
| language="python", | |
| lines=10, | |
| max_lines=30, | |
| elem_id="code-input", | |
| ) | |
| gr.HTML(INPUT_HINT_HTML) | |
| ##----------- | |
| ## Buttons | |
| ##----------- | |
| with gr.Row(): | |
| eval_btn = gr.Button("Evaluate", variant="primary", | |
| elem_id="eval-btn", scale=0) | |
| clear_btn = gr.Button("Clear", variant="secondary", | |
| elem_id="clear-btn", scale=0) | |
| gr.HTML(RESULTS_HEADING_HTML) | |
| ##----------- | |
| ## Output | |
| ##----------- | |
| with gr.Row(equal_height=True): | |
| verdict_out = gr.Textbox( | |
| label="Verdict", | |
| interactive=False, | |
| elem_id="verdict-out", | |
| scale=1, | |
| ) | |
| accuracy_out = gr.Textbox( | |
| label="Accuracy", | |
| interactive=False, | |
| elem_id="accuracy-out", | |
| scale=1, | |
| ) | |
| summary_out = gr.Textbox( | |
| label="Summary", | |
| interactive=False, | |
| lines=3, | |
| elem_id="summary-out", | |
| scale=2, | |
| ) | |
| issues_out = gr.Textbox( | |
| label="Issues Detected", | |
| interactive=False, | |
| lines=5, | |
| elem_id="issues-out", | |
| ) | |
| error_out = gr.Textbox( | |
| label="Status / Errors", | |
| interactive=False, | |
| visible=True, | |
| elem_id="error-out", | |
| ) | |
| gr.HTML(""" | |
| <div style="text-align:right;font-size:11px;color:#4A4E60;margin-top:8px;"> | |
| Press <kbd style="background:#1E2028;border:1px solid #3A3E52;border-radius:4px; | |
| padding:2px 6px;font-family:'Space Mono',monospace;font-size:10px;color:#9DA0B0;"> | |
| Ctrl+Enter</kbd> inside any input to evaluate | |
| </div> | |
| """) | |
| outputs = [verdict_out, accuracy_out, summary_out, issues_out, error_out] | |
| eval_btn.click(fn=_ui_evaluate, inputs=[description_input, code_input], outputs=outputs) | |
| def _clear(): | |
| return "", "", "", "", "", "" | |
| clear_btn.click( | |
| fn=_clear, | |
| inputs=[], | |
| outputs=[description_input, code_input, | |
| verdict_out, accuracy_out, summary_out, issues_out], | |
| ) | |
| return ui |