diff --git a/LunaTranslator/LunaTranslator/translator/dev_chatgpt.py b/LunaTranslator/LunaTranslator/translator/dev_chatgpt.py index d3354269..9a8c598e 100644 --- a/LunaTranslator/LunaTranslator/translator/dev_chatgpt.py +++ b/LunaTranslator/LunaTranslator/translator/dev_chatgpt.py @@ -1,5 +1,5 @@ from translator.basetranslator_dev import basetransdev -import time +import time, os class TS(basetransdev): @@ -24,27 +24,23 @@ class TS(basetransdev): "th": "Thai", } - def inittranslator(self): - self.currenttext = None - - def getcurr(self, idx): - - res = self.wait_for_result( - r"""document.querySelector("#__next > div.relative.z-0.flex.h-full.w-full.overflow-hidden > div.relative.flex.h-full.max-w-full.flex-1.flex-col.overflow-hidden > main > div.flex.h-full.flex-col > div.flex-1.overflow-hidden > div > div > div > div > div:nth-child({}) > div > div > div.relative.flex.w-full.flex-col.agent-turn > div.flex-col.gap-1.md\\:gap-3 > div.flex.flex-grow.flex-col.max-w-full > div > div").textContent""".format( - idx + 2 - ) - ) - if "This content may violate our usage policies." == res: - raise Exception("This content may violate our usage policies.") - return res + def injectjs(self): + if self.Runtime_evaluate("window.injectedjs")["result"]["type"] != "undefined": + return + with open( + os.path.join(os.path.dirname(__file__), "hookchatgptfetch.js"), + "r", + encoding="utf8", + ) as ff: + js = ff.read() + self.Runtime_evaluate(js) + self.Runtime_evaluate("window.injectedjs=true") def translate(self, content): - while True: - idx = self.wait_for_result( - """document.querySelector("#__next > div.relative.z-0.flex.h-full.w-full.overflow-hidden > div.relative.flex.h-full.max-w-full.flex-1.flex-col.overflow-hidden > main > div.flex.h-full.flex-col > div.flex-1.overflow-hidden > div > div > div > div").children.length""" - ) - if isinstance(idx, int): - break + self.injectjs() + + self.Runtime_evaluate("hasdone=false") + self.Runtime_evaluate('thistext=""') content = ( "You are a translator. Please help me translate the following {} text into {}, and you should only tell me the translation.\n".format( self.srclang, self.tgtlang @@ -57,27 +53,20 @@ class TS(basetransdev): ) ) self.Runtime_evaluate( - r"""document.querySelector("#__next > div.relative.z-0.flex.h-full.w-full.overflow-hidden > div.relative.flex.h-full.max-w-full.flex-1.flex-col.overflow-hidden > main > div.flex.h-full.flex-col.focus-visible\\:outline-0 > div.w-full.md\\:pt-0.dark\\:border-white\\/20.md\\:border-transparent.md\\:dark\\:border-transparent.md\\:w-\\[calc\\(100\\%-\\.5rem\\)\\].juice\\:w-full > div.px-3.text-base.md\\:px-4.m-auto.md\\:px-5.lg\\:px-1.xl\\:px-5 > div > form > div > div.flex.w-full.items-center > div > button").click()""" + r"""document.querySelector("#__next > div.relative.z-0.flex.h-full.w-full.overflow-hidden > div > main > div.flex.h-full.flex-col.focus-visible\\:outline-0 > div.md\\:pt-0.dark\\:border-white\\/20.md\\:border-transparent.md\\:dark\\:border-transparent.w-full > div.text-base.px-3.md\\:px-4.m-auto.md\\:px-5.lg\\:px-1.xl\\:px-5 > div > form > div > div.flex.w-full.items-center > div > div > button").click()""" ) - self.currenttext = content - currtext = "" - if self.tgtlang == "Arabic": - - while self.currenttext == content: - time.sleep(1) # get text before violate usage policies. - - newcurr = self.getcurr(idx) - needbreak = newcurr == currtext and newcurr != "" - currtext = newcurr - if needbreak: - break - yield currtext + if self.config["usingstream"]: + curr = "" + while not self.Runtime_evaluate("hasdone")["result"]["value"]: + time.sleep(0.1) + thistext = self.Runtime_evaluate("thistext")["result"]["value"] + if thistext.startswith(curr): + yield thistext[len(curr) :] + else: + yield thistext + curr = thistext else: - while self.currenttext == content: - time.sleep(0.01) # get text before violate usage policies. - - newcurr = self.getcurr(idx) - if newcurr == currtext: - continue - yield newcurr[len(currtext) :] - currtext = newcurr + while not self.Runtime_evaluate("hasdone")["result"]["value"]: + time.sleep(0.1) + continue + yield self.Runtime_evaluate("thistext")["result"]["value"] diff --git a/LunaTranslator/LunaTranslator/translator/hookchatgptfetch.js b/LunaTranslator/LunaTranslator/translator/hookchatgptfetch.js new file mode 100644 index 00000000..2c0e5454 --- /dev/null +++ b/LunaTranslator/LunaTranslator/translator/hookchatgptfetch.js @@ -0,0 +1,67 @@ + +const originalFetch = window.fetch; +var hasdone = true +var thistext = '' +window.fetch = function (input, init) { + const fetchPromise = originalFetch.apply(this, arguments); + if (!input.includes("conversation")) return fetchPromise; + hasdone = false; + thistext = '' + // 构造一个自定义的可读流 + //controller.close()会导致真正的fetch被终止 + // 不太会js,只能让他假等待了,ui里面会显示在等待,但luna里面能读到,而且按钮也能正确按下 + const customReadableStream = new ReadableStream({ + start(controller) { + setTimeout(() => { + + controller.close(); + }, 99999999999); + + }, + }); + fetchPromise.then(response => { + const contentType = response.headers.get('content-type'); + + if (contentType && contentType.includes('text/event-stream')) { + console.log(response.body) + const reader = response.body.getReader(); + + reader.read().then(function processStream({ done, value }) { + + if (done) { + hasdone = true; + return; + } + let lines = new TextDecoder('utf-8').decode(value); + lines = lines.split('\n') + for (let i = 0; i < lines.length; i++) { + let line = lines[i] + line = line.trim() + if (line.length == 0) continue; + try { + const chunk = JSON.parse(line.substring(6)); + console.log("Chunk received:", chunk.message.content.parts[0]); + thistext = chunk.message.content.parts[0] + } catch { + + } + } + return reader.read().then(processStream); + }).catch(error => { + console.error('Error reading stream:', error); + }); + } + }).catch(error => { + console.error('Fetch error:', error); + }); + + return new Promise((resolve, reject) => { + resolve(new Response(customReadableStream, { + status: 200, + headers: { + 'Content-type': 'text/event-stream' + } + })); + + }); +}; diff --git a/LunaTranslator/files/defaultconfig/config.json b/LunaTranslator/files/defaultconfig/config.json index 6a6ceb84..2dd226f5 100644 --- a/LunaTranslator/files/defaultconfig/config.json +++ b/LunaTranslator/files/defaultconfig/config.json @@ -1570,7 +1570,8 @@ "use": false, "color": "blue", "type": "dev", - "name": "chatgpt" + "name": "chatgpt", + "is_gpt_like": true }, "deepl_dev": { "use": false, diff --git a/LunaTranslator/files/defaultconfig/translatorsetting.json b/LunaTranslator/files/defaultconfig/translatorsetting.json index 2d89b006..85070ea9 100644 --- a/LunaTranslator/files/defaultconfig/translatorsetting.json +++ b/LunaTranslator/files/defaultconfig/translatorsetting.json @@ -732,6 +732,17 @@ } } }, + "dev_chatgpt": { + "args": { + "usingstream": true + }, + "argstype": { + "usingstream": { + "name": "流式输出", + "type": "switch" + } + } + }, "gemini": { "args": { "注册网址": "https://ai.google.dev/tutorials/python_quickstart",