baconnier commited on
Commit
4244d2c
·
verified ·
1 Parent(s): 82d9c75

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +69 -218
app.py CHANGED
@@ -1,236 +1,87 @@
1
- import os
2
- import openai
3
  import gradio as gr
4
- import json
5
- from typing import Optional, Dict, Any, List
6
- import plotly.graph_objects as go
7
- import instructor
8
- from models import ArtHistoryResponse, Location
9
- from variables import CONTEXTUAL_ZOOM_PROMPT, CONTEXTUAL_ZOOM_default_response
10
 
11
- class ArtExplorer:
12
- def __init__(self):
13
- # Initialize OpenAI client with instructor patch
14
- self.client = instructor.patch(openai.OpenAI(
15
- base_url="https://api.groq.com/openai/v1",
16
- api_key=os.environ.get("GROQ_API_KEY")
17
- ))
18
-
19
- self.current_state = {
20
- "zoom_level": 0,
21
- "selections": {}
22
- }
23
-
24
- def create_map(self, locations: List[Location]) -> go.Figure:
25
- """Create a Plotly map figure from location data"""
26
- if not locations:
27
- locations = [Location(
28
- name="Paris",
29
- lat=48.8566,
30
- lon=2.3522,
31
- relevance="Default location"
32
- )]
33
-
34
- fig = go.Figure(go.Scattermapbox(
35
- lat=[loc.lat for loc in locations],
36
- lon=[loc.lon for loc in locations],
37
- mode='markers',
38
- marker=go.scattermapbox.Marker(size=10),
39
- text=[loc.name for loc in locations]
40
- ))
41
-
42
- fig.update_layout(
43
- mapbox_style="open-street-map",
44
- mapbox=dict(
45
- center=dict(lat=48.8566, lon=2.3522),
46
- zoom=4
47
- ),
48
- margin=dict(r=0, t=0, l=0, b=0)
49
- )
50
- return fig
51
-
52
- def get_llm_response(self, query: str, zoom_context: Optional[Dict[str, Any]] = None) -> ArtHistoryResponse:
53
- """Get response from LLM with proper validation"""
54
- try:
55
- print("\n=== Starting LLM Request ===")
56
- print(f"Input query: {query}")
57
- print(f"Zoom context: {zoom_context}")
58
-
59
- current_zoom_states = {
60
- "temporal": {"level": self.current_state["zoom_level"], "selection": ""},
61
- "geographical": {"level": self.current_state["zoom_level"], "selection": ""},
62
- "style": {"level": self.current_state["zoom_level"], "selection": ""},
63
- "subject": {"level": self.current_state["zoom_level"], "selection": ""}
64
- }
65
-
66
- if zoom_context:
67
- for key, value in zoom_context.items():
68
- if key in current_zoom_states:
69
- current_zoom_states[key]["selection"] = value
70
-
71
- messages = [
72
- {"role": "system", "content": "You are an expert art historian specializing in interactive exploration."},
73
- {"role": "user", "content": CONTEXTUAL_ZOOM_PROMPT.format(
74
- user_query=query,
75
- current_zoom_states=json.dumps(current_zoom_states, indent=2)
76
- )}
77
- ]
78
-
79
- print("\nSending request to LLM...")
80
- response = self.client.chat.completions.create(
81
- model="mixtral-8x7b-32768",
82
- messages=messages,
83
- temperature=0.1,
84
- max_tokens=2048,
85
- response_model=ArtHistoryResponse
86
- )
87
- print("\nReceived validated response from LLM")
88
- return response
89
 
90
- except Exception as e:
91
- print(f"\nError in LLM response: {str(e)}")
92
- print(f"Full error details: {e.__class__.__name__}")
93
- import traceback
94
- print(traceback.format_exc())
95
- return self.get_default_response()
96
 
97
- def get_default_response(self) -> ArtHistoryResponse:
98
- """Return default response when LLM fails"""
99
- return ArtHistoryResponse(**CONTEXTUAL_ZOOM_default_response)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
 
101
- def create_interface(self) -> gr.Blocks:
102
- """Create the Gradio interface"""
103
- with gr.Blocks() as demo:
104
  gr.Markdown("# Art History Explorer")
105
 
106
  with gr.Row():
107
- query = gr.Textbox(
108
  label="Enter your art history query",
109
- placeholder="e.g., Napoleon wars, Renaissance Italy"
110
  )
111
- search_btn = gr.Button("Explore")
112
-
113
- with gr.Row():
114
- # Temporal axis
115
- with gr.Column():
116
- time_slider = gr.Slider(
117
- minimum=1000,
118
- maximum=2024,
119
- label="Time Period",
120
- interactive=True
121
- )
122
- time_explanation = gr.Markdown()
123
- time_zoom = gr.Button("🔍 Zoom Time Period")
124
-
125
- # Geographical axis
126
- with gr.Column():
127
- map_plot = gr.Plot(label="Geographic Location")
128
- geo_explanation = gr.Markdown()
129
- geo_zoom = gr.Button("🔍 Zoom Geography")
130
-
131
- with gr.Row():
132
- # Style axis
133
- style_select = gr.Dropdown(
134
- choices=["Classical", "Modern"],
135
- multiselect=True,
136
- label="Artistic Styles",
137
- allow_custom_value=True
138
  )
139
- style_explanation = gr.Markdown()
140
- style_zoom = gr.Button("🔍 Zoom Styles")
141
-
142
- def initial_search(query: str) -> tuple:
143
- """Handle the initial search query"""
144
- response = self.get_llm_response(query)
145
-
146
- temporal_config = response.axis_configurations["temporal"].current_zoom
147
- geographical_config = response.axis_configurations["geographical"].current_zoom
148
- style_config = response.axis_configurations["style"].current_zoom
149
-
150
- map_fig = self.create_map(geographical_config.locations)
151
-
152
- return (
153
- temporal_config.range,
154
- map_fig,
155
- style_config.options,
156
- temporal_config.explanation,
157
- geographical_config.explanation,
158
- style_config.explanation
159
- )
160
-
161
- def zoom_axis(query: str, axis_name: str, current_value: Any) -> tuple:
162
- """Handle zoom events for any axis"""
163
- self.current_state["zoom_level"] += 1
164
- response = self.get_llm_response(
165
- query,
166
- zoom_context={axis_name: current_value}
167
  )
168
-
169
- axis_config = response.axis_configurations[axis_name].current_zoom
170
-
171
- if axis_name == "temporal":
172
- return (
173
- axis_config.range,
174
- axis_config.explanation
175
- )
176
- elif axis_name == "geographical":
177
- map_fig = self.create_map(axis_config.locations)
178
- return (
179
- map_fig,
180
- axis_config.explanation
181
- )
182
- else: # style
183
- return (
184
- axis_config.options,
185
- axis_config.explanation
186
- )
187
-
188
- # Connect event handlers
189
- search_btn.click(
190
- fn=initial_search,
191
- inputs=[query],
192
- outputs=[
193
- time_slider,
194
- map_plot,
195
- style_select,
196
- time_explanation,
197
- geo_explanation,
198
- style_explanation
199
- ]
200
- )
201
-
202
- time_zoom.click(
203
- fn=lambda q, v: zoom_axis(q, "temporal", v),
204
- inputs=[query, time_slider],
205
- outputs=[time_slider, time_explanation]
206
- )
207
-
208
- geo_zoom.click(
209
- fn=lambda q, v: zoom_axis(q, "geographical", v),
210
- inputs=[query, map_plot],
211
- outputs=[map_plot, geo_explanation]
212
- )
213
-
214
- style_zoom.click(
215
- fn=lambda q, v: zoom_axis(q, "style", v),
216
- inputs=[query, style_select],
217
- outputs=[style_select, style_explanation]
218
  )
219
-
220
- return demo
221
 
222
  def main():
223
- """Main entry point"""
224
- print("Starting Art History Explorer...")
225
- explorer = ArtExplorer()
226
- print("Created ArtExplorer instance")
227
- demo = explorer.create_interface()
228
- print("Created interface")
229
- demo.launch(
230
- server_name="0.0.0.0",
231
- server_port=7860,
232
- share=True
233
- )
234
 
235
  if __name__ == "__main__":
236
  main()
 
 
 
1
  import gradio as gr
2
+ from art_explorer import ArtExplorer
3
+ from visualization import create_map_visualization, create_timeline_visualization
4
+ from dotenv import load_dotenv
 
 
 
5
 
6
+ # Load environment variables
7
+ load_dotenv()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
 
9
+ class ArtExplorerInterface:
10
+ def __init__(self):
11
+ self.explorer = ArtExplorer()
 
 
 
12
 
13
+ def explore(self, query: str, zoom_level: int) -> tuple:
14
+ # Get exploration results
15
+ response = self.explorer.explore_art_period(query, zoom_level)
16
+
17
+ if not response:
18
+ return "Error in exploration", None, None
19
+
20
+ # Create visualizations
21
+ map_fig = create_map_visualization(self.explorer.get_location_data())
22
+ timeline_fig = create_timeline_visualization(self.explorer.get_timeline_data())
23
+
24
+ # Format text response
25
+ text_response = f"""
26
+ Period: {response.time_period.name}
27
+ Years: {response.time_period.start_year} - {response.time_period.end_year}
28
+
29
+ Cultural Context:
30
+ {response.cultural_context}
31
+
32
+ Key Artists:
33
+ {', '.join(artist.name for artist in response.key_artists)}
34
+
35
+ Notable Works:
36
+ {', '.join(work.title for work in response.notable_works)}
37
+
38
+ Influence:
39
+ {response.influence_on_later_periods}
40
+ """
41
+
42
+ return text_response, map_fig, timeline_fig
43
 
44
+ def create_interface(self):
45
+ with gr.Blocks(title="Art History Explorer") as interface:
 
46
  gr.Markdown("# Art History Explorer")
47
 
48
  with gr.Row():
49
+ query_input = gr.Textbox(
50
  label="Enter your art history query",
51
+ placeholder="e.g., Italian Renaissance in Florence"
52
  )
53
+ zoom_level = gr.Slider(
54
+ minimum=1,
55
+ maximum=5,
56
+ value=1,
57
+ step=1,
58
+ label="Zoom Level"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  )
60
+
61
+ explore_btn = gr.Button("Explore")
62
+
63
+ with gr.Row():
64
+ text_output = gr.Textbox(
65
+ label="Exploration Results",
66
+ interactive=False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  )
68
+
69
+ with gr.Row():
70
+ map_output = gr.Plot(label="Geographic Context")
71
+ timeline_output = gr.Plot(label="Historical Timeline")
72
+
73
+ explore_btn.click(
74
+ fn=self.explore,
75
+ inputs=[query_input, zoom_level],
76
+ outputs=[text_output, map_output, timeline_output]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  )
78
+
79
+ return interface
80
 
81
  def main():
82
+ app = ArtExplorerInterface()
83
+ interface = app.create_interface()
84
+ interface.launch(share=True)
 
 
 
 
 
 
 
 
85
 
86
  if __name__ == "__main__":
87
  main()