Spaces:
Runtime error
Runtime error
File size: 14,678 Bytes
483d121 493960a 483d121 493960a 483d121 a5b2e19 483d121 a5b2e19 483d121 a5b2e19 483d121 a5b2e19 483d121 a5b2e19 483d121 a5b2e19 483d121 a5b2e19 483d121 a5b2e19 483d121 a5b2e19 483d121 a5b2e19 483d121 | 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 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 | import os
import gradio as gr
import psycopg2
from psycopg2.extras import RealDictCursor
from dotenv import load_dotenv
from langtrace_python_sdk.utils.with_root_span import with_langtrace_root_span
import openai
from contextlib import contextmanager
from langtrace_python_sdk import langtrace
load_dotenv() # Load environment variables
langtrace.init(api_key = os.getenv('LANGTRACE_API_KEY'))
GPT_4O_MINI = "gpt-4o-mini"
GPT_4 = "chatgpt-4o-latest"
O1_MINI = "o1-mini"
# Global cache for prompts
cached_prompts = {}
@contextmanager
def openai_session():
"""Context manager to properly handle OpenAI API sessions"""
try:
# Initialize client
client = openai.OpenAI()
yield client
finally:
# Clean up client resources
if hasattr(client, 'close'):
client.close()
@with_langtrace_root_span()
def call_model(prompt, model):
print(f"calling {model} with prompt: {prompt[:100]}")
with openai_session() as client:
try:
# Call API
response = client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": prompt}]
)
# Extract response text
result = response.choices[0].message.content
return result
except Exception as e:
return f"Error generating output: {str(e)}"
def get_db_connection():
"""Establishes and returns a new database connection."""
db_params = {
'dbname': os.getenv('DB_NAME'),
'user': os.getenv('DB_USER'),
'password': os.getenv('DB_PASSWORD'),
'host': os.getenv('DB_HOST'),
'port': os.getenv('DB_PORT')
}
conn = psycopg2.connect(**db_params)
return conn
def load_prompts():
"""Fetches prompts from the DB and caches them as a dict mapping prompt name to a dict with body and id."""
global cached_prompts
conn = get_db_connection()
cursor = conn.cursor(cursor_factory=RealDictCursor)
cursor.execute("""
SELECT code_review_prompt_name, code_review_prompt_body, code_review_prompt_id
FROM code_review_prompt
ORDER BY code_review_prompt_name;
""")
rows = cursor.fetchall()
# Cache format: { prompt_name: {"body": prompt_body, "id": prompt_id} }
cached_prompts = { row["code_review_prompt_name"]: {"body": row["code_review_prompt_body"], "id": row["code_review_prompt_id"]} for row in rows }
cursor.close()
conn.close()
return cached_prompts
# Initially load prompts
load_prompts()
def update_prompt_text(selected_prompt):
"""Uses the global cache to return the prompt body for the selected prompt."""
return cached_prompts.get(selected_prompt, {}).get("body", "")
def build_final_prompt(custom_prompt, input_code):
"""
Builds the final prompt for code review.
"""
return (
f"Please review the following code:\n\n"
f"{custom_prompt}\n\n"
f"<CODE>\n"
f"{input_code}\n"
)
def store_submission(prompt_name, custom_prompt, input_code, review_output):
"""
Stores the submission in the database.
"""
prompt_data = cached_prompts.get(prompt_name)
prompt_id = prompt_data["id"] if prompt_data else None
conn = get_db_connection()
cursor = conn.cursor()
cursor.execute("""
INSERT INTO code_review_submission (code_review_prompt_id, custom_prompt, input_code, ai_review)
VALUES (%s, %s, %s, %s);
""", (prompt_id, custom_prompt, input_code, review_output))
conn.commit()
cursor.close()
conn.close()
def generate_ai_review(prompt_name, custom_prompt, input_code, model):
"""
Generates an AI review by calling the API, then stores the submission.
Uses prompt_name to look up the prompt id.
"""
final_prompt = build_final_prompt(custom_prompt, input_code)
review_output = call_model(final_prompt, model)
store_submission(prompt_name, custom_prompt, input_code, review_output)
return review_output
def call_four(prompt_name, custom_prompt, input_code):
return generate_ai_review(prompt_name, custom_prompt, input_code, GPT_4)
def call_o1(prompt_name, custom_prompt, input_code):
return generate_ai_review(prompt_name, custom_prompt, input_code, O1_MINI)
def call_four_mini(prompt_name, custom_prompt, input_code):
return generate_ai_review(prompt_name, custom_prompt, input_code, GPT_4O_MINI)
def add_new_prompt(prompt_name, prompt_body):
"""Inserts a new prompt into the database, reloads the cache, and returns updated dropdown choices."""
if not prompt_name.strip() or not prompt_body.strip():
return "Error: Prompt Name and Body cannot be empty!", None, None
conn = None
try:
conn = get_db_connection()
cursor = conn.cursor(cursor_factory=RealDictCursor)
cursor.execute("""
INSERT INTO code_review_prompt (code_review_prompt_name, code_review_prompt_body)
VALUES (%s, %s)
ON CONFLICT (code_review_prompt_name) DO NOTHING
RETURNING code_review_prompt_id;
""", (prompt_name.strip(), prompt_body.strip()))
inserted = cursor.fetchone()
if inserted:
conn.commit()
message = f"Prompt '{prompt_name}' added successfully!"
else:
message = f"Prompt '{prompt_name}' already exists!"
cursor.close()
conn.close()
# Reload the prompt cache after insertion
load_prompts()
new_choices = list(cached_prompts.keys())
new_dropdown = gr.Dropdown(choices=new_choices, label="Select Review Type", value=new_choices[0] if new_choices else None)
return message, new_dropdown, ""
except psycopg2.IntegrityError:
conn.rollback()
return "Prompt already exists!", None, ""
except Exception as e:
if conn:
conn.rollback()
return f"Error: {str(e)}", None, ""
finally:
if conn:
conn.close()
def reload_prompts():
"""Reloads the prompt cache and returns a new Dropdown with updated choices."""
load_prompts()
new_choices = list(cached_prompts.keys())
new_dropdown = gr.Dropdown(choices=new_choices, label="Select Review Type", value=new_choices[0] if new_choices else None)
return new_dropdown
# ---------------------- New Code for Loading Previous Submissions ---------------------- #
def select_submission_by_id(selected_id, submissions):
"""
Given a selected submission_id (as string) and the list of submissions,
finds the matching submission and returns its details.
"""
index = next(
(i for i, s in enumerate(submissions) if str(s["code_review_submission_id"]) == selected_id),
0
)
details, code, review, index = show_submission(index, submissions)
return index, details, code, review
def load_submissions_from_db():
"""Fetch all submissions ordered by their id in ascending order."""
conn = get_db_connection()
cursor = conn.cursor(cursor_factory=RealDictCursor)
cursor.execute("""
SELECT code_review_submission_id, code_review_prompt_id, custom_prompt, input_code, ai_review
FROM code_review_submission
ORDER BY created_at DESC; """)
submissions = cursor.fetchall()
cursor.close()
conn.close()
return submissions
def show_submission(index, submissions):
"""Returns formatted outputs for the submission at the given index:
- Submission details (Markdown)
- Input code (for gr.Code)
- AI review output (Markdown)
"""
if not submissions:
return "No submissions available", "", "No submissions available", index
# Clamp index within bounds
index = max(0, min(index, len(submissions) - 1))
submission = submissions[index]
# Left panel Markdown for submission details
submission_details = (
f"**Submission ID:** {submission['code_review_submission_id']}\n\n"
f"**Prompt ID:** {submission['code_review_prompt_id']}\n\n"
f"**Custom Prompt:**\n{submission['custom_prompt']}\n\n"
)
# Input code for gr.Code
input_code = submission['input_code']
# Right panel Markdown for AI review output
ai_review_output = f"**AI Review Output:**\n{submission['ai_review']}\n"
return submission_details, input_code, ai_review_output, index
# --- Updated load_submissions function ---
def load_submissions():
"""Loads submissions from the database, resets the index,
and returns a Dropdown update for submission choices."""
submissions = load_submissions_from_db()
index = 0
details, code, review, index = show_submission(index, submissions)
submission_choices = [str(s["code_review_submission_id"]) for s in submissions]
default_choice = submission_choices[0] if submission_choices else None
dropdown_update = gr.Dropdown(choices=submission_choices, value=default_choice)
return submissions, index, details, code, review, dropdown_update
def next_submission(current_index, submissions):
"""Increment the index and display the next submission."""
if submissions and current_index < len(submissions) - 1:
current_index += 1
details, code, review, current_index = show_submission(current_index, submissions)
return current_index, details, code, review
def previous_submission(current_index, submissions):
"""Decrement the index and display the previous submission."""
if submissions and current_index > 0:
current_index -= 1
details, code, review, current_index = show_submission(current_index, submissions)
return current_index, details, code, review
# ----------------------------------------------------------------------------------------- #
# Gradio UI
with gr.Blocks() as demo:
gr.Markdown("# Code Review Assistant")
with gr.Tab("Code Review"):
with gr.Row():
with gr.Column(scale=1):
prompt_dropdown = gr.Dropdown(
choices=list(cached_prompts.keys()),
label="Select Review Type",
value=list(cached_prompts.keys())[0] if cached_prompts else None
)
with gr.Accordion("Selected Prompt", open=False):
prompt_textbox = gr.Textbox(label="", lines=15, interactive=True)
with gr.Row():
generate_4o_btn = gr.Button("Generate Code Review 4o")
generate_4omini_btn = gr.Button("Generate Code Review 4o-mini")
generate_o1_btn = gr.Button("Generate Code Review o1-mini")
with gr.Row():
input_code = gr.Code(language="python", label="Input Code", lines=15, interactive=True)
output_review = gr.Markdown(label="AI Review Output", container=True, show_copy_button=True)
with gr.Tab("Manage Prompts"):
with gr.Row():
new_prompt_name = gr.Textbox(label="New Prompt Name", placeholder="Enter a prompt name")
new_prompt_body = gr.Textbox(label="New Prompt Body", lines=3, placeholder="Enter the prompt details")
add_prompt_btn = gr.Button("Add Prompt")
reload_prompt_btn = gr.Button("Reload Prompts")
prompt_status = gr.Textbox(label="Status", interactive=False)
with gr.Tab("Submissions"):
with gr.Row():
load_submissions_btn = gr.Button("Load Submissions")
# Hidden states to store submissions and the current index
submissions_state = gr.State([])
submission_index_state = gr.State(0)
# Add a new dropdown to select submission by ID
submission_dropdown = gr.Dropdown(label="Select Submission by ID", choices=[], value=None)
with gr.Row():
back_btn = gr.Button("Back")
next_btn = gr.Button("Next")
with gr.Row():
with gr.Column():
with gr.Accordion("Prompt Details", open=False):
submission_details_md = gr.Markdown(label="Submission Details")
input_code_component = gr.Code(label="Input Code", language="python")
with gr.Column():
ai_review_md = gr.Markdown(label="AI Review Output", container=True, show_copy_button=True)
# Load submissions from DB, initialize state, and update dropdown choices
load_submissions_btn.click(
fn=load_submissions,
inputs=[],
outputs=[submissions_state, submission_index_state, submission_details_md, input_code_component, ai_review_md, submission_dropdown]
)
# When a submission is selected from the dropdown, update the submission display
submission_dropdown.change(
fn=select_submission_by_id,
inputs=[submission_dropdown, submissions_state],
outputs=[submission_index_state, submission_details_md, input_code_component, ai_review_md]
)
# Go to previous submission
back_btn.click(
fn=previous_submission,
inputs=[submission_index_state, submissions_state],
outputs=[submission_index_state, submission_details_md, input_code_component, ai_review_md]
)
# Go to next submission
next_btn.click(
fn=next_submission,
inputs=[submission_index_state, submissions_state],
outputs=[submission_index_state, submission_details_md, input_code_component, ai_review_md]
)
# When dropdown changes, update the prompt text
prompt_dropdown.change(
fn=update_prompt_text,
inputs=[prompt_dropdown],
outputs=[prompt_textbox]
)
# On code review generation, pass both the dropdown (prompt name) and the editable prompt text
generate_4o_btn.click(
fn=call_four,
inputs=[prompt_dropdown, prompt_textbox, input_code],
outputs=[output_review]
)
generate_4omini_btn.click(
fn=call_four_mini,
inputs=[prompt_dropdown, prompt_textbox, input_code],
outputs=[output_review]
)
generate_o1_btn.click(
fn=call_o1,
inputs=[prompt_dropdown, prompt_textbox, input_code],
outputs=[output_review]
)
# On adding a new prompt, update status, replace dropdown with a new one, and clear new prompt body textbox.
add_prompt_btn.click(
fn=add_new_prompt,
inputs=[new_prompt_name, new_prompt_body],
outputs=[prompt_status, prompt_dropdown, new_prompt_body]
)
# Reload prompts when the reload button is clicked.
reload_prompt_btn.click(
fn=reload_prompts,
inputs=[],
outputs=[prompt_dropdown]
)
demo.launch()
|