baconnier commited on
Commit
55020f5
·
verified ·
1 Parent(s): 533f577

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +90 -229
app.py CHANGED
@@ -1,18 +1,12 @@
1
  import os
2
  import json
3
  import gradio as gr
4
- import logging
5
  from datetime import datetime
6
  from dotenv import load_dotenv
7
  from openai import OpenAI
8
- from typing import Optional, Dict, Any, Tuple
9
 
10
- # Configure logging
11
- logging.basicConfig(
12
- level=logging.INFO,
13
- format='%(asctime)s - %(levelname)s - %(message)s'
14
- )
15
- logger = logging.getLogger(__name__)
16
 
17
  class ExplorationPathGenerator:
18
  def __init__(self, api_key: str):
@@ -20,13 +14,8 @@ class ExplorationPathGenerator:
20
  api_key=api_key,
21
  base_url="https://api.groq.com/openai/v1"
22
  )
23
-
24
- def generate_exploration_path(
25
- self,
26
- query: str,
27
- selected_path: Optional[list] = None,
28
- exploration_parameters: Optional[dict] = None
29
- ) -> Dict[str, Any]:
30
  try:
31
  if selected_path is None:
32
  selected_path = []
@@ -54,7 +43,7 @@ Response must be valid JSON with this structure:
54
  "connections": [
55
  {{
56
  "target_id": "connected_node_id",
57
- "relevance_score": float
58
  }}
59
  ]
60
  }}
@@ -70,182 +59,78 @@ Response must be valid JSON with this structure:
70
  temperature=0.7,
71
  max_tokens=4000
72
  )
73
-
74
  result = json.loads(response.choices[0].message.content)
75
  return result
76
-
77
  except Exception as e:
78
- logger.error(f"Error generating exploration path: {e}")
79
  return {"error": str(e)}
80
 
81
- @staticmethod
82
- def create_interactive_graph(nodes: list) -> str:
83
- """Create an interactive graph visualization using D3.js"""
84
- nodes_data = [{
85
- 'id': node['id'],
86
- 'title': node['title'],
87
- 'description': node['description'],
88
- 'depth': node['depth']
89
- } for node in nodes]
90
 
91
- links_data = [{
92
- 'source': node['id'],
93
- 'target': conn['target_id'],
94
- 'value': conn.get('relevance_score', 1)
95
- } for node in nodes for conn in node.get('connections', [])]
96
-
97
- html_content = f"""
98
- <!DOCTYPE html>
99
- <html>
100
- <head>
101
- <script src="https://d3js.org/d3.v7.min.js"></script>
102
- <style>
103
- #graph-container {{
104
- width: 100%;
105
- height: 600px;
106
- border: 1px solid #ddd;
107
- border-radius: 4px;
108
- }}
109
- .node {{
110
- cursor: pointer;
111
- }}
112
- .node text {{
113
- font-size: 12px;
114
- font-family: Arial, sans-serif;
115
- }}
116
- .link {{
117
- stroke: #999;
118
- stroke-opacity: 0.6;
119
- }}
120
- .tooltip {{
121
- position: absolute;
122
- padding: 8px;
123
- background: rgba(0, 0, 0, 0.8);
124
- color: white;
125
- border-radius: 4px;
126
- font-size: 12px;
127
- pointer-events: none;
128
- }}
129
- </style>
130
- </head>
131
- <body>
132
- <div id="graph-container"></div>
133
- <script>
134
- // Data
135
- const data = {{
136
- nodes: {json.dumps(nodes_data)},
137
- links: {json.dumps(links_data)}
138
- }};
139
-
140
- // Set up the SVG container
141
- const container = document.getElementById('graph-container');
142
- const width = container.clientWidth;
143
- const height = container.clientHeight;
144
- const svg = d3.select("#graph-container")
145
- .append("svg")
146
- .attr("width", width)
147
- .attr("height", height);
148
-
149
- // Add zoom capabilities
150
- const g = svg.append("g");
151
- const zoom = d3.zoom()
152
- .scaleExtent([0.1, 4])
153
- .on("zoom", (event) => g.attr("transform", event.transform));
154
- svg.call(zoom);
155
-
156
- // Create a force simulation
157
- const simulation = d3.forceSimulation(data.nodes)
158
- .force("link", d3.forceLink(data.links).id(d => d.id))
159
- .force("charge", d3.forceManyBody().strength(-400))
160
- .force("center", d3.forceCenter(width / 2, height / 2));
161
-
162
- // Create the links
163
- const link = g.append("g")
164
- .selectAll("line")
165
- .data(data.links)
166
- .join("line")
167
- .attr("stroke", "#999")
168
- .attr("stroke-width", 1);
169
-
170
- // Create the nodes
171
- const node = g.append("g")
172
- .selectAll("g")
173
- .data(data.nodes)
174
- .join("g")
175
- .call(d3.drag()
176
- .on("start", dragstarted)
177
- .on("drag", dragged)
178
- .on("end", dragended));
179
-
180
- // Add circles to nodes
181
- node.append("circle")
182
- .attr("r", 20)
183
- .attr("fill", d => ['#FF9999', '#99FF99', '#9999FF'][d.depth % 3]);
184
-
185
- // Add labels to nodes
186
- node.append("text")
187
- .text(d => d.title)
188
- .attr("x", 25)
189
- .attr("y", 5);
190
-
191
- // Add tooltip
192
- const tooltip = d3.select("body").append("div")
193
- .attr("class", "tooltip")
194
- .style("opacity", 0);
195
-
196
- // Add hover effects
197
- node.on("mouseover", function(event, d) {{
198
- tooltip.transition()
199
- .duration(200)
200
- .style("opacity", .9);
201
- tooltip.html(`<strong>${{d.title}}</strong><br/>${{d.description}}`)
202
- .style("left", (event.pageX + 10) + "px")
203
- .style("top", (event.pageY - 10) + "px");
204
- }})
205
- .on("mouseout", function() {{
206
- tooltip.transition()
207
- .duration(500)
208
- .style("opacity", 0);
209
- }});
210
-
211
- // Add click handler
212
- node.on("click", function(event, d) {{
213
- if (window.gradio) {{
214
- window.gradio.dispatch("select", d);
215
- }}
216
- }});
217
-
218
- // Update positions on each tick
219
- simulation.on("tick", () => {{
220
- link
221
- .attr("x1", d => d.source.x)
222
- .attr("y1", d => d.source.y)
223
- .attr("x2", d => d.target.x)
224
- .attr("y2", d => d.target.y);
225
- node.attr("transform", d => `translate(${{d.x}},${{d.y}})`);
226
- }});
227
-
228
- // Drag functions
229
- function dragstarted(event, d) {{
230
- if (!event.active) simulation.alphaTarget(0.3).restart();
231
- d.fx = d.x;
232
- d.fy = d.y;
233
- }}
234
 
235
- function dragged(event, d) {{
236
- d.fx = event.x;
237
- d.fy = event.y;
238
- }}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
239
 
240
- function dragended(event, d) {{
241
- if (!event.active) simulation.alphaTarget(0);
242
- d.fx = null;
243
- d.fy = null;
244
- }}
245
- </script>
246
- </body>
247
- </html>
248
- """
249
  return html_content
250
 
251
  def explore(query: str, path_history: str = "[]", parameters: str = "{}", depth: int = 5, domain: str = "") -> tuple:
@@ -265,9 +150,11 @@ def explore(query: str, path_history: str = "[]", parameters: str = "{}", depth:
265
  except json.JSONDecodeError as e:
266
  raise ValueError(f"Invalid JSON input: {str(e)}")
267
 
268
- # Add domain to parameters if provided
269
- if domain:
270
- exploration_parameters["domain"] = domain
 
 
271
 
272
  # Generate result
273
  result = generator.generate_exploration_path(
@@ -276,11 +163,10 @@ def explore(query: str, path_history: str = "[]", parameters: str = "{}", depth:
276
  exploration_parameters=exploration_parameters
277
  )
278
 
279
- # Create visualization - Fixed: Using the generator instance method
280
- graph_html = generator.create_interactive_graph(result.get('nodes', []))
281
 
282
- # Initial summary
283
- summary = "Click on nodes in the graph to see detailed information"
284
 
285
  return json.dumps(result), graph_html, summary
286
 
@@ -297,13 +183,11 @@ def create_interface() -> gr.Blocks:
297
  """Create and configure the Gradio interface"""
298
  with gr.Blocks(
299
  title="Art History Exploration Path Generator",
300
- theme=gr.themes.Soft(),
301
- css="#graph-visualization {min-height: 600px;}"
302
  ) as interface:
303
  gr.Markdown("""
304
  # Art History Exploration Path Generator
305
  Generate interactive exploration paths through art history topics.
306
- Drag nodes to rearrange, zoom with mouse wheel, and click nodes for details.
307
  """)
308
 
309
  with gr.Row():
@@ -314,20 +198,6 @@ def create_interface() -> gr.Blocks:
314
  lines=2
315
  )
316
 
317
- path_history = gr.Textbox(
318
- label="Path History (JSON)",
319
- placeholder="[]",
320
- lines=3,
321
- value="[]"
322
- )
323
-
324
- parameters = gr.Textbox(
325
- label="Additional Parameters (JSON)",
326
- placeholder="{}",
327
- lines=3,
328
- value="{}"
329
- )
330
-
331
  depth = gr.Slider(
332
  label="Exploration Depth",
333
  minimum=1,
@@ -345,40 +215,31 @@ def create_interface() -> gr.Blocks:
345
  generate_btn = gr.Button("Generate Exploration Path", variant="primary")
346
 
347
  with gr.Column(scale=2):
348
- with gr.Accordion("Exploration Result", open=False):
349
- text_output = gr.JSON(label="Raw Result")
350
- graph_output = gr.HTML(
351
- label="Interactive Exploration Graph",
352
- value="<div>Generate a path to see the visualization</div>",
353
- elem_id="graph-visualization"
354
- )
355
- node_summary = gr.Textbox(
356
- label="Node Details",
357
- lines=5,
358
- placeholder="Click on nodes to see details"
359
- )
360
 
361
  generate_btn.click(
362
  fn=explore,
363
- inputs=[query_input, path_history, parameters, depth, domain],
364
- outputs=[text_output, graph_output, node_summary]
 
365
  )
366
 
367
  gr.Examples(
368
  examples=[
369
- ["Explore the evolution of Renaissance painting techniques", "[]", "{}", 5, "Renaissance"],
370
- ["Investigate the influence of Japanese art on Impressionism", "[]", "{}", 7, "Impressionism"],
371
- ["Analyze the development of Cubism through Picasso's work", "[]", "{}", 6, "Cubism"]
372
  ],
373
- inputs=[query_input, path_history, parameters, depth, domain]
374
  )
375
 
376
  return interface
377
 
378
  if __name__ == "__main__":
379
  try:
380
- logger.info(f"===== Application Startup at {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} =====")
381
- load_dotenv()
382
  demo = create_interface()
383
  demo.launch(
384
  server_name="0.0.0.0",
@@ -386,4 +247,4 @@ if __name__ == "__main__":
386
  share=True
387
  )
388
  except Exception as e:
389
- logger.error(f"Failed to launch interface: {e}")
 
1
  import os
2
  import json
3
  import gradio as gr
 
4
  from datetime import datetime
5
  from dotenv import load_dotenv
6
  from openai import OpenAI
 
7
 
8
+ # Load environment variables
9
+ load_dotenv()
 
 
 
 
10
 
11
  class ExplorationPathGenerator:
12
  def __init__(self, api_key: str):
 
14
  api_key=api_key,
15
  base_url="https://api.groq.com/openai/v1"
16
  )
17
+
18
+ def generate_exploration_path(self, query: str, selected_path=None, exploration_parameters=None):
 
 
 
 
 
19
  try:
20
  if selected_path is None:
21
  selected_path = []
 
43
  "connections": [
44
  {{
45
  "target_id": "connected_node_id",
46
+ "relationship": "description of relationship"
47
  }}
48
  ]
49
  }}
 
59
  temperature=0.7,
60
  max_tokens=4000
61
  )
62
+
63
  result = json.loads(response.choices[0].message.content)
64
  return result
65
+
66
  except Exception as e:
67
+ print(f"Error generating exploration path: {e}")
68
  return {"error": str(e)}
69
 
70
+ def create_visualization_html(self, nodes):
71
+ """Create a simple HTML visualization"""
72
+ html_content = "<div style='padding: 20px; font-family: Arial, sans-serif;'>"
 
 
 
 
 
 
73
 
74
+ # Create a style for the nodes
75
+ html_content += """
76
+ <style>
77
+ .node-card {
78
+ border: 1px solid #ddd;
79
+ border-radius: 8px;
80
+ padding: 15px;
81
+ margin: 10px 0;
82
+ background-color: #f9f9f9;
83
+ }
84
+ .node-title {
85
+ font-weight: bold;
86
+ color: #2c3e50;
87
+ margin-bottom: 8px;
88
+ }
89
+ .node-description {
90
+ color: #34495e;
91
+ margin-bottom: 8px;
92
+ }
93
+ .node-connections {
94
+ font-size: 0.9em;
95
+ color: #7f8c8d;
96
+ }
97
+ .depth-indicator {
98
+ display: inline-block;
99
+ padding: 3px 8px;
100
+ border-radius: 12px;
101
+ font-size: 0.8em;
102
+ margin-bottom: 5px;
103
+ }
104
+ </style>
105
+ """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
 
107
+ # Create nodes visualization
108
+ for node in nodes:
109
+ depth_color = ['#FF9999', '#99FF99', '#9999FF'][node['depth'] % 3]
110
+
111
+ html_content += f"""
112
+ <div class='node-card'>
113
+ <div class='depth-indicator' style='background-color: {depth_color}'>
114
+ Depth: {node['depth']}
115
+ </div>
116
+ <div class='node-title'>{node['title']}</div>
117
+ <div class='node-description'>{node['description']}</div>
118
+ <div class='node-connections'>
119
+ """
120
+
121
+ # Add connections
122
+ if node.get('connections'):
123
+ html_content += "<strong>Connections:</strong><ul>"
124
+ for conn in node['connections']:
125
+ html_content += f"<li>Connected to: {conn['target_id']}"
126
+ if 'relationship' in conn:
127
+ html_content += f" - {conn['relationship']}"
128
+ html_content += "</li>"
129
+ html_content += "</ul>"
130
+
131
+ html_content += "</div></div>"
132
 
133
+ html_content += "</div>"
 
 
 
 
 
 
 
 
134
  return html_content
135
 
136
  def explore(query: str, path_history: str = "[]", parameters: str = "{}", depth: int = 5, domain: str = "") -> tuple:
 
150
  except json.JSONDecodeError as e:
151
  raise ValueError(f"Invalid JSON input: {str(e)}")
152
 
153
+ # Add parameters
154
+ exploration_parameters.update({
155
+ "domain": domain,
156
+ "depth": depth
157
+ })
158
 
159
  # Generate result
160
  result = generator.generate_exploration_path(
 
163
  exploration_parameters=exploration_parameters
164
  )
165
 
166
+ # Create visualization using the simplified HTML method
167
+ graph_html = generator.create_visualization_html(result.get('nodes', []))
168
 
169
+ summary = f"Generated {len(result.get('nodes', []))} nodes for your query"
 
170
 
171
  return json.dumps(result), graph_html, summary
172
 
 
183
  """Create and configure the Gradio interface"""
184
  with gr.Blocks(
185
  title="Art History Exploration Path Generator",
186
+ theme=gr.themes.Soft()
 
187
  ) as interface:
188
  gr.Markdown("""
189
  # Art History Exploration Path Generator
190
  Generate interactive exploration paths through art history topics.
 
191
  """)
192
 
193
  with gr.Row():
 
198
  lines=2
199
  )
200
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
201
  depth = gr.Slider(
202
  label="Exploration Depth",
203
  minimum=1,
 
215
  generate_btn = gr.Button("Generate Exploration Path", variant="primary")
216
 
217
  with gr.Column(scale=2):
218
+ text_output = gr.JSON(label="Raw Result")
219
+ graph_output = gr.HTML(label="Visualization")
220
+ summary_output = gr.Textbox(label="Summary", lines=2)
 
 
 
 
 
 
 
 
 
221
 
222
  generate_btn.click(
223
  fn=explore,
224
+ inputs=[query_input, gr.Textbox(value="[]", visible=False),
225
+ gr.Textbox(value="{}", visible=False), depth, domain],
226
+ outputs=[text_output, graph_output, summary_output]
227
  )
228
 
229
  gr.Examples(
230
  examples=[
231
+ ["Explore the evolution of Renaissance painting techniques", 5, "Renaissance"],
232
+ ["Investigate the influence of Japanese art on Impressionism", 7, "Impressionism"],
233
+ ["Analyze the development of Cubism through Picasso's work", 6, "Cubism"]
234
  ],
235
+ inputs=[query_input, depth, domain]
236
  )
237
 
238
  return interface
239
 
240
  if __name__ == "__main__":
241
  try:
242
+ print(f"===== Application Startup at {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} =====")
 
243
  demo = create_interface()
244
  demo.launch(
245
  server_name="0.0.0.0",
 
247
  share=True
248
  )
249
  except Exception as e:
250
+ print(f"Failed to launch interface: {e}")