File size: 4,734 Bytes
454f1d5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cc826a1
454f1d5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
import logging
import re
import tempfile
import zipfile
from pathlib import Path
from typing import List

from fastapi import APIRouter, File, Form, HTTPException, UploadFile
from fastapi.responses import FileResponse

logger = logging.getLogger(__name__)

router = APIRouter()

plugin = None


def set_plugin_instance(plugin_instance):
    global plugin
    plugin = plugin_instance


@router.get("/status")
async def get_status():
    if plugin is None:
        return {
            "name": "doc",
            "enabled": False,
            "message": "插件未加载",
        }
    return plugin.get_status()


@router.post("/merge")
async def merge_documents(
    files: List[UploadFile] = File(...),
    order: str = Form(None),
    output_format: str = Form("md"),
):
    if plugin is None or not plugin.enabled:
        raise HTTPException(status_code=400, detail="插件未启用")

    if output_format not in {"md", "txt"}:
        raise HTTPException(status_code=400, detail="格式参数错误,仅支持 md 或 txt")

    if not files:
        raise HTTPException(status_code=400, detail="至少需要上传一个文件")

    allowed_extensions = {".md", ".txt"}
    contents = []

    for file in files:
        ext = Path(file.filename).suffix.lower()
        if ext not in allowed_extensions:
            raise HTTPException(
                status_code=400, detail=f"不支持的文件格式: {file.filename}"
            )

        content = await file.read()
        try:
            decoded_content = content.decode("utf-8")
            contents.append(decoded_content)
        except UnicodeDecodeError:
            raise HTTPException(
                status_code=400, detail=f"文件编码不支持: {file.filename}"
            )

    if order:
        try:
            order_list = [int(x) for x in order.split(",")]
            reordered_contents = [
                contents[i] for i in order_list if 0 <= i < len(contents)
            ]
            if not reordered_contents:
                raise HTTPException(status_code=400, detail="顺序参数无效")
            contents = reordered_contents
        except (ValueError, IndexError):
            raise HTTPException(
                status_code=400, detail="顺序参数格式错误,应为逗号分隔的数字"
            )

    merged_content = "\n\n".join([item.strip() for item in contents])

    file_suffix = f".{output_format}"
    temp_file = tempfile.NamedTemporaryFile(
        mode="w", delete=False, suffix=file_suffix, encoding="utf-8"
    )
    temp_file.write(merged_content)
    temp_file.close()

    media_type = "text/markdown" if output_format == "md" else "text/plain"
    filename = f"merged_document.{output_format}"

    return FileResponse(temp_file.name, media_type=media_type, filename=filename)


@router.post("/split")
async def split_document(file: UploadFile = File(...), output_format: str = Form("md")):
    if plugin is None or not plugin.enabled:
        raise HTTPException(status_code=400, detail="插件未启用")

    if output_format not in {"md", "txt"}:
        raise HTTPException(status_code=400, detail="格式参数错误,仅支持 md 或 txt")

    ext = Path(file.filename).suffix.lower()
    if ext not in {".md", ".txt"}:
        raise HTTPException(
            status_code=400, detail="不支持的文件格式,仅支持 .md 和 .txt"
        )

    content_bytes = await file.read()
    try:
        content = content_bytes.decode("utf-8")
    except UnicodeDecodeError:
        raise HTTPException(status_code=400, detail="文件编码不支持,请使用 UTF-8 编码")

    pattern = re.compile(r"^第\d+章", re.MULTILINE)
    matches = list(pattern.finditer(content))

    if not matches:
        raise HTTPException(status_code=400, detail="未找到 '第X章' 格式的章节标记")

    temp_dir = tempfile.mkdtemp()
    zip_path = Path(temp_dir) / "split_documents.zip"

    with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zipf:
        for i, match in enumerate(matches):
            start_pos = match.start()
            end_pos = matches[i + 1].start() if i + 1 < len(matches) else len(content)

            chapter_content = content[start_pos:end_pos].strip()
            first_line = chapter_content.split("\n", 1)[0].strip()

            sanitized = re.sub(r'[<>:"/\\|?*]', "_", first_line)
            filename = f"{sanitized}.{output_format}"

            temp_file = Path(temp_dir) / filename
            with open(temp_file, "w", encoding="utf-8") as f:
                f.write(chapter_content)

            zipf.write(temp_file, filename)

    return FileResponse(
        zip_path, media_type="application/zip", filename="split_documents.zip"
    )