解决了打包问题
This commit is contained in:
125
.idea/workspace.xml
generated
125
.idea/workspace.xml
generated
@@ -5,11 +5,15 @@
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="6b18b44a-df57-4212-a857-9e291ebe5dd2" name="更改" comment="">
|
||||
<change afterPath="$PROJECT_DIR$/lite_onefile.spec" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/docutranslate/static/DocuTranslate.ico" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/full_onefile.spec" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/requirements.txt" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/README.md" beforeDir="false" afterPath="$PROJECT_DIR$/README.md" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/docutranslate/app.py" beforeDir="false" afterPath="$PROJECT_DIR$/docutranslate/app.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/docutranslate/global_values/conditional_import.py" beforeDir="false" afterPath="$PROJECT_DIR$/docutranslate/global_values/conditional_import.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/docutranslate/converter/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/docutranslate/converter/__init__.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/docutranslate/static/index.html" beforeDir="false" afterPath="$PROJECT_DIR$/docutranslate/static/index.html" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/full.spec" beforeDir="false" afterPath="$PROJECT_DIR$/full.spec" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/pyproject.toml" beforeDir="false" afterPath="$PROJECT_DIR$/pyproject.toml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/uv.lock" beforeDir="false" afterPath="$PROJECT_DIR$/uv.lock" afterDir="false" />
|
||||
</list>
|
||||
@@ -41,76 +45,76 @@
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent">{
|
||||
"keyToString": {
|
||||
"DefaultHtmlFileTemplate": "HTML File",
|
||||
"JavaScript 调试.output.html (1).executor": "Run",
|
||||
"JavaScript 调试.output.html.executor": "Run",
|
||||
"JavaScript 调试.regex.md_中文.html.executor": "Run",
|
||||
"JavaScript 调试.regex_中文.html.executor": "Run",
|
||||
"JavaScript 调试.test.html.executor": "Run",
|
||||
"JavaScript 调试.test2.html.executor": "Run",
|
||||
"JavaScript 调试.test2_英文.html.executor": "Run",
|
||||
"JavaScript 调试.test4-1_中文.html.executor": "Run",
|
||||
"JavaScript 调试.互联网认证授权机制.html.executor": "Run",
|
||||
"JavaScript 调试.互联网认证授权机制_英文.html.executor": "Run",
|
||||
"JavaScript 调试.毕业论文_英文.html.executor": "Run",
|
||||
"ModuleVcsDetector.initialDetectionPerformed": "true",
|
||||
"Python 测试.Python 测试 (markdown_mask.py 内).executor": "Run",
|
||||
"Python 测试.markdown_mask.Test.test_basic_link_masking 的 Python 测试.executor": "Run",
|
||||
"Python 测试.pytest (test_html.py 内).executor": "Run",
|
||||
"Python.1test.executor": "Run",
|
||||
"Python.2test2 (1).executor": "Run",
|
||||
"Python.PDFtranslater (1).executor": "Run",
|
||||
"Python.PDFtranslater (2).executor": "Run",
|
||||
"Python.agent.executor": "Debug",
|
||||
"Python.agent_utils.executor": "Run",
|
||||
"Python.app (1).executor": "Run",
|
||||
"Python.app.executor": "Run",
|
||||
"Python.app2.executor": "Run",
|
||||
"Python.app_test (1).executor": "Run",
|
||||
"Python.convert.executor": "Run",
|
||||
"Python.converter_docling.executor": "Run",
|
||||
"Python.converter_mineru.executor": "Run",
|
||||
"Python.markdown_splitter.executor": "Debug",
|
||||
"Python.markdown_utils.executor": "Run",
|
||||
"Python.test.executor": "Run",
|
||||
"Python.test1.executor": "Run",
|
||||
"Python.test2.executor": "Run",
|
||||
"Python.test3.executor": "Run",
|
||||
"Python.test4.executor": "Run",
|
||||
"Python.testhtml.executor": "Run",
|
||||
"Python.translater.executor": "Run",
|
||||
"Python.切分测试.executor": "Run",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager": "true",
|
||||
"RunOnceActivity.git.unshallow": "true",
|
||||
"git-widget-placeholder": "dev",
|
||||
"last_opened_file_path": "C:/Users/jxgm/Desktop/translate/docutranslate",
|
||||
"list.type.of.created.stylesheet": "CSS",
|
||||
"node.js.detected.package.eslint": "true",
|
||||
"node.js.detected.package.tslint": "true",
|
||||
"node.js.selected.package.eslint": "(autodetect)",
|
||||
"node.js.selected.package.tslint": "(autodetect)",
|
||||
"nodejs_package_manager_path": "npm",
|
||||
"settings.editor.selected.configurable": "preferences.pluginManager",
|
||||
"vue.rearranger.settings.migration": "true"
|
||||
<component name="PropertiesComponent"><![CDATA[{
|
||||
"keyToString": {
|
||||
"DefaultHtmlFileTemplate": "HTML File",
|
||||
"JavaScript 调试.output.html (1).executor": "Run",
|
||||
"JavaScript 调试.output.html.executor": "Run",
|
||||
"JavaScript 调试.regex.md_中文.html.executor": "Run",
|
||||
"JavaScript 调试.regex_中文.html.executor": "Run",
|
||||
"JavaScript 调试.test.html.executor": "Run",
|
||||
"JavaScript 调试.test2.html.executor": "Run",
|
||||
"JavaScript 调试.test2_英文.html.executor": "Run",
|
||||
"JavaScript 调试.test4-1_中文.html.executor": "Run",
|
||||
"JavaScript 调试.互联网认证授权机制.html.executor": "Run",
|
||||
"JavaScript 调试.互联网认证授权机制_英文.html.executor": "Run",
|
||||
"JavaScript 调试.毕业论文_英文.html.executor": "Run",
|
||||
"ModuleVcsDetector.initialDetectionPerformed": "true",
|
||||
"Python 测试.Python 测试 (markdown_mask.py 内).executor": "Run",
|
||||
"Python 测试.markdown_mask.Test.test_basic_link_masking 的 Python 测试.executor": "Run",
|
||||
"Python 测试.pytest (test_html.py 内).executor": "Run",
|
||||
"Python.1test.executor": "Run",
|
||||
"Python.2test2 (1).executor": "Run",
|
||||
"Python.PDFtranslater (1).executor": "Run",
|
||||
"Python.PDFtranslater (2).executor": "Run",
|
||||
"Python.agent.executor": "Debug",
|
||||
"Python.agent_utils.executor": "Run",
|
||||
"Python.app (1).executor": "Run",
|
||||
"Python.app.executor": "Run",
|
||||
"Python.app2.executor": "Run",
|
||||
"Python.app_test (1).executor": "Run",
|
||||
"Python.convert.executor": "Run",
|
||||
"Python.converter_docling.executor": "Run",
|
||||
"Python.converter_mineru.executor": "Run",
|
||||
"Python.markdown_splitter.executor": "Debug",
|
||||
"Python.markdown_utils.executor": "Run",
|
||||
"Python.test.executor": "Run",
|
||||
"Python.test1.executor": "Run",
|
||||
"Python.test2.executor": "Run",
|
||||
"Python.test3.executor": "Run",
|
||||
"Python.test4.executor": "Run",
|
||||
"Python.testhtml.executor": "Run",
|
||||
"Python.translater.executor": "Run",
|
||||
"Python.切分测试.executor": "Run",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager": "true",
|
||||
"RunOnceActivity.git.unshallow": "true",
|
||||
"git-widget-placeholder": "dev",
|
||||
"last_opened_file_path": "C:/Users/jxgm/Desktop/translate/docutranslate",
|
||||
"list.type.of.created.stylesheet": "CSS",
|
||||
"node.js.detected.package.eslint": "true",
|
||||
"node.js.detected.package.tslint": "true",
|
||||
"node.js.selected.package.eslint": "(autodetect)",
|
||||
"node.js.selected.package.tslint": "(autodetect)",
|
||||
"nodejs_package_manager_path": "npm",
|
||||
"settings.editor.selected.configurable": "preferences.pluginManager",
|
||||
"vue.rearranger.settings.migration": "true"
|
||||
}
|
||||
}</component>
|
||||
}]]></component>
|
||||
<component name="RecentsManager">
|
||||
<key name="CopyFile.RECENT_KEYS">
|
||||
<recent name="C:\Users\jxgm\Desktop\translate\docutranslate" />
|
||||
<recent name="C:\Users\jxgm\Desktop\translate\docutranslate\docutranslate\static" />
|
||||
<recent name="C:\Users\jxgm\Desktop\translate\docutranslate\dist\DocuTranslate" />
|
||||
<recent name="C:\Users\jxgm\Desktop\FileTranslate\dist\DocuTranslate" />
|
||||
<recent name="C:\Users\jxgm\Desktop\FileTranslate\tests\files" />
|
||||
<recent name="C:\Users\jxgm\Desktop\FileTranslate\docutranslate\agents" />
|
||||
</key>
|
||||
<key name="MoveFile.RECENT_KEYS">
|
||||
<recent name="C:\Users\jxgm\Desktop\translate\docutranslate" />
|
||||
<recent name="C:\Users\jxgm\Desktop\FileTranslate\src" />
|
||||
<recent name="C:\Users\jxgm\Desktop\FileTranslate" />
|
||||
<recent name="C:\Users\jxgm\Desktop\FileTranslate\dist\DocuTranslate" />
|
||||
<recent name="C:\Users\jxgm\Desktop\FileTranslate\dist\app" />
|
||||
<recent name="C:\Users\jxgm\Desktop\FileTranslate\tests\files" />
|
||||
</key>
|
||||
</component>
|
||||
<component name="RunManager" selected="Python.app_test (1)">
|
||||
@@ -607,6 +611,7 @@
|
||||
<workItem from="1747740341909" duration="145000" />
|
||||
<workItem from="1747752718385" duration="81000" />
|
||||
<workItem from="1747754618316" duration="16566000" />
|
||||
<workItem from="1747828300140" duration="3391000" />
|
||||
</task>
|
||||
<servers />
|
||||
</component>
|
||||
@@ -625,7 +630,7 @@
|
||||
</option>
|
||||
</component>
|
||||
<component name="com.intellij.coverage.CoverageDataManagerImpl">
|
||||
<SUITE FILE_PATH="coverage/filetranslate$app_test__1_.coverage" NAME="app_test (1) 覆盖结果" MODIFIED="1747818930270" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/tests" />
|
||||
<SUITE FILE_PATH="coverage/filetranslate$app_test__1_.coverage" NAME="app_test (1) 覆盖结果" MODIFIED="1747831001962" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/tests" />
|
||||
<SUITE FILE_PATH="coverage/filetranslate$test.coverage" NAME="test 覆盖结果" MODIFIED="1747472297913" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/tests" />
|
||||
<SUITE FILE_PATH="coverage/filetranslate$convert.coverage" NAME="convert 覆盖结果" MODIFIED="1746963490689" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/docutranslate/utils" />
|
||||
<SUITE FILE_PATH="coverage/PDFtranslate$PDFtranslater__1_.coverage" NAME="PDFtranslater (1) 覆盖结果" MODIFIED="1746633258205" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/pdftranslate_packages" />
|
||||
|
||||
16
README.md
16
README.md
@@ -19,18 +19,18 @@
|
||||
# 安装
|
||||
|
||||
使用pip
|
||||
`pip install docutranslate`
|
||||
`pip install docling`#如果使用docling进行文档解析
|
||||
1. `pip install docutranslate`
|
||||
2. `pip install docling`#如果使用docling进行文档解析
|
||||
|
||||
使用uv
|
||||
`uv init`
|
||||
`uv add docutranslate`
|
||||
`uv add docling`#如果使用docling进行文档解析
|
||||
1. `uv init`
|
||||
2. `uv add docutranslate`
|
||||
3. `uv add docling`#如果使用docling进行文档解析
|
||||
|
||||
使用git
|
||||
`git clone https://github.com/xunbu/docutranslate.git`
|
||||
`uv sync`
|
||||
|
||||
1. `git clone https://github.com/xunbu/docutranslate.git`
|
||||
2. `uv sync`
|
||||
3. `uv pip install -U -e .`
|
||||
# 支持的文件格式
|
||||
|
||||
| 输入格式 | 输出格式 |
|
||||
|
||||
@@ -2,6 +2,7 @@ import asyncio
|
||||
import io
|
||||
import logging
|
||||
import time
|
||||
from contextlib import asynccontextmanager
|
||||
from pathlib import Path
|
||||
from typing import List, Dict, Any, Optional
|
||||
from urllib.parse import quote
|
||||
@@ -10,17 +11,12 @@ import uvicorn
|
||||
from fastapi import FastAPI, File, Form, UploadFile, Request, HTTPException
|
||||
from fastapi.responses import HTMLResponse, JSONResponse, StreamingResponse,FileResponse
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from docutranslate import FileTranslater # Assuming FileTranslater is in docutranslate module
|
||||
from docutranslate import FileTranslater
|
||||
from docutranslate.logger import translater_logger
|
||||
from docutranslate.utils.resource_utils import resource_path
|
||||
from docutranslate.global_values import available_packages
|
||||
|
||||
DOCLING_EXIST=True if available_packages.get("docling") else False
|
||||
app = FastAPI()
|
||||
|
||||
STATIC_DIR=resource_path("static")
|
||||
|
||||
app.mount("/static",StaticFiles(directory=STATIC_DIR), name="static")
|
||||
|
||||
# --- 全局配置 ---
|
||||
log_queue: Optional[asyncio.Queue] = None
|
||||
@@ -69,8 +65,8 @@ class QueueAndHistoryHandler(logging.Handler):
|
||||
|
||||
|
||||
# --- 应用生命周期事件 ---
|
||||
@app.on_event("startup")
|
||||
async def startup_event():
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
global log_queue
|
||||
app.state.main_event_loop = asyncio.get_running_loop()
|
||||
log_queue = asyncio.Queue()
|
||||
@@ -94,7 +90,13 @@ async def startup_event():
|
||||
break
|
||||
|
||||
translater_logger.info("应用启动完成,日志队列/历史处理器已正确配置。")
|
||||
yield
|
||||
|
||||
app = FastAPI(lifespan=lifespan)
|
||||
|
||||
STATIC_DIR=resource_path("static")
|
||||
|
||||
app.mount("/static",StaticFiles(directory=STATIC_DIR), name="static")
|
||||
|
||||
# --- Background Task Logic ---
|
||||
async def _perform_translation(params: Dict[str, Any], file_contents: bytes, original_filename: str):
|
||||
@@ -403,7 +405,7 @@ async def download_html(filename_with_ext: str):
|
||||
headers={"Content-Disposition": f"attachment; filename*=UTF-8''{quote(actual_filename, safe='', encoding='utf-8')}"}
|
||||
)
|
||||
|
||||
|
||||
#TODO:端口被占用时使用其他端口
|
||||
def run_app():
|
||||
print("正在启动 DocuTranslate WebUI")
|
||||
print("请访问 http://127.0.0.1:8010 (ctrl+点击链接即可打开)")
|
||||
|
||||
@@ -4,3 +4,6 @@ from .converter_mineru import ConverterMineru
|
||||
from docutranslate.global_values import conditional_import
|
||||
if conditional_import("docling"):
|
||||
from .converter_docling import ConverterDocling
|
||||
|
||||
# 打包docling时取消下面一行注释
|
||||
# from .converter_docling import ConverterDocling
|
||||
|
||||
BIN
docutranslate/static/DocuTranslate.ico
Normal file
BIN
docutranslate/static/DocuTranslate.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
@@ -4,6 +4,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>DocuTranslate</title>
|
||||
<link rel="icon" href="/static/DocuTranslate.ico" type="image/x-icon">
|
||||
<link rel="stylesheet" href="/static/pico.css">
|
||||
<style>
|
||||
body {
|
||||
@@ -134,9 +135,10 @@
|
||||
margin-left: 1.5rem; /* Space from title */
|
||||
/* Pico styles will apply display:flex, gap */
|
||||
}
|
||||
|
||||
.preview-view-mode-buttons button {
|
||||
font-size: 0.85rem; /* Smaller buttons for toggle */
|
||||
padding: 0.4rem 0.8rem;
|
||||
font-size: 0.85rem; /* Smaller buttons for toggle */
|
||||
padding: 0.4rem 0.8rem;
|
||||
}
|
||||
|
||||
|
||||
@@ -184,6 +186,7 @@
|
||||
overflow: auto;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.preview-pane pre {
|
||||
padding: 10px;
|
||||
white-space: pre-wrap;
|
||||
@@ -243,33 +246,40 @@
|
||||
.form-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
#previewContainer {
|
||||
|
||||
#previewContainer {
|
||||
flex-direction: column;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
height: 95vh;
|
||||
}
|
||||
|
||||
.preview-pane {
|
||||
min-height: 300px;
|
||||
}
|
||||
|
||||
#previewTitleBar {
|
||||
flex-wrap: wrap; /* Allow wrapping for smaller screens */
|
||||
}
|
||||
|
||||
.preview-view-mode-buttons {
|
||||
margin-left: 0;
|
||||
margin-top: 0.5rem; /* Space when wrapped */
|
||||
width: 100%; /* Take full width when wrapped */
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#closeModalBtnInTitle {
|
||||
order: -1; /* Move close button to top left on wrap if needed, or adjust layout */
|
||||
margin-left: auto; /* Keep it to the right */
|
||||
}
|
||||
|
||||
#previewModalTitle {
|
||||
width: 100%; /* Allow title to take width if buttons wrap below */
|
||||
text-align: center;
|
||||
margin-bottom: 0.5rem; /* Space if buttons wrap */
|
||||
width: 100%; /* Allow title to take width if buttons wrap below */
|
||||
text-align: center;
|
||||
margin-bottom: 0.5rem; /* Space if buttons wrap */
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -321,9 +331,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<details>
|
||||
<summary>文档转换引擎配置</summary>
|
||||
<summary>文档解析引擎配置</summary>
|
||||
<div class="form-group">
|
||||
<label for="convert_engin">转换引擎</label>
|
||||
<label for="convert_engin">解析引擎</label>
|
||||
<select id="convert_engin" name="convert_engin">
|
||||
<option value="mineru" selected>minerU</option>
|
||||
<option value="docling" id="docling">Docling</option>
|
||||
@@ -342,9 +352,7 @@
|
||||
<summary>翻译API配置</summary>
|
||||
<div class="form-grid">
|
||||
<div class="form-group">
|
||||
<label for="platform_select">AI 平台 <a id="api_href" class="no-style" href="/"
|
||||
target="_blank"
|
||||
title="获取API-KEY">🔗</a></label>
|
||||
<label for="platform_select">AI 平台 </label>
|
||||
<select id="platform_select" name="platform_select_ui">
|
||||
<option value="custom">自定义接口</option>
|
||||
<option value="https://api.openai.com/v1">OpenAI</option>
|
||||
@@ -363,7 +371,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="apikey">API 密钥</label>
|
||||
<label for="apikey">API 密钥<a id="api_href" class="no-style" href="/"
|
||||
target="_blank"
|
||||
title="获取API-KEY">🔗</a></label>
|
||||
<input type="password" id="apikey" name="apikey" placeholder="平台对应的API Key" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
@@ -393,7 +403,8 @@
|
||||
<div class="modal-content">
|
||||
<div id="previewTitleBar">
|
||||
<h3 id="previewModalTitle">双语预览</h3>
|
||||
<div class="preview-view-mode-buttons button-group" style="margin-top:0;"> <!-- Pico .button-group applied -->
|
||||
<div class="preview-view-mode-buttons button-group" style="margin-top:0;">
|
||||
<!-- Pico .button-group applied -->
|
||||
<button id="setBilingualViewBtn" role="button" class="primary">双语</button>
|
||||
<button id="setTranslatedOnlyViewBtn" role="button" class="outline">译文</button>
|
||||
</div>
|
||||
@@ -512,9 +523,9 @@
|
||||
baseUrlInput.value = selectedPlatformValue;
|
||||
apiHref.classList.remove('hidden')
|
||||
if (apiHrefMap[baseUrlInput.value]) { // Check if key exists
|
||||
apiHref.href = apiHrefMap[baseUrlInput.value];
|
||||
apiHref.href = apiHrefMap[baseUrlInput.value];
|
||||
} else {
|
||||
apiHref.classList.add('hidden'); // Hide if no link defined
|
||||
apiHref.classList.add('hidden'); // Hide if no link defined
|
||||
}
|
||||
}
|
||||
saveToStorage('translator_last_platform', selectedPlatformValue);
|
||||
@@ -629,10 +640,12 @@
|
||||
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
|
||||
fileDropArea.addEventListener(eventName, preventDefaults, false);
|
||||
});
|
||||
|
||||
function preventDefaults(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
['dragenter', 'dragover'].forEach(eventName => {
|
||||
fileDropArea.addEventListener(eventName, () => {
|
||||
if (!fileDropArea.classList.contains('file-selected')) {
|
||||
@@ -676,14 +689,14 @@
|
||||
}
|
||||
});
|
||||
if (currentEngineDisabled) {
|
||||
const mineruOption = convertEnginSelect.querySelector('option[value="mineru"]');
|
||||
if (mineruOption && !mineruOption.disabled) {
|
||||
const mineruOption = convertEnginSelect.querySelector('option[value="mineru"]');
|
||||
if (mineruOption && !mineruOption.disabled) {
|
||||
convertEnginSelect.value = "mineru";
|
||||
} else {
|
||||
} else {
|
||||
const firstAvailable = convertEnginSelect.querySelector('option:not([disabled])');
|
||||
if (firstAvailable) convertEnginSelect.value = firstAvailable.value;
|
||||
}
|
||||
updateConvertEnginUI();
|
||||
}
|
||||
updateConvertEnginUI();
|
||||
}
|
||||
statusMsg.textContent = '初始化完成';
|
||||
} catch (error) {
|
||||
@@ -759,8 +772,14 @@
|
||||
|
||||
if (fileType.startsWith('text/') || ['md', 'json', 'xml', 'log', 'py', 'js', 'css', 'java', 'c', 'cpp', 'h', 'hpp', 'cs', 'rb', 'php', 'swift', 'kt', 'go', 'rs', 'ts'].includes(fileExtension)) {
|
||||
const pre = document.createElement('pre');
|
||||
reader.onload = (e) => { pre.textContent = e.target.result; originalPreviewPane.appendChild(pre); };
|
||||
reader.onerror = () => { pre.textContent = '无法读取原文文件内容。'; originalPreviewPane.appendChild(pre); };
|
||||
reader.onload = (e) => {
|
||||
pre.textContent = e.target.result;
|
||||
originalPreviewPane.appendChild(pre);
|
||||
};
|
||||
reader.onerror = () => {
|
||||
pre.textContent = '无法读取原文文件内容。';
|
||||
originalPreviewPane.appendChild(pre);
|
||||
};
|
||||
reader.readAsText(originalFile);
|
||||
} else if (fileType === 'application/pdf' || fileType === 'text/html' || fileExtension === 'html' || fileExtension === 'htm') {
|
||||
const iframe = document.createElement('iframe');
|
||||
@@ -789,7 +808,7 @@
|
||||
.then(html => {
|
||||
let finalHtml = html;
|
||||
if (!html.toLowerCase().includes('/static/pico.css')) {
|
||||
finalHtml = `<link rel="stylesheet" href="/static/pico.css">\n<style>body{padding:1em;}</style>\n${html}`;
|
||||
finalHtml = `<link rel="stylesheet" href="/static/pico.css">\n<style>body{padding:1em;}</style>\n${html}`;
|
||||
}
|
||||
const blob = new Blob([finalHtml], {type: 'text/html'});
|
||||
const blobUrl = URL.createObjectURL(blob);
|
||||
@@ -798,7 +817,9 @@
|
||||
try {
|
||||
translatedPreviewFrame.contentWindow.document.title = currentFileName + '_translated';
|
||||
URL.revokeObjectURL(blobUrl);
|
||||
} catch (e) { console.warn('无法设置译文iframe标题或释放Blob URL', e); }
|
||||
} catch (e) {
|
||||
console.warn('无法设置译文iframe标题或释放Blob URL', e);
|
||||
}
|
||||
};
|
||||
setPreviewDisplayMode('bilingual'); // Default to bilingual view
|
||||
modal.style.display = 'block';
|
||||
@@ -828,7 +849,7 @@
|
||||
.then(htmlContent => {
|
||||
let finalHtml = htmlContent;
|
||||
if (!htmlContent.toLowerCase().includes('/static/pico.css')) {
|
||||
finalHtml = `<link rel="stylesheet" href="/static/pico.css">\n<style>body{padding:1em; break-inside: avoid;}</style>\n${htmlContent}`;
|
||||
finalHtml = `<link rel="stylesheet" href="/static/pico.css">\n<style>body{padding:1em; break-inside: avoid;}</style>\n${htmlContent}`;
|
||||
}
|
||||
iframe.onload = () => {
|
||||
iframe.onload = null;
|
||||
@@ -945,31 +966,31 @@
|
||||
fileNameDisplay.classList.add('input-error-text');
|
||||
fileDropArea.classList.add('input-error');
|
||||
fileDropPrompt.classList.remove('hidden');
|
||||
if(!firstErrorElement) firstErrorElement = fileDropArea;
|
||||
if (!firstErrorElement) firstErrorElement = fileDropArea;
|
||||
}
|
||||
|
||||
if (convertEnginSelect.value === 'mineru' && !mineruTokenInput.value.trim()) {
|
||||
currentStatusMsg += (currentStatusMsg ? ' ' : '') + '使用 Mineru 引擎时,必须填写 Mineru Token。';
|
||||
mineruTokenInput.classList.add('input-error');
|
||||
if(!firstErrorElement) firstErrorElement = mineruTokenInput;
|
||||
if (!firstErrorElement) firstErrorElement = mineruTokenInput;
|
||||
}
|
||||
if (!apikeyInput.value.trim()) {
|
||||
currentStatusMsg += (currentStatusMsg ? ' ' : '') + 'API 密钥不能为空。';
|
||||
apikeyInput.classList.add('input-error');
|
||||
if(!firstErrorElement) firstErrorElement = apikeyInput;
|
||||
if (!firstErrorElement) firstErrorElement = apikeyInput;
|
||||
}
|
||||
if (!modelInput.value.trim()) {
|
||||
currentStatusMsg += (currentStatusMsg ? ' ' : '') + '模型 ID 不能为空。';
|
||||
modelInput.classList.add('input-error');
|
||||
if(!firstErrorElement) firstErrorElement = modelInput;
|
||||
if (!firstErrorElement) firstErrorElement = modelInput;
|
||||
}
|
||||
if (platformSelect.value === 'custom' && !baseUrlInput.value.trim()) {
|
||||
currentStatusMsg += (currentStatusMsg ? ' ' : '') + '自定义接口时,API 地址不能为空。';
|
||||
baseUrlInput.classList.add('input-error');
|
||||
if(!firstErrorElement) firstErrorElement = baseUrlInput;
|
||||
if (!firstErrorElement) firstErrorElement = baseUrlInput;
|
||||
}
|
||||
|
||||
if(firstErrorElement){
|
||||
if (firstErrorElement) {
|
||||
statusMsg.textContent = currentStatusMsg;
|
||||
statusMsg.className = 'error-message';
|
||||
firstErrorElement.focus();
|
||||
|
||||
10
full.spec
10
full.spec
@@ -4,12 +4,10 @@ from PyInstaller.utils.hooks import collect_all
|
||||
datas = [('./.venv/Lib/site-packages/docling_parse/pdf_resources_v2', 'docling_parse/pdf_resources_v2'),
|
||||
('./docutranslate/static', 'docutranslate/static')]
|
||||
binaries = []
|
||||
hiddenimports = []
|
||||
tmp_ret = collect_all('easyocr')
|
||||
datas += tmp_ret[0]; binaries += tmp_ret[1]; hiddenimports += tmp_ret[2]
|
||||
tmp_ret = collect_all('docling')
|
||||
datas += tmp_ret[0]; binaries += tmp_ret[1]; hiddenimports += tmp_ret[2]
|
||||
|
||||
hiddenimports=[]
|
||||
for i in ['easyocr','docling']:
|
||||
tmp_ret = collect_all(i)
|
||||
datas += tmp_ret[0]; binaries += tmp_ret[1]; hiddenimports += tmp_ret[2]
|
||||
|
||||
a = Analysis(
|
||||
['./docutranslate/app.py'],
|
||||
|
||||
46
full_onefile.spec
Normal file
46
full_onefile.spec
Normal file
@@ -0,0 +1,46 @@
|
||||
# -*- mode: python ; coding: utf-8 -*-
|
||||
from PyInstaller.utils.hooks import collect_all
|
||||
datas = [('./.venv/Lib/site-packages/docling_parse/pdf_resources_v2', 'docling_parse/pdf_resources_v2'),
|
||||
('./docutranslate/static', 'docutranslate/static')]
|
||||
binaries = []
|
||||
hiddenimports=[]
|
||||
for i in ['easyocr','docling']:
|
||||
tmp_ret = collect_all(i)
|
||||
datas += tmp_ret[0]; binaries += tmp_ret[1]; hiddenimports += tmp_ret[2]
|
||||
|
||||
a = Analysis(
|
||||
['docutranslate\\app.py'],
|
||||
pathex=[],
|
||||
binaries=binaries,
|
||||
datas=datas,
|
||||
hiddenimports=hiddenimports,
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
noarchive=False,
|
||||
optimize=0,
|
||||
)
|
||||
pyz = PYZ(a.pure)
|
||||
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.datas,
|
||||
[],
|
||||
name='DocuTranslate_full',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
runtime_tmpdir=None,
|
||||
console=True,
|
||||
disable_windowed_traceback=False,
|
||||
argv_emulation=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
icon=['DocuTranslate.ico'],
|
||||
)
|
||||
@@ -5,10 +5,22 @@ description = "文件翻译工具"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
dependencies = [
|
||||
"httpx",
|
||||
"markdown2",
|
||||
"httpx>=0.28.1",
|
||||
"markdown2>=2.5.3",
|
||||
"fastapi[standard]>=0.115.12",
|
||||
"pyinstaller>=6.13.0",
|
||||
"transformers==4.51.3",
|
||||
]
|
||||
|
||||
|
||||
[project.optional-dependencies]
|
||||
docling = [
|
||||
"docling"
|
||||
]
|
||||
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
"docling",
|
||||
"pyinstaller",
|
||||
]
|
||||
[project.scripts]
|
||||
docutranslate = "docutranslate.cli:main"
|
||||
|
||||
369
requirements.txt
Normal file
369
requirements.txt
Normal file
@@ -0,0 +1,369 @@
|
||||
# This file was autogenerated by uv via the following command:
|
||||
# uv pip compile pyproject.toml -o requirements.txt
|
||||
altgraph==0.17.4
|
||||
# via pyinstaller
|
||||
annotated-types==0.7.0
|
||||
# via pydantic
|
||||
anyio==4.9.0
|
||||
# via
|
||||
# httpx
|
||||
# starlette
|
||||
# watchfiles
|
||||
attrs==25.3.0
|
||||
# via
|
||||
# jsonlines
|
||||
# jsonschema
|
||||
# referencing
|
||||
beautifulsoup4==4.13.4
|
||||
# via docling
|
||||
certifi==2025.4.26
|
||||
# via
|
||||
# docling
|
||||
# httpcore
|
||||
# httpx
|
||||
# requests
|
||||
charset-normalizer==3.4.2
|
||||
# via requests
|
||||
click==8.1.8
|
||||
# via
|
||||
# docling
|
||||
# rich-toolkit
|
||||
# typer
|
||||
# uvicorn
|
||||
colorama==0.4.6
|
||||
# via
|
||||
# click
|
||||
# tqdm
|
||||
# uvicorn
|
||||
dill==0.4.0
|
||||
# via multiprocess
|
||||
dnspython==2.7.0
|
||||
# via email-validator
|
||||
docling==2.33.0
|
||||
# via docutranslate (pyproject.toml)
|
||||
docling-core==2.31.1
|
||||
# via
|
||||
# docling
|
||||
# docling-ibm-models
|
||||
# docling-parse
|
||||
docling-ibm-models==3.4.3
|
||||
# via docling
|
||||
docling-parse==4.0.1
|
||||
# via docling
|
||||
easyocr==1.7.2
|
||||
# via docling
|
||||
email-validator==2.2.0
|
||||
# via fastapi
|
||||
et-xmlfile==2.0.0
|
||||
# via openpyxl
|
||||
fastapi==0.115.12
|
||||
# via docutranslate (pyproject.toml)
|
||||
fastapi-cli==0.0.7
|
||||
# via fastapi
|
||||
filelock==3.18.0
|
||||
# via
|
||||
# huggingface-hub
|
||||
# torch
|
||||
# transformers
|
||||
filetype==1.2.0
|
||||
# via docling
|
||||
fsspec==2025.5.0
|
||||
# via
|
||||
# huggingface-hub
|
||||
# torch
|
||||
h11==0.16.0
|
||||
# via
|
||||
# httpcore
|
||||
# uvicorn
|
||||
httpcore==1.0.9
|
||||
# via httpx
|
||||
httptools==0.6.4
|
||||
# via uvicorn
|
||||
httpx==0.28.1
|
||||
# via
|
||||
# docutranslate (pyproject.toml)
|
||||
# fastapi
|
||||
huggingface-hub==0.31.4
|
||||
# via
|
||||
# docling
|
||||
# docling-ibm-models
|
||||
# tokenizers
|
||||
# transformers
|
||||
idna==3.10
|
||||
# via
|
||||
# anyio
|
||||
# email-validator
|
||||
# httpx
|
||||
# requests
|
||||
imageio==2.37.0
|
||||
# via scikit-image
|
||||
jinja2==3.1.6
|
||||
# via
|
||||
# fastapi
|
||||
# torch
|
||||
jsonlines==3.1.0
|
||||
# via docling-ibm-models
|
||||
jsonref==1.1.0
|
||||
# via docling-core
|
||||
jsonschema==4.23.0
|
||||
# via docling-core
|
||||
jsonschema-specifications==2025.4.1
|
||||
# via jsonschema
|
||||
latex2mathml==3.78.0
|
||||
# via docling-core
|
||||
lazy-loader==0.4
|
||||
# via scikit-image
|
||||
lxml==5.4.0
|
||||
# via
|
||||
# docling
|
||||
# python-docx
|
||||
# python-pptx
|
||||
markdown-it-py==3.0.0
|
||||
# via rich
|
||||
markdown2==2.5.3
|
||||
# via docutranslate (pyproject.toml)
|
||||
marko==2.1.3
|
||||
# via docling
|
||||
markupsafe==3.0.2
|
||||
# via jinja2
|
||||
mdurl==0.1.2
|
||||
# via markdown-it-py
|
||||
mpire==2.10.2
|
||||
# via semchunk
|
||||
mpmath==1.3.0
|
||||
# via sympy
|
||||
multiprocess==0.70.18
|
||||
# via mpire
|
||||
networkx==3.4.2
|
||||
# via
|
||||
# scikit-image
|
||||
# torch
|
||||
ninja==1.11.1.4
|
||||
# via easyocr
|
||||
numpy==2.2.6
|
||||
# via
|
||||
# docling-ibm-models
|
||||
# easyocr
|
||||
# imageio
|
||||
# opencv-python-headless
|
||||
# pandas
|
||||
# safetensors
|
||||
# scikit-image
|
||||
# scipy
|
||||
# shapely
|
||||
# tifffile
|
||||
# torchvision
|
||||
# transformers
|
||||
opencv-python-headless==4.11.0.86
|
||||
# via
|
||||
# docling-ibm-models
|
||||
# easyocr
|
||||
openpyxl==3.1.5
|
||||
# via docling
|
||||
packaging==25.0
|
||||
# via
|
||||
# huggingface-hub
|
||||
# lazy-loader
|
||||
# pyinstaller
|
||||
# pyinstaller-hooks-contrib
|
||||
# scikit-image
|
||||
# transformers
|
||||
pandas==2.2.3
|
||||
# via
|
||||
# docling
|
||||
# docling-core
|
||||
pefile==2023.2.7
|
||||
# via pyinstaller
|
||||
pillow==11.2.1
|
||||
# via
|
||||
# docling
|
||||
# docling-core
|
||||
# docling-ibm-models
|
||||
# docling-parse
|
||||
# easyocr
|
||||
# imageio
|
||||
# python-pptx
|
||||
# scikit-image
|
||||
# torchvision
|
||||
pluggy==1.6.0
|
||||
# via docling
|
||||
pyclipper==1.3.0.post6
|
||||
# via easyocr
|
||||
pydantic==2.11.4
|
||||
# via
|
||||
# docling
|
||||
# docling-core
|
||||
# docling-ibm-models
|
||||
# docling-parse
|
||||
# fastapi
|
||||
# pydantic-settings
|
||||
pydantic-core==2.33.2
|
||||
# via pydantic
|
||||
pydantic-settings==2.9.1
|
||||
# via docling
|
||||
pygments==2.19.1
|
||||
# via
|
||||
# mpire
|
||||
# rich
|
||||
pyinstaller==6.13.0
|
||||
# via docutranslate (pyproject.toml)
|
||||
pyinstaller-hooks-contrib==2025.4
|
||||
# via pyinstaller
|
||||
pylatexenc==2.10
|
||||
# via docling
|
||||
pypdfium2==4.30.1
|
||||
# via docling
|
||||
python-bidi==0.6.6
|
||||
# via easyocr
|
||||
python-dateutil==2.9.0.post0
|
||||
# via pandas
|
||||
python-docx==1.1.2
|
||||
# via docling
|
||||
python-dotenv==1.1.0
|
||||
# via
|
||||
# pydantic-settings
|
||||
# uvicorn
|
||||
python-multipart==0.0.20
|
||||
# via fastapi
|
||||
python-pptx==1.0.2
|
||||
# via docling
|
||||
pytz==2025.2
|
||||
# via pandas
|
||||
pywin32==310
|
||||
# via
|
||||
# docling-parse
|
||||
# mpire
|
||||
pywin32-ctypes==0.2.3
|
||||
# via pyinstaller
|
||||
pyyaml==6.0.2
|
||||
# via
|
||||
# docling-core
|
||||
# easyocr
|
||||
# huggingface-hub
|
||||
# transformers
|
||||
# uvicorn
|
||||
referencing==0.36.2
|
||||
# via
|
||||
# jsonschema
|
||||
# jsonschema-specifications
|
||||
regex==2024.11.6
|
||||
# via transformers
|
||||
requests==2.32.3
|
||||
# via
|
||||
# docling
|
||||
# huggingface-hub
|
||||
# transformers
|
||||
rich==14.0.0
|
||||
# via
|
||||
# rich-toolkit
|
||||
# typer
|
||||
rich-toolkit==0.14.6
|
||||
# via fastapi-cli
|
||||
rpds-py==0.25.0
|
||||
# via
|
||||
# jsonschema
|
||||
# referencing
|
||||
rtree==1.4.0
|
||||
# via docling
|
||||
safetensors==0.5.3
|
||||
# via
|
||||
# docling-ibm-models
|
||||
# transformers
|
||||
scikit-image==0.25.2
|
||||
# via easyocr
|
||||
scipy==1.15.3
|
||||
# via
|
||||
# docling
|
||||
# easyocr
|
||||
# scikit-image
|
||||
semchunk==2.2.2
|
||||
# via docling-core
|
||||
setuptools==80.8.0
|
||||
# via
|
||||
# pyinstaller
|
||||
# pyinstaller-hooks-contrib
|
||||
# torch
|
||||
shapely==2.1.1
|
||||
# via easyocr
|
||||
shellingham==1.5.4
|
||||
# via typer
|
||||
six==1.17.0
|
||||
# via python-dateutil
|
||||
sniffio==1.3.1
|
||||
# via anyio
|
||||
soupsieve==2.7
|
||||
# via beautifulsoup4
|
||||
starlette==0.46.2
|
||||
# via fastapi
|
||||
sympy==1.14.0
|
||||
# via torch
|
||||
tabulate==0.9.0
|
||||
# via
|
||||
# docling-core
|
||||
# docling-parse
|
||||
tifffile==2025.5.10
|
||||
# via scikit-image
|
||||
tokenizers==0.21.1
|
||||
# via transformers
|
||||
torch==2.7.0
|
||||
# via
|
||||
# docling-ibm-models
|
||||
# easyocr
|
||||
# safetensors
|
||||
# torchvision
|
||||
torchvision==0.22.0
|
||||
# via
|
||||
# docling-ibm-models
|
||||
# easyocr
|
||||
tqdm==4.67.1
|
||||
# via
|
||||
# docling
|
||||
# docling-ibm-models
|
||||
# huggingface-hub
|
||||
# mpire
|
||||
# semchunk
|
||||
# transformers
|
||||
transformers==4.51.3
|
||||
# via
|
||||
# docutranslate (pyproject.toml)
|
||||
# docling-core
|
||||
# docling-ibm-models
|
||||
typer==0.15.4
|
||||
# via
|
||||
# docling
|
||||
# docling-core
|
||||
# fastapi-cli
|
||||
typing-extensions==4.13.2
|
||||
# via
|
||||
# anyio
|
||||
# beautifulsoup4
|
||||
# docling-core
|
||||
# fastapi
|
||||
# huggingface-hub
|
||||
# pydantic
|
||||
# pydantic-core
|
||||
# python-docx
|
||||
# python-pptx
|
||||
# referencing
|
||||
# rich-toolkit
|
||||
# torch
|
||||
# typer
|
||||
# typing-inspection
|
||||
typing-inspection==0.4.0
|
||||
# via
|
||||
# pydantic
|
||||
# pydantic-settings
|
||||
tzdata==2025.2
|
||||
# via pandas
|
||||
urllib3==2.4.0
|
||||
# via requests
|
||||
uvicorn==0.34.2
|
||||
# via
|
||||
# fastapi
|
||||
# fastapi-cli
|
||||
watchfiles==1.0.5
|
||||
# via uvicorn
|
||||
websockets==15.0.1
|
||||
# via uvicorn
|
||||
xlsxwriter==3.2.3
|
||||
# via python-pptx
|
||||
Reference in New Issue
Block a user