SyedZaid-Bin-Haris commited on
Commit
195c57a
·
verified ·
1 Parent(s): 6f2b4dd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +335 -159
app.py CHANGED
@@ -5,133 +5,219 @@ import json
5
  from datetime import datetime
6
  import random
7
  import string
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
 
9
  def main():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  with gr.Blocks(theme=gr.themes.Soft(primary_hue="orange")) as demo:
11
  # Header
12
- gr.Markdown("# AI Synthesis Manager")
13
 
14
  # ID-based process handling
15
  with gr.Row():
16
  with gr.Column(scale=2):
17
  # New synthesis section
18
- gr.Markdown("## Create New Synthesis")
19
  query_input = gr.Textbox(
20
  label="Enter Query:",
21
- placeholder="What topic would you like to generate a synthesis for?",
22
  lines=2
23
  )
24
 
25
  with gr.Row():
26
- create_button = gr.Button("Generate New Synthesis ID", variant="primary")
27
- synthesis_id = gr.Textbox(label="Synthesis ID", placeholder="ID will appear here...")
28
 
29
  with gr.Column(scale=2):
30
  # Continue existing synthesis section
31
- gr.Markdown("## Continue Existing Synthesis")
32
  existing_id_input = gr.Textbox(
33
- label="Enter Existing Synthesis ID:",
34
  placeholder="Enter ID to continue from a previous session..."
35
  )
36
 
37
  with gr.Row():
38
- load_button = gr.Button("Load Synthesis State")
39
 
40
  # Synthesis status display
41
  with gr.Row(visible=False) as status_panel:
42
- gr.Markdown("## Current Synthesis Status")
43
 
44
  with gr.Column():
45
  status_query = gr.Textbox(label="Query")
46
- status_id = gr.Textbox(label="Synthesis ID")
47
 
48
  with gr.Row():
49
  status_created = gr.Textbox(label="Created", scale=1)
50
  status_updated = gr.Textbox(label="Last Updated", scale=1)
51
 
52
  with gr.Row():
53
- status_progress = gr.Slider(
54
- minimum=0, maximum=8, step=1, value=3,
55
- label="Progress (Steps Completed)"
56
- )
57
- status_cost = gr.Number(label="Cost So Far ($)", value=0.00)
58
 
59
- # Step Status Cards
60
  steps_container = gr.Row(visible=False)
61
  with steps_container:
62
- gr.Markdown("## Pipeline Steps")
63
-
64
- with gr.Column():
65
- # Step 1: Preoutline
66
- with gr.Group():
67
- gr.Markdown("### 1. Preoutline")
68
- step1_status = gr.Markdown("✅ **Completed**")
69
- with gr.Row():
70
- step1_view = gr.Button("View Results", size="sm")
71
- step1_download = gr.Button("Download", size="sm")
72
-
73
- # Step 2: Themes Generator
74
- with gr.Group():
75
- gr.Markdown("### 2. Themes Generator")
76
- step2_status = gr.Markdown("✅ **Completed**")
77
- with gr.Row():
78
- step2_view = gr.Button("View Results", size="sm")
79
- step2_download = gr.Button("Download", size="sm")
80
-
81
- # Step 3: Outline
82
- with gr.Group():
83
- gr.Markdown("### 3. Outline")
84
- step3_status = gr.Markdown("❌ **Failed** (Connection timeout)")
85
- with gr.Row():
86
- step3_retry = gr.Button("Retry Step", size="sm", variant="primary")
87
- step3_view = gr.Button("View Partial Results", size="sm")
88
- step3_download = gr.Button("Download Partial", size="sm")
89
-
90
- # Step 4: Research
91
- with gr.Group():
92
- gr.Markdown("### 4. Research")
93
- step4_status = gr.Markdown("⏳ **Waiting** (Depends on Outline)")
94
- with gr.Row():
95
- step4_force = gr.Button("Force Start", size="sm")
96
 
97
- with gr.Column():
98
- # Step 5: Thinking Ladder
99
- with gr.Group():
100
- gr.Markdown("### 5. Thinking Ladder")
101
- step5_status = gr.Markdown(" **Waiting** (Depends on Research)")
102
- with gr.Row():
103
- step5_force = gr.Button("Force Start", size="sm")
104
-
105
- # Step 6: Enhanced Outline
106
- with gr.Group():
107
- gr.Markdown("### 6. Enhanced Outline")
108
- step6_status = gr.Markdown("⏳ **Waiting** (Depends on Thinking Ladder)")
109
- with gr.Row():
110
- step6_force = gr.Button("Force Start", size="sm")
111
-
112
- # Step 7: Synthesis
113
- with gr.Group():
114
- gr.Markdown("### 7. Synthesis")
115
- step7_status = gr.Markdown("⏳ **Waiting** (Depends on Enhanced Outline)")
116
- with gr.Row():
117
- step7_force = gr.Button("Force Start", size="sm")
118
-
119
- # Step 8: Accountability
120
- with gr.Group():
121
- gr.Markdown("### 8. Accountability")
122
- step8_status = gr.Markdown("⏳ **Waiting** (Depends on Synthesis)")
123
- with gr.Row():
124
- step8_force = gr.Button("Force Start", size="sm")
125
 
126
  # Result Preview
127
  with gr.Row(visible=False) as result_panel:
128
- gr.Markdown("## Results Preview")
129
- # Removed 'interactive=False' as it's not a valid parameter for gr.JSON
130
- result_json = gr.JSON(label="Synthesis Results")
131
-
132
- with gr.Row():
133
- refresh_results = gr.Button("Refresh Results")
134
- download_final = gr.Button("Download Final Results")
 
 
 
 
 
 
 
 
 
 
 
 
135
 
136
  # Log panel
137
  with gr.Row(visible=False) as log_panel:
@@ -143,56 +229,88 @@ def main():
143
  placeholder="Process logs will appear here..."
144
  )
145
 
146
- # Mock function for generating a new synthesis ID
147
- def generate_new_id(query):
148
  if not query.strip():
149
  return "Please enter a query first", gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), ""
150
 
151
- # Generate a random ID (in real implementation, this would be more robust)
152
- synthesis_id = ''.join(random.choices(string.ascii_uppercase + string.digits, k=8))
 
 
153
 
154
  # Update UI
155
- timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
156
  return (
157
  synthesis_id,
158
  gr.update(visible=True),
159
  gr.update(visible=True),
160
  gr.update(visible=True),
161
- f"[{timestamp}] Created new synthesis with ID: {synthesis_id}\n[{timestamp}] Starting preoutline generation for query: {query}...\n",
162
  query,
163
  synthesis_id,
164
  datetime.now().strftime("%Y-%m-%d %H:%M"),
165
  datetime.now().strftime("%Y-%m-%d %H:%M"),
166
- 0.00
 
167
  )
168
 
169
- # Mock function for loading existing synthesis
170
  def load_existing(existing_id):
171
  if not existing_id.strip():
172
- return gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), "Please enter a valid synthesis ID"
 
 
 
 
 
 
 
 
 
173
 
174
- # In a real implementation, this would fetch data from AWS based on the ID
175
- # For demonstration, we'll use mock data
 
 
 
 
 
176
 
177
  # Update UI components
178
- timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
179
 
180
  return (
181
  gr.update(visible=True),
182
  gr.update(visible=True),
183
  gr.update(visible=True),
184
- f"[{timestamp}] Loaded synthesis with ID: {existing_id}\n[{timestamp}] Last step completed: Themes Generator\n[{timestamp}] Next step: Outline (previously failed)\n",
185
- "Sustainability in urban planning",
186
  existing_id,
187
- "2025-04-25 14:30",
188
- "2025-04-25 14:45",
189
- 2,
190
- 0.85
191
  )
192
 
193
  # Connect the handlers
194
  create_button.click(
195
- fn=generate_new_id,
196
  inputs=[query_input],
197
  outputs=[
198
  synthesis_id,
@@ -204,7 +322,8 @@ def main():
204
  status_id,
205
  status_created,
206
  status_updated,
207
- status_cost
 
208
  ]
209
  )
210
 
@@ -220,81 +339,138 @@ def main():
220
  status_id,
221
  status_created,
222
  status_updated,
223
- status_progress,
224
- status_cost
225
  ]
226
  )
227
 
228
- # Mock function for step retry
229
- def retry_step(id):
230
- timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
 
 
231
  return (
232
- "🟡 **In Progress**...",
233
- f"[{timestamp}] Retrying Outline step for synthesis ID: {id}\n[{timestamp}] Connecting to AWS...\n"
234
  )
235
 
236
- # Connect retry button
237
- step3_retry.click(
238
- fn=retry_step,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
239
  inputs=[status_id],
240
- outputs=[step3_status, log_output]
241
  )
242
 
243
- # Mock function for force start
244
- def force_start(step_name, id):
245
- timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
246
- return (
247
- "🟡 **Force Started**...",
248
- f"[{timestamp}] Force starting {step_name} step for synthesis ID: {id}\n[{timestamp}] Warning: This step depends on previous incomplete steps\n"
249
- )
250
-
251
- # Connect force start buttons
252
- step4_force.click(
253
- fn=lambda id: force_start("Research", id),
254
  inputs=[status_id],
255
- outputs=[step4_status, log_output]
256
  )
257
 
258
- step5_force.click(
259
- fn=lambda id: force_start("Thinking Ladder", id),
 
 
 
 
 
 
260
  inputs=[status_id],
261
- outputs=[step5_status, log_output]
262
  )
263
 
264
- # Mock view results for steps
265
- def view_step_results(step_name, id):
266
- mock_results = {
267
- "Preoutline": {
268
- "main_points": ["Sustainable urban development", "Green infrastructure", "Smart city technologies"],
269
- "key_concepts": ["Energy efficiency", "Waste management", "Public transportation"],
270
- "potential_structure": "Introduction → Current challenges → Sustainable solutions → Case studies → Conclusion"
271
- },
272
- "Themes": {
273
- "themes": ["Environmental Impact", "Economic Considerations", "Social Aspects", "Technological Integration"],
274
- "query": "Sustainability in urban planning",
275
- "focus_areas": ["Renewable energy in cities", "Waste reduction strategies", "Community involvement"]
276
- }
277
- }
278
-
279
- if step_name in mock_results:
280
- return gr.update(visible=True, value=mock_results[step_name])
281
- return gr.update(visible=True, value={"message": f"No results available for {step_name} step"})
282
-
283
- # Connect view buttons
284
- step1_view.click(
285
- fn=lambda: view_step_results("Preoutline", ""),
286
- inputs=[],
287
- outputs=[result_panel]
288
  )
289
 
290
- step2_view.click(
291
- fn=lambda: view_step_results("Themes", ""),
292
- inputs=[],
293
- outputs=[result_panel]
 
294
  )
295
 
296
  return demo
297
 
298
  if __name__ == "__main__":
 
 
 
 
 
 
 
 
 
299
  demo = main()
300
  demo.launch(debug=True)
 
5
  from datetime import datetime
6
  import random
7
  import string
8
+ import boto3
9
+ from botocore.exceptions import NoCredentialsError
10
+ from dotenv import load_dotenv
11
+
12
+ # Load environment variables with detailed error handling
13
+ def load_environment_variables():
14
+ # Try to load from .env file
15
+ load_dotenv()
16
+
17
+ # Check if critical environment variables exist
18
+ required_vars = ['AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY', 'AWS_REGION']
19
+ missing_vars = [var for var in required_vars if not os.getenv(var)]
20
+
21
+ if missing_vars:
22
+ print(f"WARNING: Missing required environment variables: {', '.join(missing_vars)}")
23
+ print("Make sure you have a .env file with these variables or they are set in your environment")
24
+ print(f"Current environment variable keys: {list(os.environ.keys())}")
25
+
26
+ # Set default values for testing/development (DO NOT USE IN PRODUCTION)
27
+ if 'AWS_REGION' in missing_vars and not os.getenv('AWS_REGION'):
28
+ os.environ['AWS_REGION'] = 'us-east-1'
29
+ print("Set default AWS_REGION to 'us-east-1' for testing purposes")
30
+ else:
31
+ print("All required environment variables are set")
32
+
33
+ # Load environment variables at startup
34
+ load_environment_variables()
35
 
36
  def main():
37
+ # Initialize AWS client with more robust error handling
38
+ def init_aws_client():
39
+ aws_access_key_id = os.getenv('AWS_ACCESS_KEY_ID')
40
+ aws_secret_access_key = os.getenv('AWS_SECRET_ACCESS_KEY')
41
+ aws_region = os.getenv('AWS_REGION')
42
+
43
+ # Print debug info about environment variables (redacted for security)
44
+ print(f"AWS_ACCESS_KEY_ID: {'*' * 5 + aws_access_key_id[-4:] if aws_access_key_id else 'Not set'}")
45
+ print(f"AWS_SECRET_ACCESS_KEY: {'*' * 10 if aws_secret_access_key else 'Not set'}")
46
+ print(f"AWS_REGION: {aws_region or 'Not set'}")
47
+
48
+ if not all([aws_access_key_id, aws_secret_access_key, aws_region]):
49
+ missing = []
50
+ if not aws_access_key_id: missing.append("AWS_ACCESS_KEY_ID")
51
+ if not aws_secret_access_key: missing.append("AWS_SECRET_ACCESS_KEY")
52
+ if not aws_region: missing.append("AWS_REGION")
53
+
54
+ return None, f"AWS credentials not found in environment variables: Missing {', '.join(missing)}"
55
+
56
+ try:
57
+ s3_client = boto3.client(
58
+ 's3',
59
+ aws_access_key_id=aws_access_key_id,
60
+ aws_secret_access_key=aws_secret_access_key,
61
+ region_name=aws_region
62
+ )
63
+
64
+ # Test the connection with a simple operation
65
+ try:
66
+ s3_client.list_buckets()
67
+ print("Successfully connected to AWS S3")
68
+ except Exception as e:
69
+ print(f"Warning: AWS credentials may be invalid: {str(e)}")
70
+
71
+ return s3_client, "AWS client initialized successfully"
72
+ except Exception as e:
73
+ return None, f"Error initializing AWS client: {str(e)}"
74
+
75
+ # Function to fetch outline data from AWS
76
+ def fetch_outline_data(outline_id, bucket_name="dediro-backup"):
77
+ s3_client, message = init_aws_client()
78
+ if not s3_client:
79
+ return None, message
80
+
81
+ try:
82
+ # Construct the S3 key with the correct path
83
+ s3_key = f"Outline-Agent/agent_steps/{outline_id}_outline.json"
84
+
85
+ # Debug info
86
+ log_message = f"Looking for file at: {bucket_name}/{s3_key}"
87
+ print(log_message)
88
+
89
+ # Try to get the object from S3
90
+ try:
91
+ response = s3_client.get_object(Bucket=bucket_name, Key=s3_key)
92
+ outline_data = json.loads(response['Body'].read().decode('utf-8'))
93
+ return outline_data, f"Successfully retrieved outline data for ID: {outline_id}"
94
+ except s3_client.exceptions.NoSuchKey:
95
+ # If exact key not found, try to list objects with similar prefix
96
+ prefix = f"Outline-Agent/agent_steps/{outline_id}"
97
+ response = s3_client.list_objects_v2(
98
+ Bucket=bucket_name,
99
+ Prefix=prefix
100
+ )
101
+
102
+ if 'Contents' in response:
103
+ # Find the first outline JSON file
104
+ outline_files = [obj['Key'] for obj in response['Contents']
105
+ if '_outline.json' in obj['Key']]
106
+
107
+ if outline_files:
108
+ # Get the first matching outline file
109
+ outline_key = outline_files[0]
110
+ print(f"Found alternative file: {outline_key}")
111
+ response = s3_client.get_object(Bucket=bucket_name, Key=outline_key)
112
+ outline_data = json.loads(response['Body'].read().decode('utf-8'))
113
+ return outline_data, f"Found similar outline: {outline_key}"
114
+
115
+ return None, f"No outline data found for ID: {outline_id}"
116
+
117
+ except NoCredentialsError:
118
+ return None, "AWS credentials not available"
119
+ except Exception as e:
120
+ return None, f"Error retrieving outline data: {str(e)}"
121
+
122
+ # Helper function to extract outline from potentially nested structure
123
+ def extract_outline_from_data(data):
124
+ """Extract outline data from potentially nested structures"""
125
+ if not data:
126
+ return None
127
+
128
+ # Try different possible paths to the outline data
129
+ if isinstance(data, dict):
130
+ if "outline" in data:
131
+ return data["outline"]
132
+ elif "data" in data and "outline" in data["data"]:
133
+ return data["data"]["outline"]
134
+
135
+ # Check if this looks like an outline directly (has title and themes)
136
+ if "title" in data and "themes" in data:
137
+ return data
138
+
139
+ # Return the original if we can't determine the structure
140
+ return data
141
+
142
  with gr.Blocks(theme=gr.themes.Soft(primary_hue="orange")) as demo:
143
  # Header
144
+ gr.Markdown("# AI Outline Generator")
145
 
146
  # ID-based process handling
147
  with gr.Row():
148
  with gr.Column(scale=2):
149
  # New synthesis section
150
+ gr.Markdown("## Create New Outline")
151
  query_input = gr.Textbox(
152
  label="Enter Query:",
153
+ placeholder="What topic would you like to generate an outline for?",
154
  lines=2
155
  )
156
 
157
  with gr.Row():
158
+ create_button = gr.Button("Generate New Outline", variant="primary")
159
+ synthesis_id = gr.Textbox(label="Outline ID", placeholder="ID will appear here...")
160
 
161
  with gr.Column(scale=2):
162
  # Continue existing synthesis section
163
+ gr.Markdown("## Continue Existing Outline")
164
  existing_id_input = gr.Textbox(
165
+ label="Enter Existing Outline ID:",
166
  placeholder="Enter ID to continue from a previous session..."
167
  )
168
 
169
  with gr.Row():
170
+ load_button = gr.Button("Load Outline")
171
 
172
  # Synthesis status display
173
  with gr.Row(visible=False) as status_panel:
174
+ gr.Markdown("## Current Outline Status")
175
 
176
  with gr.Column():
177
  status_query = gr.Textbox(label="Query")
178
+ status_id = gr.Textbox(label="Outline ID")
179
 
180
  with gr.Row():
181
  status_created = gr.Textbox(label="Created", scale=1)
182
  status_updated = gr.Textbox(label="Last Updated", scale=1)
183
 
184
  with gr.Row():
185
+ status_cost = gr.Number(label="Cost ($)", value=0.00)
 
 
 
 
186
 
187
+ # Step Status Card
188
  steps_container = gr.Row(visible=False)
189
  with steps_container:
190
+ gr.Markdown("## Outline Status")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
191
 
192
+ with gr.Group():
193
+ gr.Markdown("### Outline Generator")
194
+ outline_status = gr.Markdown("⏳ **In Progress**...")
195
+ with gr.Row():
196
+ outline_retry = gr.Button("Retry", size="sm", variant="primary")
197
+ outline_view = gr.Button("View Results", size="sm")
198
+ outline_download = gr.Button("Download", size="sm")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
199
 
200
  # Result Preview
201
  with gr.Row(visible=False) as result_panel:
202
+ gr.Markdown("## Outline Preview")
203
+ with gr.Column():
204
+ # Add a text area to display any errors or messages
205
+ result_message = gr.Textbox(
206
+ label="Status",
207
+ value="",
208
+ visible=False,
209
+ lines=2
210
+ )
211
+ # Keep the JSON component for the outline data
212
+ result_json = gr.JSON(
213
+ label="Outline Results",
214
+ value={}
215
+ )
216
+
217
+ # Add buttons for refresh and download
218
+ with gr.Row():
219
+ refresh_results = gr.Button("Refresh Results")
220
+ download_results = gr.Button("Download Results")
221
 
222
  # Log panel
223
  with gr.Row(visible=False) as log_panel:
 
229
  placeholder="Process logs will appear here..."
230
  )
231
 
232
+ # Function for generating a new outline
233
+ def generate_new_outline(query):
234
  if not query.strip():
235
  return "Please enter a query first", gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), ""
236
 
237
+ # Generate a timestamp-based ID (in real implementation, this would match your AWS naming pattern)
238
+ timestamp = str(int(time.time()))
239
+ formatted_query = query.replace(" ", "_")
240
+ synthesis_id = f"{timestamp}_{formatted_query}"
241
 
242
  # Update UI
243
+ log_timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
244
  return (
245
  synthesis_id,
246
  gr.update(visible=True),
247
  gr.update(visible=True),
248
  gr.update(visible=True),
249
+ f"[{log_timestamp}] Created new outline with ID: {synthesis_id}\n[{log_timestamp}] Starting outline generation for query: {query}...\n",
250
  query,
251
  synthesis_id,
252
  datetime.now().strftime("%Y-%m-%d %H:%M"),
253
  datetime.now().strftime("%Y-%m-%d %H:%M"),
254
+ 0.00,
255
+ "🟡 **In Progress**..."
256
  )
257
 
258
+ # Function for loading existing outline
259
  def load_existing(existing_id):
260
  if not existing_id.strip():
261
+ return gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), "Please enter a valid outline ID"
262
+
263
+ # Now we actually fetch the data from AWS S3
264
+ outline_data, message = fetch_outline_data(existing_id)
265
+
266
+ if not outline_data:
267
+ return gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), f"Error: {message}"
268
+
269
+ # Extract the actual outline
270
+ actual_outline = extract_outline_from_data(outline_data)
271
 
272
+ # Extract query from ID (assuming ID format: timestamp_formatted_query)
273
+ parts = existing_id.split('_', 1)
274
+ if len(parts) < 2:
275
+ return gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), "Invalid outline ID format"
276
+
277
+ # Reconstruct the original query
278
+ original_query = parts[1].replace("_", " ")
279
 
280
  # Update UI components
281
+ log_timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
282
+
283
+ # Determine actual status based on outline data
284
+ outline_status_text = "✅ **Completed**" # Default to completed if we found data
285
+
286
+ # Get creation time from timestamp in ID
287
+ try:
288
+ creation_time = datetime.fromtimestamp(int(parts[0])).strftime("%Y-%m-%d %H:%M")
289
+ except:
290
+ creation_time = "Unknown"
291
+
292
+ # Extract cost if available in the data
293
+ cost = 0.00
294
+ if isinstance(outline_data, dict):
295
+ if "metrics" in outline_data:
296
+ cost = outline_data.get("metrics", {}).get("cost", 0.00)
297
 
298
  return (
299
  gr.update(visible=True),
300
  gr.update(visible=True),
301
  gr.update(visible=True),
302
+ f"[{log_timestamp}] Loaded outline with ID: {existing_id}\n[{log_timestamp}] {message}\n",
303
+ original_query,
304
  existing_id,
305
+ creation_time,
306
+ datetime.now().strftime("%Y-%m-%d %H:%M"), # Last updated is now
307
+ cost,
308
+ outline_status_text
309
  )
310
 
311
  # Connect the handlers
312
  create_button.click(
313
+ fn=generate_new_outline,
314
  inputs=[query_input],
315
  outputs=[
316
  synthesis_id,
 
322
  status_id,
323
  status_created,
324
  status_updated,
325
+ status_cost,
326
+ outline_status
327
  ]
328
  )
329
 
 
339
  status_id,
340
  status_created,
341
  status_updated,
342
+ status_cost,
343
+ outline_status
344
  ]
345
  )
346
 
347
+ # Function for retrying outline generation
348
+ def retry_outline(outline_id):
349
+ # This would call your OutlineAgent with force_rerun=True
350
+ # For now, just update the UI
351
+ log_timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
352
  return (
353
+ "🟡 **Retrying**...",
354
+ f"[{log_timestamp}] Retrying outline generation for ID: {outline_id}\n[{log_timestamp}] Connecting to AWS...\n"
355
  )
356
 
357
+ # Function to view outline results
358
+ def view_outline_results(outline_id):
359
+ # Fetch real data from AWS
360
+ outline_data, message = fetch_outline_data(outline_id)
361
+
362
+ if not outline_data:
363
+ # Return a message if data not found
364
+ return gr.update(visible=True), {"error": message}
365
+
366
+ # Print the raw data for debugging
367
+ print(f"Raw outline data: {json.dumps(outline_data, indent=2)[:1000]}...")
368
+
369
+ # Step by step extraction with verbose logging
370
+ try:
371
+ # First, check if "outline" is directly in the data
372
+ if "outline" in outline_data:
373
+ print("Found 'outline' key at top level")
374
+ actual_outline = outline_data["outline"]
375
+ # Then check if it's in a nested "data" object
376
+ elif "data" in outline_data and "outline" in outline_data["data"]:
377
+ print("Found 'outline' key inside 'data'")
378
+ actual_outline = outline_data["data"]["outline"]
379
+ # Next, try the most common pattern seen in OutlineAgent
380
+ elif "models" in outline_data and "prompts" in outline_data and "query" in outline_data:
381
+ print("Found OutlineAgent format with 'models', 'prompts', 'query'")
382
+ # In this case, we want the actual outline in the data structure
383
+ if isinstance(outline_data.get("outline", None), dict):
384
+ actual_outline = outline_data["outline"]
385
+ print("Using 'outline' field in OutlineAgent format")
386
+ else:
387
+ # Just use the whole data
388
+ actual_outline = outline_data
389
+ print("Using complete OutlineAgent data")
390
+ # If none of those work, check if this looks like an outline directly
391
+ elif "title" in outline_data and "themes" in outline_data:
392
+ print("Found direct outline structure with 'title' and 'themes'")
393
+ actual_outline = outline_data
394
+ else:
395
+ # As a last resort, just use the whole data
396
+ print("Could not identify specific outline structure, using complete data")
397
+ actual_outline = outline_data
398
+
399
+ # Ensure we're working with a non-empty dictionary
400
+ if not actual_outline or not isinstance(actual_outline, dict):
401
+ print(f"Warning: Extracted outline is not a valid dictionary: {actual_outline}")
402
+ # If it's not, pass the original data
403
+ actual_outline = {"warning": "Could not extract proper outline structure", "data": str(outline_data)[:1000]}
404
+
405
+ # Log what we found
406
+ print(f"Final outline structure: {json.dumps(actual_outline, indent=2)[:500]}...")
407
+
408
+ # Make the result panel visible and return the data for the JSON component
409
+ return gr.update(visible=True), actual_outline
410
+
411
+ except Exception as e:
412
+ # If there's an error processing the data, log it and return the raw data
413
+ error_msg = f"Error processing outline data: {str(e)}"
414
+ print(error_msg)
415
+ traceback_info = __import__('traceback').format_exc()
416
+ print(f"Traceback: {traceback_info}")
417
+
418
+ # Return both the error and the raw data for debugging
419
+ return gr.update(visible=True), {
420
+ "error": error_msg,
421
+ "raw_data": str(outline_data)[:1000]
422
+ }
423
+
424
+ # Connect outline action buttons
425
+ outline_retry.click(
426
+ fn=retry_outline,
427
  inputs=[status_id],
428
+ outputs=[outline_status, log_output]
429
  )
430
 
431
+ outline_view.click(
432
+ fn=view_outline_results,
 
 
 
 
 
 
 
 
 
433
  inputs=[status_id],
434
+ outputs=[result_panel, result_json] # Now returning both visibility update and data
435
  )
436
 
437
+ # Function for actual download (in production)
438
+ def download_outline(outline_id):
439
+ # For now, just log that we would download
440
+ log_timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
441
+ return f"[{log_timestamp}] Downloading outline with ID: {outline_id}...\n"
442
+
443
+ outline_download.click(
444
+ fn=download_outline,
445
  inputs=[status_id],
446
+ outputs=[log_output]
447
  )
448
 
449
+ # Connect refresh button to view function
450
+ refresh_results.click(
451
+ fn=view_outline_results,
452
+ inputs=[status_id],
453
+ outputs=[result_panel, result_json] # Updated to match the view function outputs
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
454
  )
455
 
456
+ # Connect download results button
457
+ download_results.click(
458
+ fn=download_outline,
459
+ inputs=[status_id],
460
+ outputs=[log_output]
461
  )
462
 
463
  return demo
464
 
465
  if __name__ == "__main__":
466
+ # Check for .env file existence and provide guidance if not found
467
+ env_file_path = '.env'
468
+ if not os.path.exists(env_file_path):
469
+ print("\n" + "="*80)
470
+ print("WARNING: .env file not found!")
471
+
472
+ print("="*80 + "\n")
473
+
474
+ # Initialize the demo
475
  demo = main()
476
  demo.launch(debug=True)