TiH0 commited on
Commit
16ce9a3
·
verified ·
1 Parent(s): 961b18e

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +123 -0
app.py ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, File, UploadFile, Form, HTTPException
2
+ from fastapi.responses import FileResponse, HTMLResponse
3
+ from fastapi.middleware.cors import CORSMiddleware
4
+ from fastapi import BackgroundTasks
5
+ from fastapi.responses import FileResponse
6
+ import os
7
+ import tempfile
8
+ import re
9
+ from pathlib import Path
10
+
11
+ # Import your conversion function
12
+ from prof import process_excel_to_word
13
+
14
+ app = FastAPI(title="QCM Converter API")
15
+
16
+ # Enable CORS for all origins (you can restrict this in production)
17
+ app.add_middleware(
18
+ CORSMiddleware,
19
+ allow_origins=["*"],
20
+ allow_credentials=True,
21
+ allow_methods=["*"],
22
+ allow_headers=["*"],
23
+ )
24
+
25
+ def validate_hex_color(color: str) -> bool:
26
+ """Validate hex color format"""
27
+ pattern = r'^[0-9A-Fa-f]{6}$'
28
+ return bool(re.match(pattern, color))
29
+
30
+ @app.get("/", response_class=HTMLResponse)
31
+ async def root():
32
+ """Serve the HTML interface"""
33
+ html_path = Path(__file__).parent / "index.html"
34
+ if html_path.exists():
35
+ return html_path.read_text()
36
+ return """
37
+ <html>
38
+ <body>
39
+ <h1>QCM Converter API</h1>
40
+ <p>Upload your Excel files at <a href="/docs">/docs</a></p>
41
+ </body>
42
+ </html>
43
+ """
44
+
45
+ @app.post("/convert")
46
+ async def convert_file(
47
+ background_tasks: BackgroundTasks,
48
+ file: UploadFile = File(...),
49
+ use_two_columns: bool = Form(True),
50
+ add_separator_line: bool = Form(True),
51
+ theme_color: str = Form("5FFFDF")
52
+ ):
53
+ """
54
+ Convert Excel QCM file to Word document
55
+
56
+ Parameters:
57
+ - file: Excel file (.xlsx)
58
+ - use_two_columns: Use two-column layout
59
+ - add_separator_line: Add separator line between columns
60
+ - theme_color: Hex color code (without #) e.g., "5FFFDF"
61
+ """
62
+
63
+ # Validate file extension
64
+ if not file.filename.endswith('.xlsx'):
65
+ raise HTTPException(status_code=400, detail="Only .xlsx files are supported")
66
+
67
+ # Validate color
68
+ if not validate_hex_color(theme_color):
69
+ raise HTTPException(
70
+ status_code=400,
71
+ detail="Invalid color format. Use 6-character hex code (e.g., '5FFFDF')"
72
+ )
73
+
74
+ with tempfile.NamedTemporaryFile(delete=False, suffix='.xlsx') as temp_input:
75
+ content = await file.read()
76
+ temp_input.write(content)
77
+ temp_input_path = temp_input.name
78
+
79
+ output_filename = file.filename.replace('.xlsx', '_converted.docx')
80
+ temp_output_path = tempfile.mktemp(suffix='.docx')
81
+
82
+ try:
83
+ process_excel_to_word(
84
+ excel_file_path=temp_input_path,
85
+ output_word_path=temp_output_path,
86
+ display_name=None,
87
+ use_two_columns=use_two_columns,
88
+ add_separator_line=add_separator_line,
89
+ balance_method="dynamic",
90
+ theme_hex=theme_color
91
+ )
92
+
93
+ # ✅ Schedule cleanup as a background task
94
+ background_tasks.add_task(cleanup_files, temp_input_path, temp_output_path)
95
+
96
+ return FileResponse(
97
+ temp_output_path,
98
+ media_type="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
99
+ filename=output_filename,
100
+ background=None # <-- No lambda here
101
+ )
102
+
103
+ except Exception as e:
104
+ cleanup_files(temp_input_path, temp_output_path)
105
+ raise HTTPException(status_code=500, detail=f"Conversion failed: {str(e)}")
106
+
107
+ def cleanup_files(*file_paths):
108
+ """Clean up temporary files"""
109
+ for file_path in file_paths:
110
+ try:
111
+ if os.path.exists(file_path):
112
+ os.unlink(file_path)
113
+ except Exception as e:
114
+ print(f"Error cleaning up {file_path}: {e}")
115
+
116
+ @app.get("/health")
117
+ async def health_check():
118
+ """Health check endpoint"""
119
+ return {"status": "healthy", "message": "QCM Converter API is running"}
120
+
121
+ if __name__ == "__main__":
122
+ import uvicorn
123
+ uvicorn.run(app, host="0.0.0.0", port=7860)