Skip to content

Commit 2e69e1d

Browse files
fix(api): prevent leftover export artifacts by generating DOCX/HTML in temp dir and streaming in-memory
1 parent c0214b2 commit 2e69e1d

1 file changed

Lines changed: 49 additions & 53 deletions

File tree

src/api/app.py

Lines changed: 49 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -567,65 +567,61 @@ def generate_docx():
567567
# GET request - use master resume for backward compatibility
568568
resume_json_path = DATA_DIR / "master_resume.json"
569569

570-
# Create unique output paths to avoid conflicts
571-
import uuid
570+
# Generate HTML and DOCX using a temporary directory to avoid piling up files
571+
import tempfile, io
572572

573-
unique_id = str(uuid.uuid4())[:8]
574-
output_html_path = DATA_DIR / f"resume_{unique_id}.html"
575-
docx_path = DATA_DIR / f"resume_{unique_id}.docx"
576-
577-
# Generate HTML and DOCX from resume JSON
578573
try:
579-
result = subprocess.run(
580-
[
581-
sys.executable,
582-
str(generate_script),
583-
"--input",
584-
str(resume_json_path),
585-
"--output",
586-
str(output_html_path),
587-
"--docx",
588-
],
589-
capture_output=True,
590-
text=True,
591-
)
592-
593-
if result.returncode != 0:
594-
return (
595-
jsonify(
596-
{
597-
"error": f"Failed to generate DOCX: {result.stderr or result.stdout}"
598-
}
599-
),
600-
500,
574+
with tempfile.TemporaryDirectory(prefix="resume_export_") as tmpdir:
575+
tmpdir_path = Path(tmpdir)
576+
output_html_path = tmpdir_path / "resume.html"
577+
docx_path = tmpdir_path / "resume.docx" # generate_hybrid_resume.py derives this from HTML path
578+
579+
# Run generator script
580+
result = subprocess.run(
581+
[
582+
sys.executable,
583+
str(generate_script),
584+
"--input",
585+
str(resume_json_path),
586+
"--output",
587+
str(output_html_path),
588+
"--docx",
589+
],
590+
capture_output=True,
591+
text=True,
601592
)
602593

603-
# The DOCX file should be created alongside the HTML file
604-
if not docx_path.exists():
605-
return (
606-
jsonify(
607-
{
608-
"error": f"DOCX file was not created at {docx_path}. Output: {result.stdout}"
609-
}
610-
),
611-
500,
612-
)
594+
if result.returncode != 0:
595+
return (
596+
jsonify(
597+
{
598+
"error": f"Failed to generate DOCX: {result.stderr or result.stdout}"
599+
}
600+
),
601+
500,
602+
)
613603

614-
# Send file and clean up after
615-
response = send_file(docx_path, as_attachment=True, download_name="resume.docx")
604+
# Ensure DOCX exists
605+
if not docx_path.exists():
606+
return (
607+
jsonify(
608+
{
609+
"error": f"DOCX file was not created. Output: {result.stdout}"
610+
}
611+
),
612+
500,
613+
)
616614

617-
# Clean up temporary files
618-
@response.call_on_close
619-
def cleanup():
620-
try:
621-
if output_html_path.exists():
622-
output_html_path.unlink()
623-
if docx_path.exists():
624-
docx_path.unlink()
625-
except Exception:
626-
pass
627-
628-
return response
615+
# Read DOCX into memory and return
616+
docx_bytes = docx_path.read_bytes()
617+
memfile = io.BytesIO(docx_bytes)
618+
memfile.seek(0)
619+
return send_file(
620+
memfile,
621+
mimetype="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
622+
as_attachment=True,
623+
download_name="resume.docx",
624+
)
629625

630626
except Exception as e:
631627
error_msg = f"Failed to generate DOCX: {str(e)}\n{traceback.format_exc()}"

0 commit comments

Comments
 (0)