@@ -6,14 +6,26 @@ from fastapi import APIRouter, HTTPException, Depends
|
||||
from fastapi.responses import FileResponse
|
||||
from pydantic import BaseModel
|
||||
from starlette.background import BackgroundTask
|
||||
import docx
|
||||
from docx.shared import Pt
|
||||
from docx.oxml.ns import qn
|
||||
import auth
|
||||
import db
|
||||
from formula_processor import preprocess_formulas
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
class StyleOptions(BaseModel):
|
||||
base_font_size: Optional[int] = 12
|
||||
base_font_family: Optional[str] = "宋体"
|
||||
h1_size: Optional[int] = 18
|
||||
h2_size: Optional[int] = 16
|
||||
h3_size: Optional[int] = 14
|
||||
h4_size: Optional[int] = 12
|
||||
|
||||
class DocRequest(BaseModel):
|
||||
markdown: str
|
||||
styleOptions: Optional[StyleOptions] = None
|
||||
|
||||
def remove_file(path: str):
|
||||
try:
|
||||
@@ -53,6 +65,55 @@ async def convert_md_to_docx(req: DocRequest, current_user: Optional[dict] = Dep
|
||||
)
|
||||
os.remove(md_tmp_path)
|
||||
|
||||
# ====== 样式后处理 ======
|
||||
if req.styleOptions:
|
||||
doc = docx.Document(tmp_path)
|
||||
|
||||
def set_font(style_name, font_name, font_size):
|
||||
try:
|
||||
style = doc.styles[style_name]
|
||||
if font_size:
|
||||
style.font.size = Pt(font_size)
|
||||
if font_name:
|
||||
style.font.name = font_name
|
||||
style._element.rPr.rFonts.set(qn('w:eastAsia'), font_name)
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
set_font('Normal', req.styleOptions.base_font_family, req.styleOptions.base_font_size)
|
||||
set_font('Heading 1', req.styleOptions.base_font_family, req.styleOptions.h1_size)
|
||||
set_font('Heading 2', req.styleOptions.base_font_family, req.styleOptions.h2_size)
|
||||
set_font('Heading 3', req.styleOptions.base_font_family, req.styleOptions.h3_size)
|
||||
set_font('Heading 4', req.styleOptions.base_font_family, req.styleOptions.h4_size)
|
||||
set_font('Heading 5', req.styleOptions.base_font_family, req.styleOptions.h4_size)
|
||||
set_font('Heading 6', req.styleOptions.base_font_family, req.styleOptions.h4_size)
|
||||
|
||||
# 强制遍历并覆盖所有段落的 run,确保样式生效
|
||||
for p in doc.paragraphs:
|
||||
# 判定当前段落是不是标题
|
||||
current_font_size = req.styleOptions.base_font_size
|
||||
current_font_family = req.styleOptions.base_font_family
|
||||
|
||||
if p.style.name.startswith('Heading'):
|
||||
level_str = p.style.name.replace('Heading ', '')
|
||||
try:
|
||||
level = int(level_str)
|
||||
if level == 1: current_font_size = req.styleOptions.h1_size
|
||||
elif level == 2: current_font_size = req.styleOptions.h2_size
|
||||
elif level == 3: current_font_size = req.styleOptions.h3_size
|
||||
elif level >= 4: current_font_size = req.styleOptions.h4_size
|
||||
except:
|
||||
pass
|
||||
|
||||
# 为该段落中每一个具体的 run 设置字体
|
||||
for run in p.runs:
|
||||
run.font.name = current_font_family
|
||||
run._element.rPr.rFonts.set(qn('w:eastAsia'), current_font_family)
|
||||
if current_font_size:
|
||||
run.font.size = Pt(current_font_size)
|
||||
|
||||
doc.save(tmp_path)
|
||||
|
||||
return FileResponse(
|
||||
tmp_path,
|
||||
media_type='application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
|
||||
Reference in New Issue
Block a user