From 0b40d962221067d36a61c45d5574fab4af0d5810 Mon Sep 17 00:00:00 2001 From: xunbu Date: Mon, 26 May 2025 10:49:50 +0800 Subject: [PATCH] =?UTF-8?q?js=E3=80=81css=E5=AE=8C=E5=85=A8=E6=9C=AC?= =?UTF-8?q?=E5=9C=B0=E5=8C=96=EF=BC=8C=E6=98=BE=E7=A4=BA=E5=85=83=E4=BF=A1?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/workspace.xml | 134 +- docutranslate/__init__.py | 2 +- docutranslate/agents/agent.py | 2 +- docutranslate/app.py | 50 +- docutranslate/global_values/__init__.py | 2 +- docutranslate/static/MathJax.js | 1 + docutranslate/static/index.html | 28 +- docutranslate/static/mermaid.js | 2607 +++++++++++++++++++++++ docutranslate/template/__init__.py | 0 docutranslate/template/markdown.html | 46 + docutranslate/translater.py | 68 +- pyproject.toml | 8 +- 12 files changed, 2809 insertions(+), 139 deletions(-) create mode 100644 docutranslate/static/MathJax.js create mode 100644 docutranslate/static/mermaid.js create mode 100644 docutranslate/template/__init__.py create mode 100644 docutranslate/template/markdown.html diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 411d571..b346a16 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -5,7 +5,18 @@ + + + + + + + + + + + - { + "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" } -}]]> +} @@ -508,10 +520,10 @@ + - @@ -606,6 +618,8 @@ + + @@ -628,14 +642,14 @@ file://$PROJECT_DIR$/docutranslate/translater.py - 247 + 250 - + @@ -654,7 +668,7 @@ - + diff --git a/docutranslate/__init__.py b/docutranslate/__init__.py index ed3c1d2..3c7fe55 100644 --- a/docutranslate/__init__.py +++ b/docutranslate/__init__.py @@ -1,4 +1,4 @@ - +__version__="0.2.25" diff --git a/docutranslate/agents/agent.py b/docutranslate/agents/agent.py index 8a7da42..269a196 100644 --- a/docutranslate/agents/agent.py +++ b/docutranslate/agents/agent.py @@ -32,7 +32,7 @@ class PromptsCount: self.lock.release() -TIMEOUT = 500 +TIMEOUT = 600 class Agent: diff --git a/docutranslate/app.py b/docutranslate/app.py index 7d23aa2..7d18bcd 100644 --- a/docutranslate/app.py +++ b/docutranslate/app.py @@ -10,14 +10,13 @@ from urllib.parse import quote import uvicorn from fastapi import FastAPI, File, Form, UploadFile, Request, HTTPException -from fastapi.responses import HTMLResponse, JSONResponse, StreamingResponse,FileResponse +from fastapi.responses import HTMLResponse, JSONResponse, StreamingResponse, FileResponse from fastapi.staticfiles import StaticFiles -from docutranslate import FileTranslater +from docutranslate import FileTranslater, __version__ from docutranslate.logger import translater_logger from docutranslate.utils.resource_utils import resource_path from docutranslate.global_values import available_packages - # --- 全局配置 --- log_queue: Optional[asyncio.Queue] = None current_state: Dict[str, Any] = { @@ -46,7 +45,7 @@ class QueueAndHistoryHandler(logging.Handler): def emit(self, record: logging.LogRecord): log_entry = self.format(record) - print(log_entry) # Keep console log for server visibility + print(log_entry) # Keep console log for server visibility self.history_list.append(log_entry) if len(self.history_list) > self.max_history: del self.history_list[:len(self.history_list) - self.max_history] @@ -92,11 +91,13 @@ async def lifespan(app: FastAPI): translater_logger.info("应用启动完成,日志队列/历史处理器已正确配置。") yield + app = FastAPI(lifespan=lifespan) -STATIC_DIR=resource_path("static") +STATIC_DIR = resource_path("static") + +app.mount("/static", StaticFiles(directory=STATIC_DIR), name="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): @@ -179,23 +180,23 @@ async def _perform_translation(params: Dict[str, Any], file_contents: bytes, ori # --- API Endpoints --- @app.get("/", response_class=HTMLResponse) async def main_page(request: Request): - index_path = Path("index.html") # Adjust if index.html is elsewhere + index_path = Path("index.html") # Adjust if index.html is elsewhere if not index_path.exists(): - # Fallback to static dir if not in root + # Fallback to static dir if not in root index_path = STATIC_DIR / "index.html" if not index_path.exists(): raise HTTPException(status_code=404, detail="index.html not found") no_cache_headers = { "Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", # 兼容 HTTP/1.0 - "Expires": "0", # 兼容旧版代理/缓存 + "Expires": "0", # 兼容旧版代理/缓存 } - return FileResponse(index_path,headers=no_cache_headers) + return FileResponse(index_path, headers=no_cache_headers) @app.post("/translate") async def handle_translate( - request: Request, # Added request for potential future use, not strictly needed now + request: Request, # Added request for potential future use, not strictly needed now base_url: str = Form(...), apikey: str = Form(...), model_id: str = Form(...), @@ -203,8 +204,8 @@ async def handle_translate( formula_ocr: bool = Form(False), code_ocr: bool = Form(False), refine_markdown: bool = Form(False), - convert_engin: str = Form(...), # New parameter - mineru_token: Optional[str] = Form(None), # New parameter + convert_engin: str = Form(...), # New parameter + mineru_token: Optional[str] = Form(None), # New parameter file: UploadFile = File(...) ): global current_state, log_queue, log_history @@ -270,8 +271,8 @@ async def handle_translate( "base_url": base_url, "apikey": apikey, "model_id": model_id, "to_lang": to_lang, "formula_ocr": formula_ocr, "code_ocr": code_ocr, "refine_markdown": refine_markdown, - "convert_engin": convert_engin, # Pass to task - "mineru_token": mineru_token, # Pass to task + "convert_engin": convert_engin, # Pass to task + "mineru_token": mineru_token, # Pass to task } loop = asyncio.get_running_loop() @@ -327,11 +328,12 @@ async def cancel_translate_task(): @app.get("/get-engin-list") async def get_engin_list(): - engin_list=["mineru"] + engin_list = ["mineru"] if available_packages.get("docling"): engin_list.append("docling") return JSONResponse(content=engin_list) + @app.get("/get-status") async def get_status(): global current_state @@ -384,7 +386,8 @@ async def download_markdown(filename_with_ext: str): return StreamingResponse( io.StringIO(current_state["markdown_content"]), media_type="text/markdown", - headers={"Content-Disposition": f"attachment; filename*=UTF-8''{quote(actual_filename, safe='', encoding='utf-8')}"} + headers={ + "Content-Disposition": f"attachment; filename*=UTF-8''{quote(actual_filename, safe='', encoding='utf-8')}"} ) @@ -402,10 +405,16 @@ async def download_html(filename_with_ext: str): return HTMLResponse( content=current_state["html_content"], media_type="text/html", - headers={"Content-Disposition": f"attachment; filename*=UTF-8''{quote(actual_filename, safe='', encoding='utf-8')}"} + headers={ + "Content-Disposition": f"attachment; filename*=UTF-8''{quote(actual_filename, safe='', encoding='utf-8')}"} ) +@app.get("/meta") +async def get_app_version(): + return JSONResponse(content={"version": __version__}) + + def find_free_port(start_port): """从指定端口开始查找可用的端口""" port = start_port @@ -414,6 +423,8 @@ def find_free_port(start_port): if sock.connect_ex(('127.0.0.1', port)) != 0: # 端口可用 return port port += 1 # 端口被占用,尝试下一个端口 + + def run_app(): initial_port = 8010 try: @@ -429,5 +440,4 @@ def run_app(): if __name__ == "__main__": - - run_app() \ No newline at end of file + run_app() diff --git a/docutranslate/global_values/__init__.py b/docutranslate/global_values/__init__.py index c0a7c3f..863f003 100644 --- a/docutranslate/global_values/__init__.py +++ b/docutranslate/global_values/__init__.py @@ -1,2 +1,2 @@ -from .conditional_import import available_packages,conditional_import +from .conditional_import import available_packages,conditional_import \ No newline at end of file diff --git a/docutranslate/static/MathJax.js b/docutranslate/static/MathJax.js new file mode 100644 index 0000000..6f14eb3 --- /dev/null +++ b/docutranslate/static/MathJax.js @@ -0,0 +1 @@ +if(document.getElementById&&document.childNodes&&document.createElement){if(!(window.MathJax&&MathJax.Hub)){if(window.MathJax){window.MathJax={AuthorConfig:window.MathJax}}else{window.MathJax={}}MathJax.isPacked=true;MathJax.version="2.7.1";MathJax.fileversion="2.7.1";MathJax.cdnVersion="2.7.1";MathJax.cdnFileVersions={};(function(d){var b=window[d];if(!b){b=window[d]={}}var e=[];var c=function(f){var g=f.constructor;if(!g){g=function(){}}for(var h in f){if(h!=="constructor"&&f.hasOwnProperty(h)){g[h]=f[h]}}return g};var a=function(){return function(){return arguments.callee.Init.call(this,arguments)}};b.Object=c({constructor:a(),Subclass:function(f,h){var g=a();g.SUPER=this;g.Init=this.Init;g.Subclass=this.Subclass;g.Augment=this.Augment;g.protoFunction=this.protoFunction;g.can=this.can;g.has=this.has;g.isa=this.isa;g.prototype=new this(e);g.prototype.constructor=g;g.Augment(f,h);return g},Init:function(f){var g=this;if(f.length===1&&f[0]===e){return g}if(!(g instanceof f.callee)){g=new f.callee(e)}return g.Init.apply(g,f)||g},Augment:function(f,g){var h;if(f!=null){for(h in f){if(f.hasOwnProperty(h)){this.protoFunction(h,f[h])}}if(f.toString!==this.prototype.toString&&f.toString!=={}.toString){this.protoFunction("toString",f.toString)}}if(g!=null){for(h in g){if(g.hasOwnProperty(h)){this[h]=g[h]}}}return this},protoFunction:function(g,f){this.prototype[g]=f;if(typeof f==="function"){f.SUPER=this.SUPER.prototype}},prototype:{Init:function(){},SUPER:function(f){return f.callee.SUPER},can:function(f){return typeof(this[f])==="function"},has:function(f){return typeof(this[f])!=="undefined"},isa:function(f){return(f instanceof Object)&&(this instanceof f)}},can:function(f){return this.prototype.can.call(this,f)},has:function(f){return this.prototype.has.call(this,f)},isa:function(g){var f=this;while(f){if(f===g){return true}else{f=f.SUPER}}return false},SimpleSUPER:c({constructor:function(f){return this.SimpleSUPER.define(f)},define:function(f){var h={};if(f!=null){for(var g in f){if(f.hasOwnProperty(g)){h[g]=this.wrap(g,f[g])}}if(f.toString!==this.prototype.toString&&f.toString!=={}.toString){h.toString=this.wrap("toString",f.toString)}}return h},wrap:function(i,h){if(typeof(h)!=="function"||!h.toString().match(/\.\s*SUPER\s*\(/)){return h}var g=function(){this.SUPER=g.SUPER[i];try{var f=h.apply(this,arguments)}catch(j){delete this.SUPER;throw j}delete this.SUPER;return f};g.toString=function(){return h.toString.apply(h,arguments)};return g}})});b.Object.isArray=Array.isArray||function(f){return Object.prototype.toString.call(f)==="[object Array]"};b.Object.Array=Array})("MathJax");(function(BASENAME){var BASE=window[BASENAME];if(!BASE){BASE=window[BASENAME]={}}var isArray=BASE.Object.isArray;var CALLBACK=function(data){var cb=function(){return arguments.callee.execute.apply(arguments.callee,arguments)};for(var id in CALLBACK.prototype){if(CALLBACK.prototype.hasOwnProperty(id)){if(typeof(data[id])!=="undefined"){cb[id]=data[id]}else{cb[id]=CALLBACK.prototype[id]}}}cb.toString=CALLBACK.prototype.toString;return cb};CALLBACK.prototype={isCallback:true,hook:function(){},data:[],object:window,execute:function(){if(!this.called||this.autoReset){this.called=!this.autoReset;return this.hook.apply(this.object,this.data.concat([].slice.call(arguments,0)))}},reset:function(){delete this.called},toString:function(){return this.hook.toString.apply(this.hook,arguments)}};var ISCALLBACK=function(f){return(typeof(f)==="function"&&f.isCallback)};var EVAL=function(code){return eval.call(window,code)};var TESTEVAL=function(){EVAL("var __TeSt_VaR__ = 1");if(window.__TeSt_VaR__){try{delete window.__TeSt_VaR__}catch(error){window.__TeSt_VaR__=null}}else{if(window.execScript){EVAL=function(code){BASE.__code=code;code="try {"+BASENAME+".__result = eval("+BASENAME+".__code)} catch(err) {"+BASENAME+".__result = err}";window.execScript(code);var result=BASE.__result;delete BASE.__result;delete BASE.__code;if(result instanceof Error){throw result}return result}}else{EVAL=function(code){BASE.__code=code;code="try {"+BASENAME+".__result = eval("+BASENAME+".__code)} catch(err) {"+BASENAME+".__result = err}";var head=(document.getElementsByTagName("head"))[0];if(!head){head=document.body}var script=document.createElement("script");script.appendChild(document.createTextNode(code));head.appendChild(script);head.removeChild(script);var result=BASE.__result;delete BASE.__result;delete BASE.__code;if(result instanceof Error){throw result}return result}}}TESTEVAL=null};var USING=function(args,i){if(arguments.length>1){if(arguments.length===2&&!(typeof arguments[0]==="function")&&arguments[0] instanceof Object&&typeof arguments[1]==="number"){args=[].slice.call(args,i)}else{args=[].slice.call(arguments,0)}}if(isArray(args)&&args.length===1){args=args[0]}if(typeof args==="function"){if(args.execute===CALLBACK.prototype.execute){return args}return CALLBACK({hook:args})}else{if(isArray(args)){if(typeof(args[0])==="string"&&args[1] instanceof Object&&typeof args[1][args[0]]==="function"){return CALLBACK({hook:args[1][args[0]],object:args[1],data:args.slice(2)})}else{if(typeof args[0]==="function"){return CALLBACK({hook:args[0],data:args.slice(1)})}else{if(typeof args[1]==="function"){return CALLBACK({hook:args[1],object:args[0],data:args.slice(2)})}}}}else{if(typeof(args)==="string"){if(TESTEVAL){TESTEVAL()}return CALLBACK({hook:EVAL,data:[args]})}else{if(args instanceof Object){return CALLBACK(args)}else{if(typeof(args)==="undefined"){return CALLBACK({})}}}}}throw Error("Can't make callback from given data")};var DELAY=function(time,callback){callback=USING(callback);callback.timeout=setTimeout(callback,time);return callback};var WAITFOR=function(callback,signal){callback=USING(callback);if(!callback.called){WAITSIGNAL(callback,signal);signal.pending++}};var WAITEXECUTE=function(){var signals=this.signal;delete this.signal;this.execute=this.oldExecute;delete this.oldExecute;var result=this.execute.apply(this,arguments);if(ISCALLBACK(result)&&!result.called){WAITSIGNAL(result,signals)}else{for(var i=0,m=signals.length;i0&&priority=0;i--){this.hooks.splice(i,1)}this.remove=[]}});var EXECUTEHOOKS=function(hooks,data,reset){if(!hooks){return null}if(!isArray(hooks)){hooks=[hooks]}if(!isArray(data)){data=(data==null?[]:[data])}var handler=HOOKS(reset);for(var i=0,m=hooks.length;ig){g=document.styleSheets.length}if(!i){i=document.head||((document.getElementsByTagName("head"))[0]);if(!i){i=document.body}}return i};var f=[];var c=function(){for(var k=0,j=f.length;k=this.timeout){i(this.STATUS.ERROR);return 1}return 0},file:function(j,i){if(i<0){a.Ajax.loadTimeout(j)}else{a.Ajax.loadComplete(j)}},execute:function(){this.hook.call(this.object,this,this.data[0],this.data[1])},checkSafari2:function(i,j,k){if(i.time(k)){return}if(document.styleSheets.length>j&&document.styleSheets[j].cssRules&&document.styleSheets[j].cssRules.length){k(i.STATUS.OK)}else{setTimeout(i,i.delay)}},checkLength:function(i,l,n){if(i.time(n)){return}var m=0;var j=(l.sheet||l.styleSheet);try{if((j.cssRules||j.rules||[]).length>0){m=1}}catch(k){if(k.message.match(/protected variable|restricted URI/)){m=1}else{if(k.message.match(/Security error/)){m=1}}}if(m){setTimeout(a.Callback([n,i.STATUS.OK]),0)}else{setTimeout(i,i.delay)}}},loadComplete:function(i){i=this.fileURL(i);var j=this.loading[i];if(j&&!j.preloaded){a.Message.Clear(j.message);clearTimeout(j.timeout);if(j.script){if(f.length===0){setTimeout(c,0)}f.push(j.script)}this.loaded[i]=j.status;delete this.loading[i];this.addHook(i,j.callback)}else{if(j){delete this.loading[i]}this.loaded[i]=this.STATUS.OK;j={status:this.STATUS.OK}}if(!this.loadHooks[i]){return null}return this.loadHooks[i].Execute(j.status)},loadTimeout:function(i){if(this.loading[i].timeout){clearTimeout(this.loading[i].timeout)}this.loading[i].status=this.STATUS.ERROR;this.loadError(i);this.loadComplete(i)},loadError:function(i){a.Message.Set(["LoadFailed","File failed to load: %1",i],null,2000);a.Hub.signal.Post(["file load error",i])},Styles:function(k,l){var i=this.StyleString(k);if(i===""){l=a.Callback(l);l()}else{var j=document.createElement("style");j.type="text/css";this.head=h(this.head);this.head.appendChild(j);if(j.styleSheet&&typeof(j.styleSheet.cssText)!=="undefined"){j.styleSheet.cssText=i}else{j.appendChild(document.createTextNode(i))}l=this.timer.create.call(this,l,j)}return l},StyleString:function(n){if(typeof(n)==="string"){return n}var k="",o,m;for(o in n){if(n.hasOwnProperty(o)){if(typeof n[o]==="string"){k+=o+" {"+n[o]+"}\n"}else{if(a.Object.isArray(n[o])){for(var l=0;l="0"&&q<="9"){f[j]=p[f[j]-1];if(typeof f[j]==="number"){f[j]=this.number(f[j])}}else{if(q==="{"){q=f[j].substr(1);if(q>="0"&&q<="9"){f[j]=p[f[j].substr(1,f[j].length-2)-1];if(typeof f[j]==="number"){f[j]=this.number(f[j])}}else{var k=f[j].match(/^\{([a-z]+):%(\d+)\|(.*)\}$/);if(k){if(k[1]==="plural"){var d=p[k[2]-1];if(typeof d==="undefined"){f[j]="???"}else{d=this.plural(d)-1;var h=k[3].replace(/(^|[^%])(%%)*%\|/g,"$1$2%\uEFEF").split(/\|/);if(d>=0&&d=3){c.push([f[0],f[1],this.processSnippet(g,f[2])])}else{c.push(e[d])}}}}else{c.push(e[d])}}return c},markdownPattern:/(%.)|(\*{1,3})((?:%.|.)+?)\2|(`+)((?:%.|.)+?)\4|\[((?:%.|.)+?)\]\(([^\s\)]+)\)/,processMarkdown:function(b,h,d){var j=[],e;var c=b.split(this.markdownPattern);var g=c[0];for(var f=1,a=c.length;f1?d[1]:""));f=null}if(e&&(!b.preJax||d)){c.nodeValue=c.nodeValue.replace(b.postJax,(e.length>1?e[1]:""))}if(f&&!f.nodeValue.match(/\S/)){f=f.previousSibling}}if(b.preRemoveClass&&f&&f.className===b.preRemoveClass){a.MathJax.preview=f}a.MathJax.checked=1},processInput:function(a){var b,i=MathJax.ElementJax.STATE;var h,e,d=a.scripts.length;try{while(a.ithis.processUpdateTime&&a.i1){d.jax[a.outputJax].push(b)}b.MathJax.state=c.OUTPUT},prepareOutput:function(c,f){while(c.jthis.processUpdateTime&&h.i=0;q--){if((b[q].src||"").match(f)){s.script=b[q].innerHTML;if(RegExp.$2){var t=RegExp.$2.substr(1).split(/\&/);for(var p=0,l=t.length;p=parseInt(y[z])}}return true},Select:function(j){var i=j[d.Browser];if(i){return i(d.Browser)}return null}};var e=k.replace(/^Mozilla\/(\d+\.)+\d+ /,"").replace(/[a-z][-a-z0-9._: ]+\/\d+[^ ]*-[^ ]*\.([a-z][a-z])?\d+ /i,"").replace(/Gentoo |Ubuntu\/(\d+\.)*\d+ (\([^)]*\) )?/,"");d.Browser=d.Insert(d.Insert(new String("Unknown"),{version:"0.0"}),a);for(var v in a){if(a.hasOwnProperty(v)){if(a[v]&&v.substr(0,2)==="is"){v=v.slice(2);if(v==="Mac"||v==="PC"){continue}d.Browser=d.Insert(new String(v),a);var r=new RegExp(".*(Version/| Trident/.*; rv:)((?:\\d+\\.)+\\d+)|.*("+v+")"+(v=="MSIE"?" ":"/")+"((?:\\d+\\.)*\\d+)|(?:^|\\(| )([a-z][-a-z0-9._: ]+|(?:Apple)?WebKit)/((?:\\d+\\.)+\\d+)");var u=r.exec(e)||["","","","unknown","0.0"];d.Browser.name=(u[1]!=""?v:(u[3]||u[5]));d.Browser.version=u[2]||u[4]||u[6];break}}}try{d.Browser.Select({Safari:function(j){var i=parseInt((String(j.version).split("."))[0]);if(i>85){j.webkit=j.version}if(i>=538){j.version="8.0"}else{if(i>=537){j.version="7.0"}else{if(i>=536){j.version="6.0"}else{if(i>=534){j.version="5.1"}else{if(i>=533){j.version="5.0"}else{if(i>=526){j.version="4.0"}else{if(i>=525){j.version="3.1"}else{if(i>500){j.version="3.0"}else{if(i>400){j.version="2.0"}else{if(i>85){j.version="1.0"}}}}}}}}}}j.webkit=(navigator.appVersion.match(/WebKit\/(\d+)\./))[1];j.isMobile=(navigator.appVersion.match(/Mobile/i)!=null);j.noContextMenu=j.isMobile},Firefox:function(j){if((j.version==="0.0"||k.match(/Firefox/)==null)&&navigator.product==="Gecko"){var m=k.match(/[\/ ]rv:(\d+\.\d.*?)[\) ]/);if(m){j.version=m[1]}else{var i=(navigator.buildID||navigator.productSub||"0").substr(0,8);if(i>="20111220"){j.version="9.0"}else{if(i>="20111120"){j.version="8.0"}else{if(i>="20110927"){j.version="7.0"}else{if(i>="20110816"){j.version="6.0"}else{if(i>="20110621"){j.version="5.0"}else{if(i>="20110320"){j.version="4.0"}else{if(i>="20100121"){j.version="3.6"}else{if(i>="20090630"){j.version="3.5"}else{if(i>="20080617"){j.version="3.0"}else{if(i>="20061024"){j.version="2.0"}}}}}}}}}}}}j.isMobile=(navigator.appVersion.match(/Android/i)!=null||k.match(/ Fennec\//)!=null||k.match(/Mobile/)!=null)},Chrome:function(i){i.noContextMenu=i.isMobile=!!navigator.userAgent.match(/ Mobile[ \/]/)},Opera:function(i){i.version=opera.version()},Edge:function(i){i.isMobile=!!navigator.userAgent.match(/ Phone/)},MSIE:function(j){j.isMobile=!!navigator.userAgent.match(/ Phone/);j.isIE9=!!(document.documentMode&&(window.performance||window.msPerformance));MathJax.HTML.setScriptBug=!j.isIE9||document.documentMode<9;MathJax.Hub.msieHTMLCollectionBug=(document.documentMode<9);if(document.documentMode<10&&!s.params.NoMathPlayer){try{new ActiveXObject("MathPlayer.Factory.1");j.hasMathPlayer=true}catch(m){}try{if(j.hasMathPlayer){var i=document.createElement("object");i.id="mathplayer";i.classid="clsid:32F66A20-7614-11D4-BD11-00104BD3F987";g.appendChild(i);document.namespaces.add("m","http://www.w3.org/1998/Math/MathML");j.mpNamespace=true;if(document.readyState&&(document.readyState==="loading"||document.readyState==="interactive")){document.write('');j.mpImported=true}}else{document.namespaces.add("mjx_IE_fix","http://www.w3.org/1999/xlink")}}catch(m){}}}})}catch(c){console.error(c.message)}d.Browser.Select(MathJax.Message.browsers);if(h.AuthorConfig&&typeof h.AuthorConfig.AuthorInit==="function"){h.AuthorConfig.AuthorInit()}d.queue=h.Callback.Queue();d.queue.Push(["Post",s.signal,"Begin"],["Config",s],["Cookie",s],["Styles",s],["Message",s],function(){var i=h.Callback.Queue(s.Jax(),s.Extensions());return i.Push({})},["Menu",s],s.onLoad(),function(){MathJax.isReady=true},["Typeset",s],["Hash",s],["MenuZoom",s],["Post",s.signal,"End"])})("MathJax")}}; diff --git a/docutranslate/static/index.html b/docutranslate/static/index.html index 68afb16..745978d 100644 --- a/docutranslate/static/index.html +++ b/docutranslate/static/index.html @@ -34,6 +34,15 @@ margin-top: 1rem; } + .meta { + margin-top: 2rem; + font-size: 0.8rem; + } + + .meta * { + font-size: inherit; + } + .error-message { color: #d32f2f; } @@ -404,6 +413,13 @@

运行日志

+ @@ -438,7 +454,6 @@ - + {{MathJax}} + + +{{markdown}} + +{{mermaid}} + + + \ No newline at end of file diff --git a/docutranslate/translater.py b/docutranslate/translater.py index 2614290..063f4b9 100644 --- a/docutranslate/translater.py +++ b/docutranslate/translater.py @@ -2,6 +2,7 @@ import asyncio from pathlib import Path from typing import Literal import markdown2 +import jinja2 from docutranslate.agents import Agent, AgentArgs from docutranslate.agents import MDRefineAgent, MDTranslateAgent from docutranslate.converter import Document, ConverterMineru @@ -9,10 +10,12 @@ from docutranslate.utils.markdown_splitter import split_markdown_text, join_mark from docutranslate.utils.markdown_utils import uris2placeholder, placeholder2_uris, MaskDict from docutranslate.logger import translater_logger from docutranslate.global_values import available_packages -DOCLING_FLAG=True if available_packages.get("docling") else False + +DOCLING_FLAG = True if available_packages.get("docling") else False if DOCLING_FLAG: from docutranslate.converter import ConverterDocling + class FileTranslater: def __init__(self, file_path: Path | str | None = None, chunksize: int = 2000, base_url="", key=None, model_id="", temperature=0.7, @@ -304,57 +307,18 @@ class FileTranslater: markdowner = markdown2.Markdown(extras=['tables', 'fenced-code-blocks', 'mermaid', "code-friendly"]) # TODO:实现完全本地化css和js # language=html - html = f""" - - - - {title} - - - - - - - -{markdowner.convert(self.markdown.replace("\\", "\\\\"))} - - - - -""" - return html + pico=Path(__file__).parent / "static" / "pico.css" + html = Path(__file__).parent / "template" / "markdown.html" + MathJax=Path(__file__).parent / "static" / "MathJax.js" + mermaid=Path(__file__).parent / "static" / "mermaid.js" + render = jinja2.Template(html.read_text()).render( + title=title, + pico=f"", + markdown=markdowner.convert(self.markdown.replace("\\", "\\\\")), + MathJax=f"", + mermaid=f"", + ) + return render def translate_file(self, file_path: Path | str | None = None, to_lang="中文", output_dir="./output", formula=True, diff --git a/pyproject.toml b/pyproject.toml index e748cc7..4ec514b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,5 @@ [project] name = "docutranslate" -version = "0.2.24" description = "文件翻译工具" readme = "README.md" requires-python = ">=3.10" @@ -9,7 +8,7 @@ dependencies = [ "markdown2>=2.5.3", "fastapi[standard]>=0.115.12", ] - +dynamic=["version"] [project.optional-dependencies] docling = [ @@ -35,5 +34,8 @@ backend-path = ["."] [tool.setuptools] packages = ["docutranslate"] [tool.setuptools.package-data] -docutranslate = ["static/**"] +docutranslate = ["static/**", "template/**"] + +[tool.setuptools.dynamic] +version = { attr = "docutranslate.__version__" }