rairo commited on
Commit
192d9d2
·
verified ·
1 Parent(s): 2e4212f

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +114 -33
main.py CHANGED
@@ -798,12 +798,23 @@ def approve_project_plan(project_id):
798
  logger.info(f"[PROJECT APPROVAL] Selected option: {selected_option}")
799
 
800
  image_download_start = time.time()
801
- response = requests.get(project_data['userImageURL'])
 
 
 
 
 
 
802
  image_download_time = time.time() - image_download_start
803
  logger.info(f"[PROJECT APPROVAL] Image download completed in {image_download_time:.3f}s, size: {len(response.content)} bytes")
804
 
805
  image_processing_start = time.time()
806
- pil_image = Image.open(io.BytesIO(response.content)).convert('RGB')
 
 
 
 
 
807
  image_processing_time = time.time() - image_processing_start
808
  logger.info(f"[PROJECT APPROVAL] Image processing completed in {image_processing_time:.3f}s")
809
 
@@ -860,19 +871,77 @@ def approve_project_plan(project_id):
860
  parsing_time = time.time() - parsing_start
861
  logger.info(f"[PROJECT APPROVAL] Response parsing completed in {parsing_time:.3f}s, found {len(inline_images)} images")
862
 
863
- # Text extraction timing
864
  extraction_start = time.time()
865
- tools_section = re.search(r"TOOLS AND MATERIALS:\s*(.*?)\s*STEPS:", combined_text, re.DOTALL).group(1).strip()
866
- steps_section = re.search(r"STEPS:\s*(.*)", combined_text, re.DOTALL).group(1).strip()
867
 
868
- tools_list = [line.strip("- ").strip() for line in tools_section.split('\n') if line.strip()]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
869
  parsed_steps = parse_numbered_steps(steps_section)
 
 
 
 
 
 
 
 
 
 
 
 
870
  extraction_time = time.time() - extraction_start
871
  logger.info(f"[PROJECT APPROVAL] Text extraction completed in {extraction_time:.3f}s, tools: {len(tools_list)}, steps: {len(parsed_steps)}")
872
 
873
  if len(parsed_steps) != len(inline_images):
874
  logger.error(f"[PROJECT APPROVAL] ERROR: AI response mismatch - Steps: {len(parsed_steps)}, Images: {len(inline_images)}")
875
- return jsonify({'error': 'AI response mismatch: Steps and images do not match.'}), 500
 
 
 
 
 
 
 
876
 
877
  # Step processing timing
878
  step_processing_start = time.time()
@@ -883,30 +952,42 @@ def approve_project_plan(project_id):
883
  for i, step_info in enumerate(parsed_steps):
884
  logger.info(f"[PROJECT APPROVAL] Processing step {i+1}/{len(parsed_steps)}")
885
 
886
- # Image upload timing
887
- image_upload_start = time.time()
888
- img_byte_arr = io.BytesIO()
889
- inline_images[i].save(img_byte_arr, format='JPEG', optimize=True, quality=70)
890
- img_path = f"users/{uid}/projects/{project_id}/steps/step_{i+1}_image.jpg"
891
- img_url = upload_to_storage(img_byte_arr.getvalue(), img_path, 'image/jpeg')
892
- image_upload_time = time.time() - image_upload_start
893
- total_upload_time += image_upload_time
894
- logger.info(f"[PROJECT APPROVAL] Step {i+1} image upload completed in {image_upload_time:.3f}s")
895
-
896
- # TTS generation timing
897
- tts_start = time.time()
898
- narration_url = generate_tts_audio_and_upload(step_info['text'], uid, project_id, i + 1)
899
- tts_time = time.time() - tts_start
900
- total_tts_time += tts_time
901
- logger.info(f"[PROJECT APPROVAL] Step {i+1} TTS generation completed in {tts_time:.3f}s")
902
-
903
- step_info.update({
904
- "imageUrl": img_url,
905
- "narrationUrl": narration_url,
906
- "isDone": False,
907
- "notes": ""
908
- })
909
- final_steps.append(step_info)
 
 
 
 
 
 
 
 
 
 
 
 
910
 
911
  step_processing_time = time.time() - step_processing_start
912
  logger.info(f"[PROJECT APPROVAL] All steps processing completed in {step_processing_time:.3f}s")
@@ -921,7 +1002,7 @@ def approve_project_plan(project_id):
921
  "selectedOption": selected_option or ""
922
  }
923
  project_ref.update(update_data)
924
- logger.info(f"[PROJECT APPROVAL] uodating data in db: {update_data}")
925
  db_update_time = time.time() - db_update_start
926
  logger.info(f"[PROJECT APPROVAL] Database update completed in {db_update_time:.3f}s")
927
 
@@ -967,7 +1048,7 @@ def approve_project_plan(project_id):
967
  logger.error(f"[PROJECT APPROVAL] Project ID: {project_id}, User ID: {uid}")
968
  import traceback
969
  logger.error(f"[PROJECT APPROVAL] Full traceback: {traceback.format_exc()}")
970
- return jsonify({'error': str(e)}), 500
971
 
972
  @app.route('/api/projects', methods=['GET'])
973
  def list_projects():
 
798
  logger.info(f"[PROJECT APPROVAL] Selected option: {selected_option}")
799
 
800
  image_download_start = time.time()
801
+ try:
802
+ response = requests.get(project_data['userImageURL'], timeout=30)
803
+ response.raise_for_status()
804
+ except requests.RequestException as e:
805
+ logger.error(f"[PROJECT APPROVAL] ERROR: Image download failed: {e}")
806
+ return jsonify({'error': 'Failed to download project image'}), 500
807
+
808
  image_download_time = time.time() - image_download_start
809
  logger.info(f"[PROJECT APPROVAL] Image download completed in {image_download_time:.3f}s, size: {len(response.content)} bytes")
810
 
811
  image_processing_start = time.time()
812
+ try:
813
+ pil_image = Image.open(io.BytesIO(response.content)).convert('RGB')
814
+ except Exception as e:
815
+ logger.error(f"[PROJECT APPROVAL] ERROR: Image processing failed: {e}")
816
+ return jsonify({'error': 'Failed to process project image'}), 500
817
+
818
  image_processing_time = time.time() - image_processing_start
819
  logger.info(f"[PROJECT APPROVAL] Image processing completed in {image_processing_time:.3f}s")
820
 
 
871
  parsing_time = time.time() - parsing_start
872
  logger.info(f"[PROJECT APPROVAL] Response parsing completed in {parsing_time:.3f}s, found {len(inline_images)} images")
873
 
874
+ # Text extraction timing with robust error handling
875
  extraction_start = time.time()
 
 
876
 
877
+ # Add debug logging to see what the AI actually returned
878
+ logger.info(f"[PROJECT APPROVAL] AI Response structure check:")
879
+ logger.info(f"[PROJECT APPROVAL] Full response length: {len(combined_text)}")
880
+ logger.info(f"[PROJECT APPROVAL] Contains 'TOOLS AND MATERIALS': {'TOOLS AND MATERIALS' in combined_text.upper()}")
881
+ logger.info(f"[PROJECT APPROVAL] Contains 'STEPS': {'STEPS' in combined_text.upper()}")
882
+ logger.info(f"[PROJECT APPROVAL] Response preview: {combined_text[:300]}...")
883
+
884
+ # More robust regex patterns with error handling - updated for your production format
885
+ tools_match = re.search(r"TOOLS AND MATERIALS:\s*(.*?)\s*(?=STEPS\(|STEPS:|$)", combined_text, re.DOTALL | re.IGNORECASE)
886
+ steps_match = re.search(r"STEPS\([^)]*\):\s*(.*)|STEPS:\s*(.*)", combined_text, re.DOTALL | re.IGNORECASE)
887
+
888
+ if not tools_match:
889
+ logger.error(f"[PROJECT APPROVAL] ERROR: Could not find TOOLS AND MATERIALS section in AI response")
890
+ logger.error(f"[PROJECT APPROVAL] AI Response full text: {combined_text}")
891
+ return jsonify({'error': 'AI response format error: Could not parse tools section'}), 500
892
+
893
+ if not steps_match:
894
+ logger.error(f"[PROJECT APPROVAL] ERROR: Could not find STEPS section in AI response")
895
+ logger.error(f"[PROJECT APPROVAL] AI Response full text: {combined_text}")
896
+ return jsonify({'error': 'AI response format error: Could not parse steps section'}), 500
897
+
898
+ tools_section = tools_match.group(1).strip()
899
+ steps_section = (steps_match.group(1) or steps_match.group(2)).strip() if steps_match else ""
900
+
901
+ # Additional validation
902
+ if not tools_section:
903
+ logger.error(f"[PROJECT APPROVAL] ERROR: Empty tools section found")
904
+ return jsonify({'error': 'AI response format error: Empty tools section'}), 500
905
+
906
+ if not steps_section:
907
+ logger.error(f"[PROJECT APPROVAL] ERROR: Empty steps section found")
908
+ return jsonify({'error': 'AI response format error: Empty steps section'}), 500
909
+
910
+ tools_list = [line.strip("- ").strip() for line in tools_section.split('\n') if line.strip() and not line.strip().startswith('-')]
911
+ # Also include lines that start with dashes
912
+ dash_tools = [line.strip("- ").strip() for line in tools_section.split('\n') if line.strip().startswith('-')]
913
+ tools_list.extend(dash_tools)
914
+
915
+ # Remove duplicates while preserving order
916
+ seen = set()
917
+ tools_list = [x for x in tools_list if not (x in seen or seen.add(x))]
918
+
919
  parsed_steps = parse_numbered_steps(steps_section)
920
+
921
+ # Validate parsed results
922
+ if not tools_list:
923
+ logger.error(f"[PROJECT APPROVAL] ERROR: No tools parsed from response")
924
+ logger.error(f"[PROJECT APPROVAL] Tools section was: {tools_section}")
925
+ return jsonify({'error': 'AI response format error: No tools found'}), 500
926
+
927
+ if not parsed_steps:
928
+ logger.error(f"[PROJECT APPROVAL] ERROR: No steps parsed from response")
929
+ logger.error(f"[PROJECT APPROVAL] Steps section was: {steps_section}")
930
+ return jsonify({'error': 'AI response format error: No steps found'}), 500
931
+
932
  extraction_time = time.time() - extraction_start
933
  logger.info(f"[PROJECT APPROVAL] Text extraction completed in {extraction_time:.3f}s, tools: {len(tools_list)}, steps: {len(parsed_steps)}")
934
 
935
  if len(parsed_steps) != len(inline_images):
936
  logger.error(f"[PROJECT APPROVAL] ERROR: AI response mismatch - Steps: {len(parsed_steps)}, Images: {len(inline_images)}")
937
+ # Try to handle the mismatch gracefully
938
+ min_length = min(len(parsed_steps), len(inline_images))
939
+ if min_length > 0:
940
+ logger.info(f"[PROJECT APPROVAL] Attempting to proceed with {min_length} steps/images")
941
+ parsed_steps = parsed_steps[:min_length]
942
+ inline_images = inline_images[:min_length]
943
+ else:
944
+ return jsonify({'error': 'AI response mismatch: No valid steps and images found.'}), 500
945
 
946
  # Step processing timing
947
  step_processing_start = time.time()
 
952
  for i, step_info in enumerate(parsed_steps):
953
  logger.info(f"[PROJECT APPROVAL] Processing step {i+1}/{len(parsed_steps)}")
954
 
955
+ try:
956
+ # Image upload timing
957
+ image_upload_start = time.time()
958
+ img_byte_arr = io.BytesIO()
959
+ inline_images[i].save(img_byte_arr, format='JPEG', optimize=True, quality=70)
960
+ img_path = f"users/{uid}/projects/{project_id}/steps/step_{i+1}_image.jpg"
961
+ img_url = upload_to_storage(img_byte_arr.getvalue(), img_path, 'image/jpeg')
962
+ image_upload_time = time.time() - image_upload_start
963
+ total_upload_time += image_upload_time
964
+ logger.info(f"[PROJECT APPROVAL] Step {i+1} image upload completed in {image_upload_time:.3f}s")
965
+
966
+ # TTS generation timing
967
+ tts_start = time.time()
968
+ narration_url = generate_tts_audio_and_upload(step_info['text'], uid, project_id, i + 1)
969
+ tts_time = time.time() - tts_start
970
+ total_tts_time += tts_time
971
+ logger.info(f"[PROJECT APPROVAL] Step {i+1} TTS generation completed in {tts_time:.3f}s")
972
+
973
+ step_info.update({
974
+ "imageUrl": img_url,
975
+ "narrationUrl": narration_url,
976
+ "isDone": False,
977
+ "notes": ""
978
+ })
979
+ final_steps.append(step_info)
980
+
981
+ except Exception as e:
982
+ logger.error(f"[PROJECT APPROVAL] ERROR processing step {i+1}: {e}")
983
+ # Continue with other steps rather than failing entirely
984
+ step_info.update({
985
+ "imageUrl": "",
986
+ "narrationUrl": "",
987
+ "isDone": False,
988
+ "notes": ""
989
+ })
990
+ final_steps.append(step_info)
991
 
992
  step_processing_time = time.time() - step_processing_start
993
  logger.info(f"[PROJECT APPROVAL] All steps processing completed in {step_processing_time:.3f}s")
 
1002
  "selectedOption": selected_option or ""
1003
  }
1004
  project_ref.update(update_data)
1005
+ logger.info(f"[PROJECT APPROVAL] Updating data in db: {len(update_data)} fields")
1006
  db_update_time = time.time() - db_update_start
1007
  logger.info(f"[PROJECT APPROVAL] Database update completed in {db_update_time:.3f}s")
1008
 
 
1048
  logger.error(f"[PROJECT APPROVAL] Project ID: {project_id}, User ID: {uid}")
1049
  import traceback
1050
  logger.error(f"[PROJECT APPROVAL] Full traceback: {traceback.format_exc()}")
1051
+ return jsonify({'error': f'Internal server error: {str(e)}'}), 500
1052
 
1053
  @app.route('/api/projects', methods=['GET'])
1054
  def list_projects():