Spaces:
Sleeping
Sleeping
| from robyn import Robyn, Request, Response, jsonify, ALLOW_CORS | |
| import os | |
| import tempfile | |
| import asyncio | |
| from concurrent.futures import ProcessPoolExecutor | |
| import traceback | |
| from ord import process_excel_to_word | |
| # At the top, after imports | |
| from functools import partial | |
| # Increase worker pool | |
| executor = ProcessPoolExecutor(max_workers=os.cpu_count() or 4) | |
| # In convert_excel function, the process_file_sync is already good | |
| # But you can add batching if multiple files come in | |
| app = Robyn(__file__) | |
| ALLOW_CORS(app, origins=["*"]) | |
| # Create process pool for CPU-intensive tasks | |
| executor = ProcessPoolExecutor(max_workers=4) | |
| def process_file_sync(input_path, output_path, display_name, use_two_columns, | |
| add_separator, balance_method, theme_hex): | |
| """Synchronous wrapper for process_excel_to_word""" | |
| process_excel_to_word( | |
| excel_file_path=input_path, | |
| output_word_path=output_path, | |
| display_name=display_name, | |
| use_two_columns=use_two_columns, | |
| add_separator_line=add_separator, | |
| balance_method=balance_method, | |
| theme_hex=theme_hex | |
| ) | |
| return output_path | |
| def index(request: Request): | |
| """Health check endpoint - synchronous is fine for simple JSON""" | |
| return jsonify({ | |
| "status": "online", | |
| "message": "Excel to Word Converter API", | |
| "version": "1.0.0", | |
| "endpoints": { | |
| "/convert": "POST - Convert Excel to Word", | |
| "/health": "GET - Health check" | |
| } | |
| }) | |
| def health(request: Request): | |
| """Health check for HuggingFace""" | |
| return jsonify({"status": "healthy", "service": "excel-to-word-converter"}) | |
| async def convert_excel(request: Request): | |
| """Convert Excel to Word document - async for I/O operations""" | |
| input_path = None | |
| output_path = None | |
| try: | |
| # Get the uploaded file | |
| files = request.files | |
| if not files: | |
| return Response( | |
| status_code=400, | |
| headers={"Content-Type": "application/json"}, | |
| description=jsonify({"error": "No file uploaded"}) | |
| ) | |
| # Get file | |
| uploaded_file = files.get('file') or files[list(files.keys())[0]] | |
| # Extract file content | |
| if isinstance(uploaded_file, bytes): | |
| file_content = uploaded_file | |
| elif hasattr(uploaded_file, 'content'): | |
| file_content = uploaded_file.content | |
| elif hasattr(uploaded_file, 'read'): | |
| file_content = uploaded_file.read() | |
| elif hasattr(uploaded_file, 'file'): | |
| file_content = uploaded_file.file.read() | |
| else: | |
| file_content = uploaded_file | |
| # Get parameters | |
| form_data = request.form_data or {} | |
| display_name = form_data.get('display_name') | |
| use_two_columns = form_data.get('use_two_columns', 'true').lower() == 'true' | |
| add_separator = form_data.get('add_separator', 'true').lower() == 'true' | |
| balance_method = form_data.get('balance_method', 'dynamic') | |
| theme_hex = form_data.get('theme_hex', '5FFFDF') | |
| # Create temp files using asyncio for non-blocking I/O | |
| loop = asyncio.get_event_loop() | |
| # Write input file asynchronously | |
| input_path = tempfile.mktemp(suffix='.xlsx') | |
| await loop.run_in_executor(None, lambda: open(input_path, 'wb').write(file_content)) | |
| output_path = tempfile.mktemp(suffix='.docx') | |
| # Run the CPU-intensive conversion in a separate process | |
| await loop.run_in_executor( | |
| executor, | |
| process_file_sync, | |
| input_path, | |
| output_path, | |
| display_name, | |
| use_two_columns, | |
| add_separator, | |
| balance_method, | |
| theme_hex | |
| ) | |
| # Read output file asynchronously | |
| docx_content = await loop.run_in_executor( | |
| None, | |
| lambda: open(output_path, 'rb').read() | |
| ) | |
| # Clean up temp files | |
| await loop.run_in_executor(None, lambda: os.unlink(input_path)) | |
| await loop.run_in_executor(None, lambda: os.unlink(output_path)) | |
| return Response( | |
| status_code=200, | |
| headers={ | |
| "Content-Type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", | |
| "Content-Disposition": "attachment; filename=converted_document.docx", | |
| }, | |
| description=docx_content | |
| ) | |
| except Exception as e: | |
| error_trace = traceback.format_exc() | |
| print(f"Error: {error_trace}") | |
| # Clean up on error | |
| if input_path and os.path.exists(input_path): | |
| os.unlink(input_path) | |
| if output_path and os.path.exists(output_path): | |
| os.unlink(output_path) | |
| return Response( | |
| status_code=500, | |
| headers={"Content-Type": "application/json"}, | |
| description=jsonify({ | |
| "error": str(e), | |
| "trace": error_trace | |
| }) | |
| ) | |
| if __name__ == "__main__": | |
| port = int(os.getenv("PORT", 7860)) | |
| app.start(host="0.0.0.0", port=port) |