pipeline-app/app/office_proxy.py
yumoqing b849eb3e92 feat(office): 补提交 univer-office 办公代理(已部署上线)
/office/* 反向代理到本机 univer-office Node 服务(9091),承接 markdown<->IDocumentData 转换 + docx/xlsx/ppt 导出。含 office_proxy.py + config.json 路由 + pipeline_app 注册 + restart-pipeline.sh
2026-08-21 17:28:47 +08:00

52 lines
2.1 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""office_proxy - 把 /office/* 请求转发到本机 univer-office Node 服务(9091)。
univer-office 承担 markdown<->IDocumentData 转换与 docx/xlsx/ppt 导出,
这些能力是 Node 生态(Univer + docx/exceljs/pptxgenjs)Python 侧无法直接实现,
故通过 ahserver 的 startswiths 机制做反向代理。
路由映射:
/office/render -> http://127.0.0.1:9091/render (markdown -> IDocumentData)
/office/extract -> http://127.0.0.1:9091/extract (IDocumentData -> 纯文本)
/office/export/docx -> http://127.0.0.1:9091/export/docx (markdown -> docx 二进制)
"""
import aiohttp
from aiohttp import web
from appPublic.registerfunction import registerFunction
from appPublic.log import error, debug
OFFICE_BACKEND = 'http://127.0.0.1:9091'
# hop-by-hop 头,转发时需剔除
_HOP_BY_HOP = {
'host', 'content-length', 'transfer-encoding', 'connection',
'keep-alive', 'upgrade', 'proxy-authenticate', 'proxy-authorization',
'te', 'trailers',
}
async def office_proxy(request, params_kw, *args, **env):
"""把 /office/* 转发到 9091。args = leading 之后的路径段,如 ('render',) 或 ('export','docx')。"""
path = '/'.join(args)
url = f'{OFFICE_BACKEND}/{path}'
debug(f'office_proxy: {request.method} {url}')
body = await request.read()
headers = {k: v for k, v in request.headers.items() if k.lower() not in _HOP_BY_HOP}
try:
timeout = aiohttp.ClientTimeout(total=180)
async with aiohttp.ClientSession(timeout=timeout) as session:
async with session.request(request.method, url, headers=headers, data=body) as resp:
resp_body = await resp.read()
resp_headers = {
k: v for k, v in resp.headers.items()
if k.lower() not in _HOP_BY_HOP and k.lower() != 'content-encoding'
}
return web.Response(body=resp_body, status=resp.status, headers=resp_headers)
except Exception as e:
error(f'office_proxy failed: {e}')
return web.Response(body=f'office backend error: {e}'.encode(), status=502)
registerFunction('office_proxy', office_proxy)