大量修改二期功能清单内容
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
"""上传脚本取正文 —— 只认 docx / txt。
|
||||
|
||||
docx 用标准库拆(zip + xml),不引 python-docx:镜像少一个依赖,也避免它对损坏文件抛一堆内部异常。
|
||||
段落 = <w:p>,文字 = 其中所有 <w:t> 拼接;<w:br>/<w:tab> 补空白,否则整段会粘成一坨。
|
||||
"""
|
||||
|
||||
import re
|
||||
import zipfile
|
||||
from io import BytesIO
|
||||
from xml.etree import ElementTree
|
||||
|
||||
W_NS = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
|
||||
MAX_UPLOAD_BYTES = 5 * 1024 * 1024 # 脚本是纯文字,5MB 足够;更大的基本是误传
|
||||
|
||||
|
||||
class ScriptFileError(ValueError):
|
||||
"""取正文失败,message 直接给用户看(中文)。"""
|
||||
|
||||
|
||||
def _docx_text(raw: bytes) -> str:
|
||||
try:
|
||||
with zipfile.ZipFile(BytesIO(raw)) as bundle:
|
||||
document = bundle.read("word/document.xml")
|
||||
except KeyError:
|
||||
raise ScriptFileError("这个 docx 里没有正文,请确认文件没有损坏")
|
||||
except zipfile.BadZipFile:
|
||||
raise ScriptFileError("这个文件不是有效的 docx,请另存为 .docx 后重试")
|
||||
|
||||
try:
|
||||
root = ElementTree.fromstring(document)
|
||||
except ElementTree.ParseError:
|
||||
raise ScriptFileError("docx 正文解析失败,请另存一份后重试")
|
||||
|
||||
paragraphs = []
|
||||
for node in root.iter(f"{{{W_NS}}}p"):
|
||||
pieces = []
|
||||
for child in node.iter():
|
||||
tag = child.tag
|
||||
if tag == f"{{{W_NS}}}t":
|
||||
pieces.append(child.text or "")
|
||||
elif tag in (f"{{{W_NS}}}br", f"{{{W_NS}}}cr"):
|
||||
pieces.append("\n")
|
||||
elif tag == f"{{{W_NS}}}tab":
|
||||
pieces.append("\t")
|
||||
line = "".join(pieces).strip()
|
||||
if line:
|
||||
paragraphs.append(line)
|
||||
return "\n".join(paragraphs)
|
||||
|
||||
|
||||
def _txt_text(raw: bytes) -> str:
|
||||
# 中文 txt 常见三种落盘编码;utf-8 失败再退 GBK 家族,最后一步忽略坏字节保底出文本。
|
||||
for encoding in ("utf-8-sig", "utf-8", "gb18030"):
|
||||
try:
|
||||
return raw.decode(encoding)
|
||||
except UnicodeDecodeError:
|
||||
continue
|
||||
return raw.decode("utf-8", errors="ignore")
|
||||
|
||||
|
||||
def extract_script_text(upload) -> tuple[str, str]:
|
||||
"""(文件名, 正文)。只收 docx / txt,其余一律拒绝。"""
|
||||
name = getattr(upload, "name", "") or "script"
|
||||
lowered = name.lower()
|
||||
if not lowered.endswith((".docx", ".txt")):
|
||||
raise ScriptFileError("只支持 docx 和 txt 两种脚本文件")
|
||||
|
||||
raw = upload.read()
|
||||
if len(raw) > MAX_UPLOAD_BYTES:
|
||||
raise ScriptFileError("脚本文件不能超过 5MB")
|
||||
|
||||
text = _docx_text(raw) if lowered.endswith(".docx") else _txt_text(raw)
|
||||
# 统一换行 + 压掉连续空行,避免原稿的排版空白撑爆后面的提示词
|
||||
text = re.sub(r"\n{3,}", "\n\n", text.replace("\r\n", "\n").replace("\r", "\n")).strip()
|
||||
if not text:
|
||||
raise ScriptFileError("没能从这个文件里读到文字,请换一份")
|
||||
return name, text
|
||||
Reference in New Issue
Block a user