diff --git a/__pycache__/app.cpython-312.pyc b/__pycache__/app.cpython-312.pyc new file mode 100644 index 0000000..a0feb2f Binary files /dev/null and b/__pycache__/app.cpython-312.pyc differ diff --git a/app.py b/app.py index 64a3e4c..8f7f717 100644 --- a/app.py +++ b/app.py @@ -1,11 +1,8 @@ from fastapi import FastAPI, Request from fastapi.staticfiles import StaticFiles from pydantic import BaseModel -from reportlab.pdfgen import canvas -from reportlab.lib.pagesizes import A4 -from reportlab.pdfbase.ttfonts import TTFont -from reportlab.pdfbase import pdfmetrics -from reportlab.pdfbase.pdfmetrics import stringWidth +from openpyxl import Workbook +from openpyxl.styles import Font, Alignment import uuid, os app = FastAPI() @@ -13,37 +10,79 @@ app = FastAPI() os.makedirs("static", exist_ok=True) app.mount("/static", StaticFiles(directory="static"), name="static") -pdfmetrics.registerFont(TTFont("TWFont", "NotoSansTC-Medium.ttf")) class TextRequest(BaseModel): content: str + separator: str = "\t" # 預設使用 Tab 分隔符 + has_header: bool = False # 是否第一行是標題 -@app.post("/generate-pdf") -def generate_pdf(data: TextRequest, request: Request): - filename = f"{uuid.uuid4()}.pdf" +@app.post("/generate-excel") +def generate_excel(data: TextRequest, request: Request): + filename = f"{uuid.uuid4()}.xlsx" filepath = os.path.join("static", filename) - c = canvas.Canvas(filepath, pagesize=A4) - c.setFont("TWFont", 12) + # 創建新的工作簿 + wb = Workbook() + ws = wb.active + ws.title = "文字內容" - text_obj = c.beginText(50, 800) - text_obj.setFont("TWFont", 12) + # 將文字內容按行分割 + lines = data.content.splitlines() + + if not lines: + return {"error": "沒有提供文字內容"} - max_line_width = A4[0] - 50 * 2 # 頁寬扣左右邊距 + # 分析第一行來確定欄位數量 + first_line = lines[0] + columns = first_line.split(data.separator) + num_columns = len(columns) + + # 設置標題(如果有指定) + start_row = 1 + if data.has_header and len(lines) > 1: + # 第一行作為標題 + for col_idx, header in enumerate(columns, 1): + cell = ws.cell(row=1, column=col_idx, value=header.strip()) + cell.font = Font(bold=True, size=12) + cell.alignment = Alignment(horizontal='center') + start_row = 2 + lines = lines[1:] # 跳過標題行 + else: + # 沒有標題,第一行也是資料 + lines = lines - for line in data.content.splitlines(): - while stringWidth(line, "TWFont", 12) > max_line_width: - for i in range(len(line), 0, -1): - if stringWidth(line[:i], "TWFont", 12) <= max_line_width: - text_obj.textLine(line[:i]) - line = line[i:] - break - text_obj.textLine(line) + # 寫入資料 + for row_idx, line in enumerate(lines, start=start_row): + columns_data = line.split(data.separator) + + # 確保每行都有足夠的欄位 + while len(columns_data) < num_columns: + columns_data.append("") + + # 寫入每個欄位的資料 + for col_idx, cell_data in enumerate(columns_data[:num_columns], 1): + cell = ws.cell(row=row_idx, column=col_idx, value=cell_data.strip()) + cell.alignment = Alignment(wrap_text=True) - c.drawText(text_obj) - c.showPage() - c.save() + # 自動調整列寬 + for col_idx in range(1, num_columns + 1): + column_letter = ws.cell(row=1, column=col_idx).column_letter + max_length = 0 + + for row in ws.iter_rows(min_col=col_idx, max_col=col_idx): + for cell in row: + if cell.value: + max_length = max(max_length, len(str(cell.value))) + + # 設置列寬,最小10,最大50 + adjusted_width = min(max(max_length + 2, 10), 50) + ws.column_dimensions[column_letter].width = adjusted_width + + # 保存文件 + wb.save(filepath) return { - "download_url": str(request.base_url).rstrip("/") + f"/static/{filename}" + "download_url": str(request.base_url).rstrip("/") + f"/static/{filename}", + "columns": num_columns, + "rows": len(lines) + (1 if data.has_header else 0) } diff --git a/requirements.txt b/requirements.txt index e7caa4e..c90cf89 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ fastapi uvicorn pydantic -reportlab +openpyxl python-multipart