|
|
import os |
|
|
import gradio as gr |
|
|
from openai import OpenAI |
|
|
import subprocess |
|
|
import tempfile |
|
|
|
|
|
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) |
|
|
|
|
|
|
|
|
def analyze_code(language, code): |
|
|
error_output = "" |
|
|
|
|
|
if language.lower() == "python": |
|
|
with tempfile.NamedTemporaryFile(delete=False, suffix=".py") as tmp: |
|
|
tmp.write(code.encode("utf-8")) |
|
|
tmp.flush() |
|
|
try: |
|
|
subprocess.run( |
|
|
["python3", tmp.name], |
|
|
check=True, |
|
|
capture_output=True, |
|
|
text=True, |
|
|
timeout=5, |
|
|
) |
|
|
except subprocess.CalledProcessError as e: |
|
|
error_output = e.stderr |
|
|
except Exception as e: |
|
|
error_output = str(e) |
|
|
else: |
|
|
error_output = "Automatic execution only supported for Python. Please paste your error manually." |
|
|
|
|
|
if not error_output.strip(): |
|
|
error_output = "β
No runtime error detected. Let's review for logic or syntax improvements." |
|
|
|
|
|
return help_with_code(language, code, error_output) |
|
|
|
|
|
|
|
|
def help_with_code(language, code, error): |
|
|
prompt = f""" |
|
|
You are a skilled coding instructor identifying skill gaps in students learning {language}. |
|
|
--- CODE START --- |
|
|
{code} |
|
|
--- CODE END --- |
|
|
--- ERROR --- |
|
|
{error} |
|
|
--- END ERROR --- |
|
|
Your task: |
|
|
1. Identify my coding skill gaps (syntax, logic, structure, or language fundamentals). |
|
|
2. Explain clearly what went wrong and why. |
|
|
3. Suggest one or two short, focused practice exercises to improve that specific skill. |
|
|
4. Do NOT rewrite or fix the code. |
|
|
""" |
|
|
|
|
|
try: |
|
|
response = client.chat.completions.create( |
|
|
model="gpt-4o-mini", |
|
|
messages=[{"role": "user", "content": prompt}], |
|
|
temperature=0.4, |
|
|
) |
|
|
return response.choices[0].message.content.strip() |
|
|
|
|
|
except Exception as e: |
|
|
err_msg = str(e) |
|
|
|
|
|
|
|
|
if "billing_not_active" in err_msg or "Error code: 429" in err_msg: |
|
|
return ( |
|
|
"β οΈ Please contact an RC staff member β the billing is currently not active." |
|
|
) |
|
|
|
|
|
|
|
|
return "β οΈ An unexpected error occurred. Please try again later or verify your API key." |
|
|
|
|
|
|
|
|
|
|
|
with gr.Blocks( |
|
|
theme="soft", |
|
|
css=""" |
|
|
/* === Apply theme colors immediately === */ |
|
|
body, .gradio-container, .dark, [data-theme="dark"] { |
|
|
background-color: var(--body-background-fill) !important; |
|
|
color: var(--body-text-color) !important; |
|
|
transition: none !important; |
|
|
} |
|
|
|
|
|
/* === Base Theme Variables (Light Mode) === */ |
|
|
:root { |
|
|
--body-background-fill: #ffffff; |
|
|
--body-text-color: #1a1a1a; |
|
|
--codebox-background: #f8f8f8; |
|
|
--codebox-border: #EDEBEB; |
|
|
--scrollbar-thumb: #c1c1c1; |
|
|
--scrollbar-track: #f8f8f8; |
|
|
} |
|
|
|
|
|
/* π Dark Mode Theme */ |
|
|
:root .dark, [data-theme="dark"] { |
|
|
--body-background-fill: #1e1e1f !important; |
|
|
--body-text-color: #e5e5e5 !important; |
|
|
--codebox-background: #2a2a2b !important; |
|
|
--codebox-border: #3a3a3b !important; |
|
|
--scrollbar-thumb: #555 !important; |
|
|
--scrollbar-track: #2a2a2b !important; |
|
|
} |
|
|
|
|
|
/* π§± Code boxes, dropdowns, textareas unified */ |
|
|
#code-box, |
|
|
select, |
|
|
textarea, |
|
|
pre, |
|
|
code { |
|
|
background-color: var(--codebox-background) !important; |
|
|
border: 1px solid var(--codebox-border) !important; |
|
|
border-radius: 6px !important; |
|
|
color: var(--body-text-color) !important; |
|
|
transition: none !important; |
|
|
} |
|
|
|
|
|
/* β¨ Consistent scrollbar theme */ |
|
|
#code-box::-webkit-scrollbar, |
|
|
textarea::-webkit-scrollbar, |
|
|
pre::-webkit-scrollbar { |
|
|
width: 8px; |
|
|
height: 8px; |
|
|
} |
|
|
#code-box::-webkit-scrollbar-thumb, |
|
|
textarea::-webkit-scrollbar-thumb, |
|
|
pre::-webkit-scrollbar-thumb { |
|
|
background-color: var(--scrollbar-thumb); |
|
|
border-radius: 10px; |
|
|
} |
|
|
#code-box::-webkit-scrollbar-track, |
|
|
textarea::-webkit-scrollbar-track, |
|
|
pre::-webkit-scrollbar-track { |
|
|
background-color: var(--scrollbar-track); |
|
|
} |
|
|
|
|
|
/* π― Submit button */ |
|
|
#submit-btn { |
|
|
background-color: #e40014 !important; |
|
|
color: white !important; |
|
|
border: none !important; |
|
|
border-radius: 6px !important; |
|
|
transition: background-color 0.2s ease-in-out; |
|
|
margin-top: 6px !important; |
|
|
width: 100%; |
|
|
} |
|
|
#submit-btn:hover { |
|
|
background-color: #c00010 !important; |
|
|
} |
|
|
|
|
|
/* π§© Compact layout */ |
|
|
.gr-block, .gr-form, .gr-column, .gr-row { |
|
|
gap: 4px !important; |
|
|
padding: 0 !important; |
|
|
margin: 0 !important; |
|
|
} |
|
|
.gr-markdown { |
|
|
margin: 0 !important; |
|
|
padding: 2px !important; |
|
|
line-height: 1.4 !important; |
|
|
} |
|
|
|
|
|
/* β
Feedback area spacing */ |
|
|
.gr-markdown p { |
|
|
margin-top: 0 !important; |
|
|
margin-bottom: 4px !important; |
|
|
} |
|
|
|
|
|
/* Prevent reflow on feedback render */ |
|
|
.gr-column > *:not(:last-child) { |
|
|
margin-bottom: 4px !important; |
|
|
} |
|
|
""" |
|
|
) as demo: |
|
|
with gr.Row(equal_height=True): |
|
|
with gr.Column(scale=2): |
|
|
|
|
|
language = gr.Dropdown( |
|
|
["JavaScript", "HTML", "CSS", "Python"], |
|
|
value="Python", |
|
|
show_label=True, |
|
|
label="Language", |
|
|
) |
|
|
|
|
|
code_input = gr.Code( |
|
|
language="python", |
|
|
lines=22, |
|
|
show_label=True, |
|
|
label="Your Code", |
|
|
elem_id="code-box", |
|
|
) |
|
|
|
|
|
analyze_button = gr.Button("Submit", variant="secondary", elem_id="submit-btn") |
|
|
|
|
|
with gr.Column(scale=1): |
|
|
output = gr.Markdown("*Feedback will show here!*") |
|
|
|
|
|
analyze_button.click(analyze_code, inputs=[language, code_input], outputs=output) |
|
|
|
|
|
demo.launch() |
|
|
|