baconnier commited on
Commit
910154a
·
verified ·
1 Parent(s): 3c74d99

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +386 -366
app.py CHANGED
@@ -1,379 +1,399 @@
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):
13
- self.client = OpenAI(
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 = []
22
- if exploration_parameters is None:
23
- exploration_parameters = {}
24
-
25
- system_prompt = """You are an expert art historian AI that helps users explore art history topics by generating
26
- interconnected exploration paths. Generate a JSON response with nodes representing concepts, artworks, or historical
27
- events, and connections showing their relationships."""
28
-
29
- user_prompt = f"""Query: {query}
30
- Selected Path: {json.dumps(selected_path)}
31
- Parameters: {json.dumps(exploration_parameters)}
32
-
33
- Generate an exploration path that includes:
34
- - Multiple interconnected nodes
35
- - Clear relationships between nodes
36
- - Depth-based organization
37
- - Relevant historical context
38
-
39
- Response must be valid JSON with this structure:
40
- {{
41
- "nodes": [
42
- {{
43
- "id": "unique_string",
44
- "title": "node_title",
45
- "description": "detailed_description",
46
- "depth": number,
47
- "connections": [
48
- {{
49
- "target_id": "connected_node_id",
50
- "relevance_score": float
51
- }}
52
- ]
53
- }}
54
- ]
55
- }}"""
56
-
57
- response = self.client.chat.completions.create(
58
- model="mixtral-8x7b-32768",
59
- messages=[
60
- {"role": "system", "content": system_prompt},
61
- {"role": "user", "content": user_prompt}
62
- ],
63
- temperature=0.7,
64
- max_tokens=4000
65
- )
66
-
67
- result = json.loads(response.choices[0].message.content)
68
- return result
69
-
70
- except Exception as e:
71
- print(f"Error generating exploration path: {e}")
72
- return {"error": str(e)}
73
-
74
- def create_interactive_graph(nodes):
75
- """Create an interactive graph visualization using D3.js"""
76
- # First, let's create the data structure D3 expects
77
- nodes_data = [{
78
- 'id': node['id'],
79
- 'title': node['title'],
80
- 'description': node['description'],
81
- 'depth': node['depth']
82
- } for node in nodes]
83
-
84
- links_data = [{
85
- 'source': node['id'],
86
- 'target': conn['target_id'],
87
- 'value': conn.get('relevance_score', 1)
88
- } for node in nodes for conn in node.get('connections', [])]
89
-
90
- html_content = f"""
91
- <!DOCTYPE html>
92
- <html>
93
- <head>
94
- <script src="https://d3js.org/d3.v7.min.js"></script>
95
- <style>
96
- #graph-container {{
97
- width: 100%;
98
- height: 600px;
99
- border: 1px solid #ddd;
100
- border-radius: 4px;
101
- }}
102
- .node {{
103
- cursor: pointer;
104
- }}
105
- .node text {{
106
- font-size: 12px;
107
- font-family: Arial, sans-serif;
108
- }}
109
- .link {{
110
- stroke: #999;
111
- stroke-opacity: 0.6;
112
- }}
113
- .tooltip {{
114
- position: absolute;
115
- padding: 8px;
116
- background: rgba(0, 0, 0, 0.8);
117
- color: white;
118
- border-radius: 4px;
119
- font-size: 12px;
120
- pointer-events: none;
121
- }}
122
- </style>
123
- </head>
124
- <body>
125
- <div id="graph-container"></div>
126
- <script>
127
- // Data
128
- const data = {{
129
- nodes: {json.dumps(nodes_data)},
130
- links: {json.dumps(links_data)}
131
- }};
132
-
133
- // Set up the SVG container
134
- const container = document.getElementById('graph-container');
135
- const width = container.clientWidth;
136
- const height = container.clientHeight;
137
-
138
- const svg = d3.select("#graph-container")
139
- .append("svg")
140
- .attr("width", width)
141
- .attr("height", height);
142
-
143
- // Add zoom capabilities
144
- const g = svg.append("g");
145
- const zoom = d3.zoom()
146
- .scaleExtent([0.1, 4])
147
- .on("zoom", (event) => g.attr("transform", event.transform));
148
- svg.call(zoom);
149
-
150
- // Create a force simulation
151
- const simulation = d3.forceSimulation(data.nodes)
152
- .force("link", d3.forceLink(data.links).id(d => d.id))
153
- .force("charge", d3.forceManyBody().strength(-400))
154
- .force("center", d3.forceCenter(width / 2, height / 2));
155
-
156
- // Create the links
157
- const link = g.append("g")
158
- .selectAll("line")
159
- .data(data.links)
160
- .join("line")
161
- .attr("stroke", "#999")
162
- .attr("stroke-width", 1);
163
-
164
- // Create the nodes
165
- const node = g.append("g")
166
- .selectAll("g")
167
- .data(data.nodes)
168
- .join("g")
169
- .call(d3.drag()
170
- .on("start", dragstarted)
171
- .on("drag", dragged)
172
- .on("end", dragended));
173
-
174
- // Add circles to nodes
175
- node.append("circle")
176
- .attr("r", 20)
177
- .attr("fill", d => ['#FF9999', '#99FF99', '#9999FF'][d.depth % 3]);
178
-
179
- // Add labels to nodes
180
- node.append("text")
181
- .text(d => d.title)
182
- .attr("x", 25)
183
- .attr("y", 5);
184
-
185
- // Add tooltip
186
- const tooltip = d3.select("body").append("div")
187
- .attr("class", "tooltip")
188
- .style("opacity", 0);
189
-
190
- // Add hover effects
191
- node.on("mouseover", function(event, d) {{
192
- tooltip.transition()
193
- .duration(200)
194
- .style("opacity", .9);
195
- tooltip.html(`<strong>${{d.title}}</strong><br/>${{d.description}}`)
196
- .style("left", (event.pageX + 10) + "px")
197
- .style("top", (event.pageY - 10) + "px");
198
- }})
199
- .on("mouseout", function() {{
200
- tooltip.transition()
201
- .duration(500)
202
- .style("opacity", 0);
203
- }});
204
-
205
- // Add click handler
206
- node.on("click", function(event, d) {{
207
- if (window.gradio) {{
208
- window.gradio.dispatch("select", d);
209
- }}
210
- }});
211
-
212
- // Update positions on each tick
213
- simulation.on("tick", () => {{
214
- link
215
- .attr("x1", d => d.source.x)
216
- .attr("y1", d => d.source.y)
217
- .attr("x2", d => d.target.x)
218
- .attr("y2", d => d.target.y);
219
-
220
- node.attr("transform", d => `translate(${{d.x}},${{d.y}})`);
221
- }});
222
-
223
- // Drag functions
224
- function dragstarted(event, d) {{
225
- if (!event.active) simulation.alphaTarget(0.3).restart();
226
- d.fx = d.x;
227
- d.fy = d.y;
228
- }}
229
-
230
- function dragged(event, d) {{
231
- d.fx = event.x;
232
- d.fy = event.y;
233
- }}
234
-
235
- function dragended(event, d) {{
236
- if (!event.active) simulation.alphaTarget(0);
237
- d.fx = null;
238
- d.fy = null;
239
- }}
240
- </script>
241
- </body>
242
- </html>
243
- """
244
- return html_content
245
-
246
- def explore(query: str, path_history: str = "[]", parameters: str = "{}", depth: int = 5, domain: str = "") -> tuple:
247
- """Generate exploration path and visualization"""
248
- try:
249
- # Initialize generator
250
- api_key = os.getenv("GROQ_API_KEY")
251
- if not api_key:
252
- raise ValueError("GROQ_API_KEY not found in environment variables")
253
-
254
- generator = ExplorationPathGenerator(api_key=api_key)
255
-
256
- # Parse inputs
257
- try:
258
- selected_path = json.loads(path_history)
259
- exploration_parameters = json.loads(parameters)
260
- except json.JSONDecodeError as e:
261
- raise ValueError(f"Invalid JSON input: {str(e)}")
262
-
263
- # Add domain to parameters if provided
264
- if domain:
265
- exploration_parameters["domain"] = domain
266
-
267
- # Generate result
268
- result = generator.generate_exploration_path(
269
- query=query,
270
- selected_path=selected_path,
271
- exploration_parameters=exploration_parameters
272
- )
273
-
274
- # Create visualization
275
- graph_html = create_interactive_graph(result.get('nodes', []))
276
-
277
- # Initial summary
278
- summary = "Click on nodes in the graph to see detailed information"
279
-
280
- return json.dumps(result), graph_html, summary
281
-
282
- except Exception as e:
283
- error_response = {
284
- "error": str(e),
285
- "status": "failed",
286
- "timestamp": datetime.now().isoformat(),
287
- "query": query
288
- }
289
- return json.dumps(error_response), "<div>Error generating visualization</div>", f"Error: {str(e)}"
 
 
 
 
 
 
 
 
 
290
 
291
  def create_interface() -> gr.Blocks:
292
- """Create and configure the Gradio interface"""
293
- with gr.Blocks(
294
- title="Art History Exploration Path Generator",
295
- theme=gr.themes.Soft(),
296
- css="#graph-visualization {min-height: 600px;}"
297
- ) as interface:
298
- gr.Markdown("""
299
- # Art History Exploration Path Generator
300
- Generate interactive exploration paths through art history topics.
301
- Drag nodes to rearrange, zoom with mouse wheel, and click nodes for details.
302
- """)
303
-
304
- with gr.Row():
305
- with gr.Column(scale=1):
306
- query_input = gr.Textbox(
307
- label="Exploration Query",
308
- placeholder="Enter your art history exploration query...",
309
- lines=2
310
- )
311
- path_history = gr.Textbox(
312
- label="Path History (JSON)",
313
- placeholder="[]",
314
- lines=3,
315
- value="[]"
316
- )
317
- parameters = gr.Textbox(
318
- label="Additional Parameters (JSON)",
319
- placeholder="{}",
320
- lines=3,
321
- value="{}"
322
- )
323
- depth = gr.Slider(
324
- label="Exploration Depth",
325
- minimum=1,
326
- maximum=10,
327
- value=5,
328
- step=1
329
- )
330
- domain = gr.Textbox(
331
- label="Domain Context",
332
- placeholder="Optional: Specify art history period or movement",
333
- lines=1
334
- )
335
- generate_btn = gr.Button("Generate Exploration Path", variant="primary")
336
-
337
- with gr.Column(scale=2):
338
- with gr.Accordion("Exploration Result", open=False):
339
- text_output = gr.JSON(label="Raw Result")
340
-
341
- graph_output = gr.HTML(
342
- label="Interactive Exploration Graph",
343
- value="<div>Generate a path to see the visualization</div>",
344
- elem_id="graph-visualization"
345
- )
346
- node_summary = gr.Textbox(
347
- label="Node Details",
348
- lines=5,
349
- placeholder="Click on nodes to see details"
350
- )
351
-
352
- generate_btn.click(
353
- fn=explore,
354
- inputs=[query_input, path_history, parameters, depth, domain],
355
- outputs=[text_output, graph_output, node_summary]
356
- )
357
-
358
- gr.Examples(
359
- examples=[
360
- ["Explore the evolution of Renaissance painting techniques", "[]", "{}", 5, "Renaissance"],
361
- ["Investigate the influence of Japanese art on Impressionism", "[]", "{}", 7, "Impressionism"],
362
- ["Analyze the development of Cubism through Picasso's work", "[]", "{}", 6, "Cubism"]
363
- ],
364
- inputs=[query_input, path_history, parameters, depth, domain]
365
- )
366
-
367
- return interface
 
 
 
 
368
 
369
  if __name__ == "__main__":
370
- try:
371
- print(f"===== Application Startup at {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} =====")
372
- demo = create_interface()
373
- demo.launch(
374
- server_name="0.0.0.0",
375
- server_port=7860,
376
- share=True
377
- )
378
- except Exception as e:
379
- print(f"Failed to launch interface: {e}")
 
 
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):
19
+ self.client = OpenAI(
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 = []
33
+ if exploration_parameters is None:
34
+ exploration_parameters = {}
35
+
36
+ system_prompt = """You are an expert art historian AI that helps users explore art history topics by generating interconnected exploration paths. Generate a JSON response with nodes representing concepts, artworks, or historical events, and connections showing their relationships."""
37
+
38
+ user_prompt = f"""Query: {query}
39
+ Selected Path: {json.dumps(selected_path)}
40
+ Parameters: {json.dumps(exploration_parameters)}
41
+ Generate an exploration path that includes:
42
+ - Multiple interconnected nodes
43
+ - Clear relationships between nodes
44
+ - Depth-based organization
45
+ - Relevant historical context
46
+ Response must be valid JSON with this structure:
47
+ {{
48
+ "nodes": [
49
+ {{
50
+ "id": "unique_string",
51
+ "title": "node_title",
52
+ "description": "detailed_description",
53
+ "depth": number,
54
+ "connections": [
55
+ {{
56
+ "target_id": "connected_node_id",
57
+ "relevance_score": float
58
+ }}
59
+ ]
60
+ }}
61
+ ]
62
+ }}"""
63
+
64
+ response = self.client.chat.completions.create(
65
+ model="mixtral-8x7b-32768",
66
+ messages=[
67
+ {"role": "system", "content": system_prompt},
68
+ {"role": "user", "content": user_prompt}
69
+ ],
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
+ @gr.cache_examples
252
+ def explore(
253
+ query: str,
254
+ path_history: str = "[]",
255
+ parameters: str = "{}",
256
+ depth: int = 5,
257
+ domain: str = ""
258
+ ) -> Tuple[str, str, str]:
259
+ """Generate exploration path and visualization"""
260
+ try:
261
+ # Initialize generator
262
+ api_key = os.getenv("GROQ_API_KEY")
263
+ if not api_key:
264
+ raise ValueError("GROQ_API_KEY not found in environment variables")
265
+
266
+ generator = ExplorationPathGenerator(api_key=api_key)
267
+
268
+ # Parse inputs
269
+ try:
270
+ selected_path = json.loads(path_history)
271
+ exploration_parameters = json.loads(parameters)
272
+ except json.JSONDecodeError as e:
273
+ raise ValueError(f"Invalid JSON input: {str(e)}")
274
+
275
+ # Add domain and depth to parameters
276
+ exploration_parameters.update({
277
+ "domain": domain,
278
+ "depth": depth
279
+ })
280
+
281
+ # Generate result
282
+ result = generator.generate_exploration_path(
283
+ query=query,
284
+ selected_path=selected_path,
285
+ exploration_parameters=exploration_parameters
286
+ )
287
+
288
+ # Create visualization
289
+ graph_html = ExplorationPathGenerator.create_interactive_graph(result.get('nodes', []))
290
+
291
+ # Initial summary
292
+ summary = "Click on nodes in the graph to see detailed information"
293
+
294
+ return json.dumps(result), graph_html, summary
295
+
296
+ except Exception as e:
297
+ logger.error(f"Error in explore function: {e}")
298
+ error_response = {
299
+ "error": str(e),
300
+ "status": "failed",
301
+ "timestamp": datetime.now().isoformat(),
302
+ "query": query
303
+ }
304
+ return json.dumps(error_response), "<div>Error generating visualization</div>", f"Error: {str(e)}"
305
 
306
  def create_interface() -> gr.Blocks:
307
+ """Create and configure the Gradio interface"""
308
+ with gr.Blocks(
309
+ title="Art History Exploration Path Generator",
310
+ theme=gr.themes.Soft(),
311
+ css="#graph-visualization {min-height: 600px;}"
312
+ ) as interface:
313
+ gr.Markdown("""
314
+ # Art History Exploration Path Generator
315
+ Generate interactive exploration paths through art history topics.
316
+ Drag nodes to rearrange, zoom with mouse wheel, and click nodes for details.
317
+ """)
318
+
319
+ with gr.Row():
320
+ with gr.Column(scale=1):
321
+ query_input = gr.Textbox(
322
+ label="Exploration Query",
323
+ placeholder="Enter your art history exploration query...",
324
+ lines=2
325
+ )
326
+
327
+ path_history = gr.Textbox(
328
+ label="Path History (JSON)",
329
+ placeholder="[]",
330
+ lines=3,
331
+ value="[]"
332
+ )
333
+
334
+ parameters = gr.Textbox(
335
+ label="Additional Parameters (JSON)",
336
+ placeholder="{}",
337
+ lines=3,
338
+ value="{}"
339
+ )
340
+
341
+ depth = gr.Slider(
342
+ label="Exploration Depth",
343
+ minimum=1,
344
+ maximum=10,
345
+ value=5,
346
+ step=1
347
+ )
348
+
349
+ domain = gr.Textbox(
350
+ label="Domain Context",
351
+ placeholder="Optional: Specify art history period or movement",
352
+ lines=1
353
+ )
354
+
355
+ generate_btn = gr.Button("Generate Exploration Path", variant="primary")
356
+
357
+ with gr.Column(scale=2):
358
+ with gr.Accordion("Exploration Result", open=False):
359
+ text_output = gr.JSON(label="Raw Result")
360
+ graph_output = gr.HTML(
361
+ label="Interactive Exploration Graph",
362
+ value="<div>Generate a path to see the visualization</div>",
363
+ elem_id="graph-visualization"
364
+ )
365
+ node_summary = gr.Textbox(
366
+ label="Node Details",
367
+ lines=5,
368
+ placeholder="Click on nodes to see details"
369
+ )
370
+
371
+ generate_btn.click(
372
+ fn=explore,
373
+ inputs=[query_input, path_history, parameters, depth, domain],
374
+ outputs=[text_output, graph_output, node_summary]
375
+ )
376
+
377
+ gr.Examples(
378
+ examples=[
379
+ ["Explore the evolution of Renaissance painting techniques", "[]", "{}", 5, "Renaissance"],
380
+ ["Investigate the influence of Japanese art on Impressionism", "[]", "{}", 7, "Impressionism"],
381
+ ["Analyze the development of Cubism through Picasso's work", "[]", "{}", 6, "Cubism"]
382
+ ],
383
+ inputs=[query_input, path_history, parameters, depth, domain]
384
+ )
385
+
386
+ return interface
387
 
388
  if __name__ == "__main__":
389
+ try:
390
+ logger.info(f"===== Application Startup at {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} =====")
391
+ load_dotenv()
392
+ demo = create_interface()
393
+ demo.launch(
394
+ server_name="0.0.0.0",
395
+ server_port=7860,
396
+ share=True
397
+ )
398
+ except Exception as e:
399
+ logger.error(f"Failed to launch interface: {e}")