devZenaight commited on
Commit
d734bf7
Β·
1 Parent(s): 450b2cd
app/DocumentGeneration/pdf_generator.py CHANGED
@@ -44,12 +44,19 @@ def create_pdf_document(request: ExportRequest):
44
  raise Exception("fpdf2 is not installed. Please install it with: pip install fpdf2")
45
 
46
  # Filter out empty sections to prevent blank pages
47
- filtered_sections = filter_empty_sections(request.sections)
 
 
 
48
  if not filtered_sections:
49
  raise Exception("No valid sections found after filtering. All sections appear to be empty.")
50
 
51
  # Generate table of contents
52
- toc_items = generate_table_of_contents(filtered_sections, request.businessIdea)
 
 
 
 
53
  # logging.info(f"Generated TOC with {len(toc_items)} items: {[item['title'] for item in toc_items[:3]]}...")
54
 
55
  # Create PDF with professional settings
@@ -254,8 +261,15 @@ def create_pdf_document(request: ExportRequest):
254
  pdf.set_xy(25, pdf.get_y()) # Use current Y position for consistent spacing
255
 
256
  # Process content
257
- content_text = clean_text_for_pdf(section.content)
258
- content_text = convert_currency_symbols_to_iso(content_text)
 
 
 
 
 
 
 
259
 
260
  # Remove chart data markers
261
  content_text = re.sub(r'<!--CHARTDATASTART-->.*?<!--CHARTDATAEND-->', '', content_text, flags=re.DOTALL)
@@ -408,7 +422,8 @@ def create_pdf_document(request: ExportRequest):
408
 
409
  charts_added += 1
410
  total_charts_placed += 1
411
- except Exception as chart_error:
 
412
  continue
413
  else:
414
  # Debug: Check if there are any charts that might match this section
 
44
  raise Exception("fpdf2 is not installed. Please install it with: pip install fpdf2")
45
 
46
  # Filter out empty sections to prevent blank pages
47
+ try:
48
+ filtered_sections = filter_empty_sections(request.sections)
49
+ except Exception as e:
50
+ raise Exception(f"Failed to filter sections: {str(e)}")
51
  if not filtered_sections:
52
  raise Exception("No valid sections found after filtering. All sections appear to be empty.")
53
 
54
  # Generate table of contents
55
+ try:
56
+ toc_items = generate_table_of_contents(filtered_sections, request.businessIdea)
57
+ except Exception as e:
58
+ toc_items = []
59
+ # Continue with a fallback; TOC page builder already has fallback handling
60
  # logging.info(f"Generated TOC with {len(toc_items)} items: {[item['title'] for item in toc_items[:3]]}...")
61
 
62
  # Create PDF with professional settings
 
261
  pdf.set_xy(25, pdf.get_y()) # Use current Y position for consistent spacing
262
 
263
  # Process content
264
+ try:
265
+ content_text = clean_text_for_pdf(section.content)
266
+ except Exception as e:
267
+ content_text = section.content or ""
268
+ try:
269
+ content_text = convert_currency_symbols_to_iso(content_text)
270
+ except Exception:
271
+ # If currency conversion fails, keep original text
272
+ pass
273
 
274
  # Remove chart data markers
275
  content_text = re.sub(r'<!--CHARTDATASTART-->.*?<!--CHARTDATAEND-->', '', content_text, flags=re.DOTALL)
 
422
 
423
  charts_added += 1
424
  total_charts_placed += 1
425
+ except Exception:
426
+ # Skip faulty chart and continue rendering others
427
  continue
428
  else:
429
  # Debug: Check if there are any charts that might match this section
app/DocumentGeneration/word_generator.py CHANGED
@@ -41,7 +41,10 @@ def create_word_document(request: ExportRequest):
41
  raise Exception("python-docx is not installed. Please install it with: pip install python-docx")
42
 
43
  # Filter out empty sections to prevent blank pages
44
- filtered_sections = filter_empty_sections(request.sections)
 
 
 
45
  if not filtered_sections:
46
  raise Exception("No valid sections found after filtering. All sections appear to be empty.")
47
 
@@ -138,7 +141,11 @@ def create_word_document(request: ExportRequest):
138
  doc.add_paragraph()
139
 
140
  # Sort sections according to predefined order (do this before TOC generation)
141
- sorted_sections = sort_sections_by_order(filtered_sections)
 
 
 
 
142
 
143
  # Generate TOC entries with actual page numbers
144
  # Since each section starts on a new page, we can calculate page numbers
@@ -205,8 +212,14 @@ def create_word_document(request: ExportRequest):
205
  doc.add_heading(section.title, level=1)
206
 
207
  # Clean and process content
208
- clean_content = clean_text_for_pdf(section.content)
209
- clean_content = convert_currency_symbols_to_iso(clean_content)
 
 
 
 
 
 
210
 
211
  # Remove chart data markers
212
  clean_content = re.sub(r'<!--CHARTDATASTART-->.*?<!--CHARTDATAEND-->', '', clean_content, flags=re.DOTALL)
 
41
  raise Exception("python-docx is not installed. Please install it with: pip install python-docx")
42
 
43
  # Filter out empty sections to prevent blank pages
44
+ try:
45
+ filtered_sections = filter_empty_sections(request.sections)
46
+ except Exception as e:
47
+ raise Exception(f"Failed to filter sections: {str(e)}")
48
  if not filtered_sections:
49
  raise Exception("No valid sections found after filtering. All sections appear to be empty.")
50
 
 
141
  doc.add_paragraph()
142
 
143
  # Sort sections according to predefined order (do this before TOC generation)
144
+ try:
145
+ sorted_sections = sort_sections_by_order(filtered_sections)
146
+ except Exception as e:
147
+ # Fallback: use filtered order if sorting fails
148
+ sorted_sections = filtered_sections
149
 
150
  # Generate TOC entries with actual page numbers
151
  # Since each section starts on a new page, we can calculate page numbers
 
212
  doc.add_heading(section.title, level=1)
213
 
214
  # Clean and process content
215
+ try:
216
+ clean_content = clean_text_for_pdf(section.content)
217
+ except Exception:
218
+ clean_content = section.content or ""
219
+ try:
220
+ clean_content = convert_currency_symbols_to_iso(clean_content)
221
+ except Exception:
222
+ pass
223
 
224
  # Remove chart data markers
225
  clean_content = re.sub(r'<!--CHARTDATASTART-->.*?<!--CHARTDATAEND-->', '', clean_content, flags=re.DOTALL)
app/main.py CHANGED
@@ -1457,36 +1457,32 @@ async def export_business_plan(request: ExportRequest):
1457
  FLOW: Server generates document β†’ Returns base64 data β†’ Frontend uploads to UploadThing β†’ User gets download link
1458
  """
1459
  try:
1460
-
1461
-
1462
-
1463
- # Generate unique request ID for tracking
1464
- request_id = str(id(request))
1465
-
1466
- # Add request fingerprint for duplicate detection
1467
- request_fingerprint = f"{request.businessIdea}_{request.format}_{len(request.sections)}_{hash(str(request.sections))}"
1468
-
1469
- # Check if this is a duplicate request (within 5 seconds)
1470
- current_time = time.time()
1471
- if hasattr(export_business_plan, 'last_requests'):
1472
- # Clean old requests (older than 5 seconds)
1473
- export_business_plan.last_requests = {
1474
- fp: timestamp for fp, timestamp in export_business_plan.last_requests.items()
1475
- if current_time - timestamp < 5
1476
- }
1477
-
1478
- # Check for duplicate
1479
- if request_fingerprint in export_business_plan.last_requests:
1480
- raise HTTPException(
1481
- status_code=429,
1482
- detail="Duplicate export request detected. Please wait a few seconds before trying again."
1483
- )
1484
- else:
1485
- export_business_plan.last_requests = {}
1486
-
1487
- # Record this request
1488
- export_business_plan.last_requests[request_fingerprint] = current_time
1489
-
1490
 
1491
 
1492
  # Validate request format
@@ -1503,10 +1499,13 @@ async def export_business_plan(request: ExportRequest):
1503
  if len(request.sections) == 0:
1504
  raise HTTPException(status_code=400, detail="At least one section is required for export.")
1505
 
1506
- # Check section content
1507
  for i, section in enumerate(request.sections):
 
 
 
1508
  if not section.content or not section.content.strip():
1509
- raise HTTPException(status_code=400, detail=f"Section '{section.title}' has no content.")
1510
 
1511
  # logging.info(f"Exporting business plan for: {request.businessIdea} in {request.format.upper()} format")
1512
  # logging.info(f"Request has {len(request.sections)} sections and summary length: {len(request.summary)}")
@@ -1539,6 +1538,11 @@ async def export_business_plan(request: ExportRequest):
1539
  doc_bytes, filename = create_pdf_document(request)
1540
  else: # word
1541
  doc_bytes, filename = create_word_document(request)
 
 
 
 
 
1542
  except ImportError as import_error:
1543
  raise HTTPException(
1544
  status_code=500,
 
1457
  FLOW: Server generates document β†’ Returns base64 data β†’ Frontend uploads to UploadThing β†’ User gets download link
1458
  """
1459
  try:
1460
+ # Duplicate detection (best-effort; non-fatal if bookkeeping fails)
1461
+ try:
1462
+ request_id = str(id(request))
1463
+ request_fingerprint = f"{request.businessIdea}_{request.format}_{len(request.sections)}_{hash(str(request.sections))}"
1464
+ current_time = time.time()
1465
+ if hasattr(export_business_plan, 'last_requests'):
1466
+ # Clean old requests (older than 5 seconds)
1467
+ export_business_plan.last_requests = {
1468
+ fp: timestamp for fp, timestamp in export_business_plan.last_requests.items()
1469
+ if current_time - timestamp < 5
1470
+ }
1471
+ # Check for duplicate
1472
+ if request_fingerprint in export_business_plan.last_requests:
1473
+ raise HTTPException(
1474
+ status_code=429,
1475
+ detail="Duplicate export request detected. Please wait a few seconds before trying again."
1476
+ )
1477
+ else:
1478
+ export_business_plan.last_requests = {}
1479
+ # Record this request
1480
+ export_business_plan.last_requests[request_fingerprint] = current_time
1481
+ except HTTPException:
1482
+ raise
1483
+ except Exception:
1484
+ # Do not block export on dedupe bookkeeping errors
1485
+ pass
 
 
 
 
1486
 
1487
 
1488
  # Validate request format
 
1499
  if len(request.sections) == 0:
1500
  raise HTTPException(status_code=400, detail="At least one section is required for export.")
1501
 
1502
+ # Check section content and shape
1503
  for i, section in enumerate(request.sections):
1504
+ title = getattr(section, 'title', None)
1505
+ if not title or not str(title).strip():
1506
+ raise HTTPException(status_code=400, detail=f"Section at index {i} is missing a title.")
1507
  if not section.content or not section.content.strip():
1508
+ raise HTTPException(status_code=400, detail=f"Section '{title}' has no content.")
1509
 
1510
  # logging.info(f"Exporting business plan for: {request.businessIdea} in {request.format.upper()} format")
1511
  # logging.info(f"Request has {len(request.sections)} sections and summary length: {len(request.summary)}")
 
1538
  doc_bytes, filename = create_pdf_document(request)
1539
  else: # word
1540
  doc_bytes, filename = create_word_document(request)
1541
+ # Basic sanity check on output
1542
+ if not doc_bytes or (isinstance(doc_bytes, (bytes, bytearray)) and len(doc_bytes) < 1000):
1543
+ raise HTTPException(status_code=500, detail=f"Generated {request.format.upper()} appears empty or invalid.")
1544
+ except HTTPException:
1545
+ raise
1546
  except ImportError as import_error:
1547
  raise HTTPException(
1548
  status_code=500,