rairo commited on
Commit
5151b7c
·
verified ·
1 Parent(s): e3aa5e7

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +19 -77
main.py CHANGED
@@ -354,6 +354,8 @@ def delete_sozo_project(project_id):
354
  logger.error(f"CRITICAL ERROR during delete project {project_id}: {traceback.format_exc()}")
355
  return jsonify({'error': str(e)}), 500
356
 
 
 
357
  @app.route('/api/sozo/projects/<string:project_id>/generate-report', methods=['POST'])
358
  def generate_sozo_report(project_id):
359
  logger.info(f"POST /api/sozo/projects/{project_id}/generate-report - Generating report")
@@ -365,22 +367,17 @@ def generate_sozo_report(project_id):
365
  logger.warning(f"Unauthorized access attempt to generate report for project {project_id}")
366
  return jsonify({'error': 'Unauthorized'}), 401
367
 
368
- logger.info(f"User {uid} generating report for project {project_id}")
369
-
370
  project_ref = db.reference(f'sozo_projects/{project_id}')
371
  project_data = project_ref.get()
372
 
373
  if not project_data or project_data.get('uid') != uid:
374
- logger.warning(f"Project {project_id} not found or unauthorized for user {uid}")
375
  return jsonify({'error': 'Project not found or unauthorized'}), 404
376
 
377
- logger.info(f"Project {project_id} validated for user {uid}")
378
-
379
- blob_path = "/".join(project_data['originalDataUrl'].split('/')[4:])
380
  blob = bucket.blob(blob_path)
381
  file_bytes = blob.download_as_bytes()
382
 
383
- # This function is the source of the inconsistent response
384
  draft_data = generate_report_draft(
385
  io.BytesIO(file_bytes),
386
  project_data['originalFilename'],
@@ -390,67 +387,17 @@ def generate_sozo_report(project_id):
390
  bucket
391
  )
392
 
393
- # Initialize variables from the draft data, providing safe defaults
394
- final_raw_md = draft_data.get('raw_md', '')
395
- final_chart_urls = draft_data.get('chartUrls', {})
396
-
397
- # CORE LOGIC: If raw_md is empty BUT we received chart_specs, it means the
398
- # primary markdown generation failed. We must reconstruct it to ensure the
399
- # user sees their report.
400
- if not final_raw_md.strip() and draft_data.get('report_content', {}).get('chart_specs'):
401
- logger.warning(f"raw_md was empty for project {project_id}. Reconstructing from chart_specs.")
402
-
403
- # 1. Reconstruct the Markdown String
404
- final_raw_md = "## Executive Summary\n\nThis report provides a visual analysis of the key metrics from the provided dataset. Each section below highlights a specific insight through a detailed chart.\n\n"
405
- chart_specs_list = draft_data['report_content']['chart_specs']
406
-
407
- for spec_data in chart_specs_list:
408
- title = spec_data.get('title', 'Chart')
409
- final_raw_md += f"### {title}\n\n"
410
- final_raw_md += f"<generate_chart: \"{title}\">\n\n"
411
-
412
- # 2. Reconstruct the Chart URLs (as they will also be missing)
413
- logger.warning(f"Reconstructing missing chart URLs for project {project_id}.")
414
- df = load_dataframe_safely(io.BytesIO(file_bytes), project_data['originalFilename'])
415
- llm = ChatGoogleGenerativeAI(model="gemini-2.0-flash", google_api_key=os.getenv("GOOGLE_API_KEY"), temperature=0.1)
416
-
417
- for spec_data in chart_specs_list:
418
- try:
419
- spec_title = spec_data.get('title')
420
- # Create a ChartSpecification instance from the dictionary data
421
- chart_spec = ChartSpecification(
422
- chart_type=spec_data.get('chart_type'),
423
- title=spec_data.get('title'),
424
- x_col=spec_data.get('x_col'),
425
- y_col=spec_data.get('y_col'),
426
- agg_method=spec_data.get('agg_method'),
427
- top_n=spec_data.get('top_n')
428
- )
429
-
430
- with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as temp_file:
431
- img_path = Path(temp_file.name)
432
- if execute_chart_spec(chart_spec, df, img_path):
433
- blob_name = f"sozo_projects/{uid}/{project_id}/charts/{uuid.uuid4().hex}.png"
434
- chart_blob = bucket.blob(blob_name)
435
- chart_blob.upload_from_filename(str(img_path))
436
- final_chart_urls[spec_title] = chart_blob.public_url
437
- logger.info(f"Re-generated and uploaded chart '{spec_title}' to {chart_blob.public_url}")
438
- except Exception as chart_gen_error:
439
- logger.error(f"Error re-generating chart '{spec_data.get('title')}': {chart_gen_error}")
440
- finally:
441
- if 'img_path' in locals() and os.path.exists(img_path):
442
- os.unlink(img_path)
443
-
444
- # Prepare the final, corrected data for Firebase
445
  update_data = {
446
  'status': 'draft',
447
- 'rawMarkdown': final_raw_md,
448
- 'chartUrls': final_chart_urls
 
449
  }
450
 
451
  project_ref.update(update_data)
452
 
453
- logger.info(f"Project {project_id} successfully updated with draft data. Markdown length: {len(final_raw_md)}")
454
 
455
  return jsonify({
456
  'success': True,
@@ -458,15 +405,10 @@ def generate_sozo_report(project_id):
458
  }), 200
459
 
460
  except Exception as e:
461
- logger.error(f"CRITICAL error generating report for project {project_id}: {str(e)}")
462
- logger.error(f"Traceback: {traceback.format_exc()}")
463
- db.reference(f'sozo_projects/{project_id}').update({
464
- 'status': 'failed',
465
- 'error': str(e)
466
- })
467
  return jsonify({'error': str(e)}), 500
468
 
469
- # In app.py
470
 
471
  @app.route('/api/sozo/projects/<string:project_id>/generate-video', methods=['POST'])
472
  def generate_sozo_video(project_id):
@@ -481,23 +423,23 @@ def generate_sozo_video(project_id):
481
 
482
  data = request.get_json()
483
  voice_model = data.get('voice_model', 'aura-2-andromeda-en')
484
- if voice_model not in ['aura-2-andromeda-en', 'aura-2-orpheus-en']: return jsonify({'error': 'Invalid voice model specified'}), 400
485
 
486
  project_ref.update({'status': 'generating_video'})
487
 
488
- blob_path = "/".join(project_data['originalDataUrl'].split('/')[4:])
489
  blob = bucket.blob(blob_path)
490
  file_bytes = blob.download_as_bytes()
491
  df = load_dataframe_safely(io.BytesIO(file_bytes), project_data['originalFilename'])
492
 
493
- # --- THIS IS THE CORRECTED FUNCTION CALL ---
494
  video_url = generate_video_from_project(
495
  df,
496
- project_data.get('rawMarkdown', ''), # Use the correct key for the markdown
497
- uid, # ADDED missing uid
498
- project_id, # ADDED missing project_id
499
- voice_model, # Now in the correct position
500
- bucket # ADDED missing bucket
 
501
  )
502
 
503
  if not video_url: raise Exception("Video generation failed in core function.")
 
354
  logger.error(f"CRITICAL ERROR during delete project {project_id}: {traceback.format_exc()}")
355
  return jsonify({'error': str(e)}), 500
356
 
357
+ # In main.py
358
+
359
  @app.route('/api/sozo/projects/<string:project_id>/generate-report', methods=['POST'])
360
  def generate_sozo_report(project_id):
361
  logger.info(f"POST /api/sozo/projects/{project_id}/generate-report - Generating report")
 
367
  logger.warning(f"Unauthorized access attempt to generate report for project {project_id}")
368
  return jsonify({'error': 'Unauthorized'}), 401
369
 
 
 
370
  project_ref = db.reference(f'sozo_projects/{project_id}')
371
  project_data = project_ref.get()
372
 
373
  if not project_data or project_data.get('uid') != uid:
 
374
  return jsonify({'error': 'Project not found or unauthorized'}), 404
375
 
376
+ blob_path = f"sozo_projects/{uid}/{project_id}/data{Path(project_data['originalFilename']).suffix}"
 
 
377
  blob = bucket.blob(blob_path)
378
  file_bytes = blob.download_as_bytes()
379
 
380
+ # This function now returns data_context, which we need to capture
381
  draft_data = generate_report_draft(
382
  io.BytesIO(file_bytes),
383
  project_data['originalFilename'],
 
387
  bucket
388
  )
389
 
390
+ # **CORRECTION HERE: Save the data_context to Firebase**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
391
  update_data = {
392
  'status': 'draft',
393
+ 'rawMarkdown': draft_data.get('raw_md'),
394
+ 'chartUrls': draft_data.get('chartUrls'),
395
+ 'dataContext': draft_data.get('data_context') # Save the context for the video generator
396
  }
397
 
398
  project_ref.update(update_data)
399
 
400
+ logger.info(f"Project {project_id} successfully updated with draft data.")
401
 
402
  return jsonify({
403
  'success': True,
 
405
  }), 200
406
 
407
  except Exception as e:
408
+ logger.error(f"CRITICAL error generating report for project {project_id}: {traceback.format_exc()}")
409
+ db.reference(f'sozo_projects/{project_id}').update({'status': 'failed', 'error': str(e)})
 
 
 
 
410
  return jsonify({'error': str(e)}), 500
411
 
 
412
 
413
  @app.route('/api/sozo/projects/<string:project_id>/generate-video', methods=['POST'])
414
  def generate_sozo_video(project_id):
 
423
 
424
  data = request.get_json()
425
  voice_model = data.get('voice_model', 'aura-2-andromeda-en')
 
426
 
427
  project_ref.update({'status': 'generating_video'})
428
 
429
+ blob_path = f"sozo_projects/{uid}/{project_id}/data{Path(project_data['originalFilename']).suffix}"
430
  blob = bucket.blob(blob_path)
431
  file_bytes = blob.download_as_bytes()
432
  df = load_dataframe_safely(io.BytesIO(file_bytes), project_data['originalFilename'])
433
 
434
+ # **CORRECTION HERE: Pass the required 'data_context' argument**
435
  video_url = generate_video_from_project(
436
  df,
437
+ project_data.get('rawMarkdown', ''),
438
+ project_data.get('dataContext', {}), # Load the context from the project
439
+ uid,
440
+ project_id,
441
+ voice_model,
442
+ bucket # The missing argument from your error message
443
  )
444
 
445
  if not video_url: raise Exception("Video generation failed in core function.")