Ryan commited on
Commit
6528c77
·
1 Parent(s): 1b8fad7
app.py CHANGED
@@ -1,6 +1,7 @@
1
  import gradio as gr
2
  from ui.dataset_input import create_dataset_input, load_example_dataset
3
  from ui.analysis_screen import create_analysis_screen, process_analysis_request
 
4
  import nltk
5
  import os
6
  import json
@@ -95,56 +96,42 @@ def create_app():
95
 
96
  # Analysis Tab
97
  with gr.Tab("Analysis"):
98
- # Use create_analysis_screen to get UI components
99
- analysis_options, analysis_params, run_analysis_btn, analysis_output, bow_top_slider = create_analysis_screen()
100
 
101
  # Define a helper function to extract parameter values and call process_analysis_request
102
  def run_analysis(dataset, selected_analyses, bow_top_value):
103
  # Check if dataset exists
104
  if not dataset or "entries" not in dataset or not dataset["entries"]:
105
- return {}, gr.update(visible=True, value={"error": "No dataset provided. Please create a dataset in the Dataset Input tab first."})
 
106
 
107
  # Create parameters dictionary with the slider value
108
  params = {"bow_top": bow_top_value}
109
 
110
  # Call the process_analysis_request function with proper parameters
111
  try:
112
- results, output = process_analysis_request(dataset, selected_analyses, params)
113
  print(f"Analysis completed successfully")
114
 
115
- # Fix double-encoded JSON issue
116
- if isinstance(output, dict) and "value" in output:
117
- try:
118
- # Remove any extraneous whitespace and quotes
119
- json_str = output["value"].strip()
120
-
121
- # Check if the value is a string that looks like JSON
122
- if isinstance(json_str, str) and json_str.startswith("{") and json_str.endswith("}"):
123
- # Parse the first JSON string into a Python dictionary
124
- parsed_output = json.loads(json_str)
125
-
126
- # Return the cleaned data directly
127
- return results, gr.update(visible=True, value=parsed_output)
128
- else:
129
- return results, output
130
- except json.JSONDecodeError as e:
131
- print(f"JSON parsing error: {e}")
132
- return results, gr.update(visible=True, value={"error": f"Error parsing results: {str(e)}"})
133
- else:
134
- return results, output
135
 
136
  except Exception as e:
137
  import traceback
138
  error_trace = traceback.format_exc()
139
  print(f"Error in analysis: {e}")
140
  print(f"Full traceback: {error_trace}")
141
- return {}, gr.update(visible=True, value={"error": f"Analysis error: {str(e)}"})
 
142
 
143
  # Run analysis with proper parameters
144
  run_analysis_btn.click(
145
  fn=run_analysis,
146
  inputs=[dataset_state, analysis_options, bow_top_slider],
147
- outputs=[analysis_results_state, analysis_output]
148
  )
149
 
150
  return app
 
1
  import gradio as gr
2
  from ui.dataset_input import create_dataset_input, load_example_dataset
3
  from ui.analysis_screen import create_analysis_screen, process_analysis_request
4
+ from visualization.bow_visualizer import process_and_visualize_analysis
5
  import nltk
6
  import os
7
  import json
 
96
 
97
  # Analysis Tab
98
  with gr.Tab("Analysis"):
99
+ # Use create_analysis_screen to get UI components including visualization container
100
+ analysis_options, analysis_params, run_analysis_btn, analysis_output, bow_top_slider, visualization_container = create_analysis_screen()
101
 
102
  # Define a helper function to extract parameter values and call process_analysis_request
103
  def run_analysis(dataset, selected_analyses, bow_top_value):
104
  # Check if dataset exists
105
  if not dataset or "entries" not in dataset or not dataset["entries"]:
106
+ error_components = [gr.Markdown(" **Error:** No dataset provided. Please create a dataset in the Dataset Input tab first.")]
107
+ return {}, gr.update(visible=False), gr.update(visible=True, value=error_components)
108
 
109
  # Create parameters dictionary with the slider value
110
  params = {"bow_top": bow_top_value}
111
 
112
  # Call the process_analysis_request function with proper parameters
113
  try:
114
+ results, _ = process_analysis_request(dataset, selected_analyses, params)
115
  print(f"Analysis completed successfully")
116
 
117
+ # Process and visualize the results
118
+ visualization_components = process_and_visualize_analysis(results)
119
+
120
+ return results, gr.update(visible=False, value=results), gr.update(visible=True, value=visualization_components)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
 
122
  except Exception as e:
123
  import traceback
124
  error_trace = traceback.format_exc()
125
  print(f"Error in analysis: {e}")
126
  print(f"Full traceback: {error_trace}")
127
+ error_components = [gr.Markdown(f" **Error during analysis:** {str(e)}")]
128
+ return {}, gr.update(visible=False), gr.update(visible=True, value=error_components)
129
 
130
  # Run analysis with proper parameters
131
  run_analysis_btn.click(
132
  fn=run_analysis,
133
  inputs=[dataset_state, analysis_options, bow_top_slider],
134
+ outputs=[analysis_results_state, analysis_output, visualization_container]
135
  )
136
 
137
  return app
requirements.txt CHANGED
@@ -1,9 +1,7 @@
1
- gradio>=3.50.2
2
- numpy>=1.24.3
3
- scikit-learn>=1.2.2
4
- matplotlib>=3.7.1
5
- nltk>=3.8.1
6
- scipy>=1.10.1
7
- pandas>=2.0.1
8
- markdown>=3.4.3
9
- requests>=2.31.0
 
1
+ gradio>=4.0.0
2
+ numpy>=1.20.0
3
+ scikit-learn>=1.0.0
4
+ nltk>=3.6.0
5
+ pandas>=1.3.0
6
+ plotly>=5.3.0
7
+ matplotlib>=3.4.0
 
 
ui/analysis_screen.py CHANGED
@@ -1,5 +1,6 @@
1
  import gradio as gr
2
  import json
 
3
 
4
  # Import analysis modules
5
  # Uncomment these when implemented
@@ -99,11 +100,14 @@ def create_analysis_screen():
99
  # Run analysis button
100
  run_analysis_btn = gr.Button("Run Analysis", variant="primary", size="large")
101
 
102
- # Analysis output area
103
  analysis_output = gr.JSON(label="Analysis Results", visible=False)
 
 
 
104
 
105
  # Return the bow_top_slider directly so app.py can access it
106
- return analysis_options, analysis_params, run_analysis_btn, analysis_output, bow_top_slider
107
 
108
  def process_analysis_request(dataset, selected_analyses, parameters):
109
  """
@@ -149,4 +153,4 @@ def process_analysis_request(dataset, selected_analyses, parameters):
149
  print("Analysis complete - results:", analysis_results)
150
 
151
  # Return results and update the output component
152
- return analysis_results, gr.update(visible=True, value=json.dumps(analysis_results, indent=2))
 
1
  import gradio as gr
2
  import json
3
+ from visualization.bow_visualizer import process_and_visualize_analysis
4
 
5
  # Import analysis modules
6
  # Uncomment these when implemented
 
100
  # Run analysis button
101
  run_analysis_btn = gr.Button("Run Analysis", variant="primary", size="large")
102
 
103
+ # Analysis output area - hidden JSON component to store raw results
104
  analysis_output = gr.JSON(label="Analysis Results", visible=False)
105
+
106
+ # Visualization components container
107
+ visualization_container = gr.Column(visible=False)
108
 
109
  # Return the bow_top_slider directly so app.py can access it
110
+ return analysis_options, analysis_params, run_analysis_btn, analysis_output, bow_top_slider, visualization_container
111
 
112
  def process_analysis_request(dataset, selected_analyses, parameters):
113
  """
 
153
  print("Analysis complete - results:", analysis_results)
154
 
155
  # Return results and update the output component
156
+ return analysis_results, gr.update(visible=False, value=analysis_results) # Hide the raw JSON
visualizers/__init__.py CHANGED
@@ -1,8 +1,7 @@
1
- # processors/__init__.py
2
- # Empty file to make the directory a Python package
 
3
 
4
- # ui/__init__.py
5
- # Empty file to make the directory a Python package
6
 
7
- # utils/__init__.py
8
- # Empty file to make the directory a Python package
 
1
+ """
2
+ Visualization components for LLM Response Comparator
3
+ """
4
 
5
+ from .bow_visualizer import process_and_visualize_analysis
 
6
 
7
+ __all__ = ['process_and_visualize_analysis']
 
visualizers/bow_visualizer.py ADDED
@@ -0,0 +1,180 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import json
3
+ import numpy as np
4
+ import plotly.graph_objects as go
5
+ import plotly.express as px
6
+ from plotly.subplots import make_subplots
7
+ import pandas as pd
8
+ from difflib import SequenceMatcher
9
+
10
+ def create_bow_visualization(analysis_results):
11
+ """
12
+ Create visualizations for bag of words analysis results
13
+
14
+ Args:
15
+ analysis_results (dict): Analysis results from the bow analysis
16
+
17
+ Returns:
18
+ list: List of gradio components with visualizations
19
+ """
20
+ # Parse analysis results if it's a string
21
+ if isinstance(analysis_results, str):
22
+ try:
23
+ results = json.loads(analysis_results)
24
+ except json.JSONDecodeError:
25
+ return [gr.Markdown("Error parsing analysis results.")]
26
+ else:
27
+ results = analysis_results
28
+
29
+ output_components = []
30
+
31
+ # Check if we have valid results
32
+ if not results or "analyses" not in results:
33
+ return [gr.Markdown("No analysis results found.")]
34
+
35
+ # Process each prompt
36
+ for prompt, analyses in results["analyses"].items():
37
+ output_components.append(gr.Markdown(f"## Analysis of Prompt: \"{prompt}\""))
38
+
39
+ # Process Bag of Words analysis if available
40
+ if "bag_of_words" in analyses:
41
+ bow_results = analyses["bag_of_words"]
42
+
43
+ # Show models being compared
44
+ models = bow_results.get("models", [])
45
+ if len(models) >= 2:
46
+ output_components.append(gr.Markdown(f"### Comparing responses from {models[0]} and {models[1]}"))
47
+
48
+ # Get important words for each model
49
+ important_words = bow_results.get("important_words", {})
50
+
51
+ # Prepare data for plotting important words
52
+ if important_words:
53
+ for model_name, words in important_words.items():
54
+ df = pd.DataFrame(words)
55
+
56
+ # Create bar chart for top words
57
+ fig = px.bar(df, x='word', y='count',
58
+ title=f"Top Words Used by {model_name}",
59
+ labels={'word': 'Word', 'count': 'Frequency'},
60
+ height=400)
61
+
62
+ # Improve layout
63
+ fig.update_layout(
64
+ xaxis_title="Word",
65
+ yaxis_title="Frequency",
66
+ xaxis={'categoryorder':'total descending'}
67
+ )
68
+
69
+ output_components.append(gr.Plot(value=fig))
70
+
71
+ # Show comparison metrics
72
+ comparisons = bow_results.get("comparisons", {})
73
+ if comparisons:
74
+ for comparison_key, metrics in comparisons.items():
75
+ output_components.append(gr.Markdown(f"### Similarity Metrics for {comparison_key}"))
76
+
77
+ # Format metrics for better display
78
+ if "jaccard_similarity" in metrics:
79
+ output_components.append(gr.Markdown(
80
+ f"- **Jaccard Similarity**: {metrics['jaccard_similarity']:.2f} "
81
+ f"(measures word overlap between responses)"
82
+ ))
83
+
84
+ if "cosine_similarity" in metrics:
85
+ output_components.append(gr.Markdown(
86
+ f"- **Cosine Similarity**: {metrics['cosine_similarity']:.2f} "
87
+ f"(measures how similar the word frequency distributions are)"
88
+ ))
89
+
90
+ if "common_word_count" in metrics:
91
+ output_components.append(gr.Markdown(
92
+ f"- **Common Words**: {metrics['common_word_count']} words appear in both responses"
93
+ ))
94
+
95
+ # Visualize differential words (words with biggest frequency difference)
96
+ diff_words = bow_results.get("differential_words", [])
97
+ word_matrix = bow_results.get("word_count_matrix", {})
98
+
99
+ if diff_words and word_matrix and len(diff_words) > 0:
100
+ output_components.append(gr.Markdown("### Words with Biggest Frequency Differences"))
101
+
102
+ # Create dataframe for plotting
103
+ model1, model2 = models[0], models[1]
104
+ diff_data = []
105
+
106
+ for word in diff_words[:15]: # Limit to top 15 for readability
107
+ if word in word_matrix:
108
+ counts = word_matrix[word]
109
+ diff_data.append({
110
+ "word": word,
111
+ model1: counts.get(model1, 0),
112
+ model2: counts.get(model2, 0)
113
+ })
114
+
115
+ if diff_data:
116
+ diff_df = pd.DataFrame(diff_data)
117
+
118
+ # Create grouped bar chart
119
+ fig = go.Figure()
120
+ fig.add_trace(go.Bar(
121
+ x=diff_df['word'],
122
+ y=diff_df[model1],
123
+ name=model1,
124
+ marker_color='indianred'
125
+ ))
126
+ fig.add_trace(go.Bar(
127
+ x=diff_df['word'],
128
+ y=diff_df[model2],
129
+ name=model2,
130
+ marker_color='lightsalmon'
131
+ ))
132
+
133
+ fig.update_layout(
134
+ title="Word Frequency Comparison",
135
+ xaxis_title="Word",
136
+ yaxis_title="Frequency",
137
+ barmode='group',
138
+ height=500
139
+ )
140
+
141
+ output_components.append(gr.Plot(value=fig))
142
+
143
+ # If no components were added, show a message
144
+ if len(output_components) <= 1:
145
+ output_components.append(gr.Markdown("No detailed Bag of Words analysis found in results."))
146
+
147
+ return output_components
148
+
149
+ def process_and_visualize_analysis(analysis_results):
150
+ """
151
+ Process analysis results and create visualizations
152
+
153
+ Args:
154
+ analysis_results (dict): Analysis results
155
+
156
+ Returns:
157
+ list: List of gradio components with visualizations
158
+ """
159
+ if not analysis_results:
160
+ return [gr.Markdown("No analysis results available. Please run an analysis first.")]
161
+
162
+ all_components = []
163
+
164
+ # Display the JSON output in a collapsible section for debugging
165
+ json_text = json.dumps(analysis_results, indent=2)
166
+ all_components.append(gr.Markdown("### Raw Analysis Results (Expandable)"))
167
+ all_components.append(gr.Markdown("<details><summary>Click to view raw JSON results</summary>\n\n```json\n" + json_text + "\n```\n\n</details>"))
168
+
169
+ # Check if bag of words analysis is present in any prompt's results
170
+ has_bow = False
171
+ for prompt_results in analysis_results.get("analyses", {}).values():
172
+ if "bag_of_words" in prompt_results:
173
+ has_bow = True
174
+ break
175
+
176
+ # Create visualizations for Bag of Words if present
177
+ if has_bow:
178
+ all_components.extend(create_bow_visualization(analysis_results))
179
+
180
+ return all_components