mgbam commited on
Commit
411684b
Β·
verified Β·
1 Parent(s): 4369489

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +42 -48
app.py CHANGED
@@ -10,10 +10,10 @@ import plotly.express as px
10
  import pandas as pd
11
 
12
  # --- Configuration ---
13
- MAX_PROMPT_TOKENS_ESTIMATE = 800000 # Token estimate limit
14
  RESULTS_PAGE_SIZE = 25
15
 
16
- AVAILABLE_ANALYSES = {
17
  "generate_docs": "Generate Missing Docstrings/Comments",
18
  "find_bugs": "Identify Potential Bugs & Anti-patterns",
19
  "check_style": "Check Style Guide Compliance (General)",
@@ -35,13 +35,9 @@ if 'error_message' not in st.session_state:
35
  if 'analysis_requested' not in st.session_state:
36
  st.session_state.analysis_requested = False
37
  if 'selected_model_name' not in st.session_state:
38
- st.session_state.selected_model_name = None # Internal model name
39
  if 'available_models_dict' not in st.session_state:
40
- st.session_state.available_models_dict = {} # Mapping: display -> internal
41
- if 'file_count' not in st.session_state:
42
- st.session_state.file_count = 0
43
- if 'total_chars' not in st.session_state:
44
- st.session_state.total_chars = 0
45
 
46
  # --- Gemini API Setup & Model Discovery ---
47
  model = None # Global variable for the initialized model instance
@@ -100,8 +96,8 @@ def initialize_gemini_model():
100
  def estimate_token_count(text):
101
  """
102
  Estimates the token count.
103
- If a string is provided, calculates based on length.
104
- If an integer is provided (e.g., total character count), uses that directly.
105
  """
106
  if isinstance(text, int):
107
  return text // 3
@@ -160,13 +156,16 @@ def process_zip_file_cached(file_id, file_size, file_content_bytes):
160
  st.error(f"🚨 ZIP Error: {e}")
161
  return None, 0, 0, []
162
  if file_count == 0:
163
- st.warning("No code files found." if not ignored_files else "No code files found; some skipped.")
 
 
 
164
  return code_files, total_chars, file_count, ignored_files
165
 
166
  def construct_analysis_prompt(code_files_dict, requested_analyses):
167
  """
168
- Constructs the prompt for analysis by including code files and JSON structure.
169
- Returns the full prompt and list of included files.
170
  """
171
  prompt_parts = ["Analyze the following codebase...\n\n"]
172
  current_token_estimate = estimate_token_count(prompt_parts[0])
@@ -218,7 +217,7 @@ def construct_analysis_prompt(code_files_dict, requested_analyses):
218
  def call_gemini_api(prompt):
219
  """
220
  Calls the Gemini API using the provided prompt.
221
- Returns parsed JSON insights or an error message.
222
  """
223
  if not prompt:
224
  return None, "Prompt generation failed."
@@ -249,7 +248,7 @@ def call_gemini_api(prompt):
249
  generation_config=genai.types.GenerationConfig(temperature=0.2),
250
  safety_settings=[
251
  {"category": c, "threshold": "BLOCK_MEDIUM_AND_ABOVE"}
252
- for c in ["HARM_CATEGORY_HARASSMENT", "HARM_CATEGORY_HATE_SPEECH",
253
  "HARM_CATEGORY_SEXUALLY_EXPLICIT", "HARM_CATEGORY_DANGEROUS_CONTENT"]
254
  ]
255
  )
@@ -308,7 +307,7 @@ def call_gemini_api(prompt):
308
 
309
  def display_results(results_json, requested_analyses):
310
  """
311
- Displays analysis results with pagination and a downloadable JSON report.
312
  """
313
  st.header("πŸ“Š Analysis Report")
314
  if not isinstance(results_json, dict):
@@ -395,7 +394,7 @@ def display_results(results_json, requested_analyses):
395
  st.set_page_config(page_title="Codebase Audit Assistant", layout="wide")
396
  st.title("πŸ€– Codebase Audit & Documentation Assistant")
397
 
398
- # --- Sidebar Enhancements ---
399
  with st.sidebar:
400
  # Dark Mode Toggle
401
  dark_mode = st.checkbox("Enable Dark Mode", value=False)
@@ -403,13 +402,14 @@ with st.sidebar:
403
  st.markdown(
404
  """
405
  <style>
406
- .reportview-container { background-color: #2E2E2E; color: white; }
407
- .sidebar .sidebar-content { background-color: #1A1A1A; }
 
 
408
  </style>
409
  """,
410
  unsafe_allow_html=True
411
  )
412
-
413
  st.header("βš™οΈ Analysis Controls")
414
  st.session_state.mock_api_call = st.toggle(
415
  "πŸ§ͺ Enable Mock API Mode",
@@ -455,7 +455,7 @@ with st.sidebar:
455
  st.divider()
456
  st.header("πŸ”Ž Select Analyses")
457
  selected_analyses = [
458
- key for key, name in AVAILABLE_ANALYSES.items()
459
  if st.checkbox(name, value=True, key=f"cb_{key}")
460
  ]
461
  st.divider()
@@ -473,7 +473,7 @@ with st.sidebar:
473
  st.divider()
474
  st.warning("⚠️ **Privacy:** Code sent to Google API if Mock Mode is OFF.")
475
 
476
- # Update title based on selected model
477
  if st.session_state.selected_model_name and not st.session_state.mock_api_call:
478
  st.markdown(f"Upload codebase (`.zip`) for analysis via **{st.session_state.selected_model_name}**.")
479
  elif st.session_state.mock_api_call:
@@ -503,13 +503,20 @@ if uploaded_file:
503
  file_id, uploaded_file.size, uploaded_file_bytes
504
  )
505
  if code_files is not None:
506
- # Save these metrics to session state for dashboard use
507
- st.session_state.file_count = file_count
508
- st.session_state.total_chars = total_chars
509
  st.info(f"Found **{file_count}** code files ({total_chars:,} chars). Est. tokens: ~{estimate_token_count(total_chars):,}")
 
 
 
 
 
 
 
 
 
510
  if ignored_files:
511
  with st.expander(f"View {len(ignored_files)} Skipped/Ignored Files"):
512
  st.code("\n".join(ignored_files), language='text')
 
513
  model_ready = bool(st.session_state.selected_model_name) or st.session_state.mock_api_call
514
  analyze_button_disabled = (not selected_analyses or file_count == 0 or not model_ready)
515
  analyze_button_label = "Analyze Codebase"
@@ -518,7 +525,11 @@ if uploaded_file:
518
  elif analyze_button_disabled:
519
  analyze_button_label = "Select Analyses or Upload Valid Code"
520
 
521
- if analysis_button_placeholder.button(analyze_button_label, type="primary", disabled=analyze_button_disabled):
 
 
 
 
522
  st.session_state.analysis_requested = True
523
  st.session_state.analysis_results = None
524
  st.session_state.error_message = None
@@ -530,7 +541,11 @@ if uploaded_file:
530
  st.warning("Please select a Gemini model from the sidebar.")
531
  else:
532
  with results_placeholder:
533
- spinner_model_name = st.session_state.selected_model_name if not st.session_state.mock_api_call else "Mock Mode"
 
 
 
 
534
  spinner_msg = f"πŸš€ Preparing prompt & contacting AI ({spinner_model_name})... Please wait."
535
  with st.spinner(spinner_msg):
536
  analysis_prompt, included_files_in_prompt = construct_analysis_prompt(code_files, selected_analyses)
@@ -544,7 +559,6 @@ if uploaded_file:
544
  st.session_state.error_message = "Failed to generate analysis prompt."
545
  st.rerun()
546
 
547
- # Display analysis results if available
548
  if st.session_state.analysis_requested:
549
  with results_placeholder:
550
  st.divider()
@@ -560,25 +574,5 @@ if st.session_state.analysis_requested:
560
  elif not uploaded_file:
561
  results_placeholder.info("Upload a ZIP file to begin.")
562
 
563
- # --- Audit Dashboard ---
564
- # If analysis results exist, display an interactive dashboard summarizing key metrics.
565
- if st.session_state.analysis_results:
566
- st.subheader("Audit Dashboard")
567
- # Compute metrics from session state and analysis results
568
- metrics = {
569
- "Files Analyzed": st.session_state.file_count,
570
- "Total Tokens": estimate_token_count(st.session_state.total_chars)
571
- }
572
- metrics["Documentation Suggestions"] = len(st.session_state.analysis_results.get("documentation_suggestions", []))
573
- metrics["Potential Bugs"] = len(st.session_state.analysis_results.get("potential_bugs", []))
574
- metrics["Style Issues"] = len(st.session_state.analysis_results.get("style_issues", []))
575
- metrics["Module Summaries"] = len(st.session_state.analysis_results.get("module_summaries", []))
576
- metrics["Refactoring Suggestions"] = len(st.session_state.analysis_results.get("refactoring_suggestions", []))
577
-
578
- # Create a DataFrame and a bar chart using Plotly
579
- df_metrics = pd.DataFrame(list(metrics.items()), columns=["Metric", "Value"])
580
- fig = px.bar(df_metrics, x="Metric", y="Value", title="Audit Summary Metrics")
581
- st.plotly_chart(fig)
582
-
583
  results_placeholder.divider()
584
  results_placeholder.markdown("_Assistant powered by Google Gemini._")
 
10
  import pandas as pd
11
 
12
  # --- Configuration ---
13
+ MAX_PROMPT_TOKENS_ESTIMATE = 800000 # Keep this estimate
14
  RESULTS_PAGE_SIZE = 25
15
 
16
+ AVAILABLE_ANALYSES = { # Keep analyses config
17
  "generate_docs": "Generate Missing Docstrings/Comments",
18
  "find_bugs": "Identify Potential Bugs & Anti-patterns",
19
  "check_style": "Check Style Guide Compliance (General)",
 
35
  if 'analysis_requested' not in st.session_state:
36
  st.session_state.analysis_requested = False
37
  if 'selected_model_name' not in st.session_state:
38
+ st.session_state.selected_model_name = None # Will hold the "models/..." name
39
  if 'available_models_dict' not in st.session_state:
40
+ st.session_state.available_models_dict = {} # Mapping display_name -> name
 
 
 
 
41
 
42
  # --- Gemini API Setup & Model Discovery ---
43
  model = None # Global variable for the initialized model instance
 
96
  def estimate_token_count(text):
97
  """
98
  Estimates the token count.
99
+ If a string is provided, calculates based on its length.
100
+ If an integer (e.g. total char count) is provided, uses that directly.
101
  """
102
  if isinstance(text, int):
103
  return text // 3
 
156
  st.error(f"🚨 ZIP Error: {e}")
157
  return None, 0, 0, []
158
  if file_count == 0:
159
+ if not ignored_files:
160
+ st.warning("No code files found.")
161
+ else:
162
+ st.warning("No code files found; some skipped.")
163
  return code_files, total_chars, file_count, ignored_files
164
 
165
  def construct_analysis_prompt(code_files_dict, requested_analyses):
166
  """
167
+ Constructs the prompt for analysis by including code files and a JSON structure for output.
168
+ Returns the full prompt and a list of included files.
169
  """
170
  prompt_parts = ["Analyze the following codebase...\n\n"]
171
  current_token_estimate = estimate_token_count(prompt_parts[0])
 
217
  def call_gemini_api(prompt):
218
  """
219
  Calls the Gemini API using the provided prompt.
220
+ Returns the parsed JSON insights or an error message.
221
  """
222
  if not prompt:
223
  return None, "Prompt generation failed."
 
248
  generation_config=genai.types.GenerationConfig(temperature=0.2),
249
  safety_settings=[
250
  {"category": c, "threshold": "BLOCK_MEDIUM_AND_ABOVE"}
251
+ for c in ["HARM_CATEGORY_HARASSMENT", "HARM_CATEGORY_HATE_SPEECH",
252
  "HARM_CATEGORY_SEXUALLY_EXPLICIT", "HARM_CATEGORY_DANGEROUS_CONTENT"]
253
  ]
254
  )
 
307
 
308
  def display_results(results_json, requested_analyses):
309
  """
310
+ Displays the analysis results with pagination and allows JSON download.
311
  """
312
  st.header("πŸ“Š Analysis Report")
313
  if not isinstance(results_json, dict):
 
394
  st.set_page_config(page_title="Codebase Audit Assistant", layout="wide")
395
  st.title("πŸ€– Codebase Audit & Documentation Assistant")
396
 
397
+ # --- Sidebar with Enhancements ---
398
  with st.sidebar:
399
  # Dark Mode Toggle
400
  dark_mode = st.checkbox("Enable Dark Mode", value=False)
 
402
  st.markdown(
403
  """
404
  <style>
405
+ .reportview-container, .main {
406
+ background-color: #2E2E2E;
407
+ color: white;
408
+ }
409
  </style>
410
  """,
411
  unsafe_allow_html=True
412
  )
 
413
  st.header("βš™οΈ Analysis Controls")
414
  st.session_state.mock_api_call = st.toggle(
415
  "πŸ§ͺ Enable Mock API Mode",
 
455
  st.divider()
456
  st.header("πŸ”Ž Select Analyses")
457
  selected_analyses = [
458
+ key for key, name in AVAILABLE_ANALYSES.items()
459
  if st.checkbox(name, value=True, key=f"cb_{key}")
460
  ]
461
  st.divider()
 
473
  st.divider()
474
  st.warning("⚠️ **Privacy:** Code sent to Google API if Mock Mode is OFF.")
475
 
476
+ # Update title dynamically based on selected model
477
  if st.session_state.selected_model_name and not st.session_state.mock_api_call:
478
  st.markdown(f"Upload codebase (`.zip`) for analysis via **{st.session_state.selected_model_name}**.")
479
  elif st.session_state.mock_api_call:
 
503
  file_id, uploaded_file.size, uploaded_file_bytes
504
  )
505
  if code_files is not None:
 
 
 
506
  st.info(f"Found **{file_count}** code files ({total_chars:,} chars). Est. tokens: ~{estimate_token_count(total_chars):,}")
507
+ # --- Interactive Metrics Visualization ---
508
+ metrics = {
509
+ "Metric": ["Files Analyzed", "Total Characters", "Token Estimate", "Ignored Files"],
510
+ "Value": [file_count, total_chars, estimate_token_count(total_chars), len(ignored_files)]
511
+ }
512
+ df_metrics = pd.DataFrame(metrics)
513
+ fig = px.bar(df_metrics, x="Metric", y="Value", title="Upload Summary Metrics")
514
+ st.plotly_chart(fig)
515
+ # --- End Metrics Visualization ---
516
  if ignored_files:
517
  with st.expander(f"View {len(ignored_files)} Skipped/Ignored Files"):
518
  st.code("\n".join(ignored_files), language='text')
519
+
520
  model_ready = bool(st.session_state.selected_model_name) or st.session_state.mock_api_call
521
  analyze_button_disabled = (not selected_analyses or file_count == 0 or not model_ready)
522
  analyze_button_label = "Analyze Codebase"
 
525
  elif analyze_button_disabled:
526
  analyze_button_label = "Select Analyses or Upload Valid Code"
527
 
528
+ if analysis_button_placeholder.button(
529
+ analyze_button_label,
530
+ type="primary",
531
+ disabled=analyze_button_disabled
532
+ ):
533
  st.session_state.analysis_requested = True
534
  st.session_state.analysis_results = None
535
  st.session_state.error_message = None
 
541
  st.warning("Please select a Gemini model from the sidebar.")
542
  else:
543
  with results_placeholder:
544
+ spinner_model_name = (
545
+ st.session_state.selected_model_name
546
+ if not st.session_state.mock_api_call
547
+ else "Mock Mode"
548
+ )
549
  spinner_msg = f"πŸš€ Preparing prompt & contacting AI ({spinner_model_name})... Please wait."
550
  with st.spinner(spinner_msg):
551
  analysis_prompt, included_files_in_prompt = construct_analysis_prompt(code_files, selected_analyses)
 
559
  st.session_state.error_message = "Failed to generate analysis prompt."
560
  st.rerun()
561
 
 
562
  if st.session_state.analysis_requested:
563
  with results_placeholder:
564
  st.divider()
 
574
  elif not uploaded_file:
575
  results_placeholder.info("Upload a ZIP file to begin.")
576
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
577
  results_placeholder.divider()
578
  results_placeholder.markdown("_Assistant powered by Google Gemini._")