diff --git a/LunaTranslator/LunaTranslator/translator/basetranslator_dev.py b/LunaTranslator/LunaTranslator/translator/basetranslator_dev.py index dcbc0025..7a346ddd 100644 --- a/LunaTranslator/LunaTranslator/translator/basetranslator_dev.py +++ b/LunaTranslator/LunaTranslator/translator/basetranslator_dev.py @@ -1,5 +1,5 @@ from translator.basetranslator import basetrans -import json, requests +import json, requests, threading from myutils.config import globalconfig import websocket, time from traceback import print_exc @@ -38,28 +38,27 @@ class basetransdev(basetrans): ######################################### def _private_init(self): self._id = 1 + self.sendrecvlock = threading.Lock() self._createtarget() super()._private_init() def _SendRequest(self, method, params, ws=None): if self.using == False: return - self._id += 1 + with self.sendrecvlock: + self._id += 1 - if ws is None: - ws = self.ws - ws.send(json.dumps({"id": self._id, "method": method, "params": params})) - res = ws.recv() + if ws is None: + ws = self.ws + ws.send(json.dumps({"id": self._id, "method": method, "params": params})) + res = ws.recv() - res = json.loads(res) - try: - return res["result"] - except: - if res["error"]["code"] == -32600: - self._id += 1 - self._SendRequest(method, params, ws) - else: - raise + res = json.loads(res) + try: + return res["result"] + except: + print(res) + raise Exception() def _createtarget(self): if self.using == False: diff --git a/LunaTranslator/LunaTranslator/translator/commonhookfetchstream.js b/LunaTranslator/LunaTranslator/translator/commonhookfetchstream.js index 10f38a63..501b56d3 100644 --- a/LunaTranslator/LunaTranslator/translator/commonhookfetchstream.js +++ b/LunaTranslator/LunaTranslator/translator/commonhookfetchstream.js @@ -1,44 +1,47 @@ +(function () { + window.hasdone = false + window.thistext = '' + if (window.injectedjs) return + window.injectedjs = true + const originalFetch = window.fetch; + window.fetch = function (input, init) { + const fetchPromise = originalFetch.apply(this, arguments); + if (!%s) return fetchPromise; + window.hasdone = false; + window.thistext = '' + fetchPromise.then(response => { + const clone = response.clone() + const contentType = clone.headers.get('content-type'); + if (contentType && contentType.includes('text/event-stream')) { + const reader = clone.body.getReader(); -const originalFetch = window.fetch; -var hasdone = true -var thistext = '' -window.fetch = function (input, init) { - const fetchPromise = originalFetch.apply(this, arguments); - if (!%s) return fetchPromise; - hasdone = false; - thistext = '' - fetchPromise.then(response => { - const clone = response.clone() - const contentType = clone.headers.get('content-type'); - if (contentType && contentType.includes('text/event-stream')) { - const reader = clone.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 { - %s - } catch { + reader.read().then(function processStream({ done, value }) { + if (done) { + hasdone = true; + return; } - } - return reader.read().then(processStream); - }).catch(error => { - console.error('Error reading stream:', error); - }); - } - }).catch(error => { - console.error('Fetch error:', error); - }); + 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 { + %s + } catch { - return fetchPromise; -}; + } + } + return reader.read().then(processStream); + }).catch(error => { + console.error('Error reading stream:', error); + }); + } + }).catch(error => { + console.error('Fetch error:', error); + }); + + return fetchPromise; + }; +})() \ No newline at end of file diff --git a/LunaTranslator/LunaTranslator/translator/commonhookxhrstream.js b/LunaTranslator/LunaTranslator/translator/commonhookxhrstream.js index d17b7d24..3cd0fb28 100644 --- a/LunaTranslator/LunaTranslator/translator/commonhookxhrstream.js +++ b/LunaTranslator/LunaTranslator/translator/commonhookxhrstream.js @@ -1,44 +1,47 @@ -const originXHR = XMLHttpRequest -var hasdone = true -var thistext = '' -window.XMLHttpRequest = function () { - var newxhr = new originXHR() - newxhr.open_ori = newxhr.open +(function () { + window.hasdone = false + window.thistext = '' + if (window.injectedjs) return + const originXHR = XMLHttpRequest + window.XMLHttpRequest = function () { + var newxhr = new originXHR() + newxhr.open_ori = newxhr.open - newxhr.open = function () { - var input = arguments[1] - if (%s) { - hasdone = false; - thistext = '' - newxhr.onprogress_ori = newxhr.onprogress - newxhr.onload_ori = newxhr.onload_ori - newxhr.offset = 0 - newxhr.onload = function () { - hasdone = true; - if (newxhr.onload_ori) - return newxhr.onload_ori.apply(this, arguments); - }; - newxhr.onprogress = function (event) { - var current = newxhr.responseText - var lines = current.substring(newxhr.offset) - 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 { - %s - } catch { + newxhr.open = function () { + var input = arguments[1] + if (%s) { + window.hasdone = false; + window.thistext = '' + newxhr.onprogress_ori = newxhr.onprogress + newxhr.onload_ori = newxhr.onload_ori + newxhr.offset = 0 + newxhr.onload = function () { + hasdone = true; + if (newxhr.onload_ori) + return newxhr.onload_ori.apply(this, arguments); + }; + newxhr.onprogress = function (event) { + var current = newxhr.responseText + var lines = current.substring(newxhr.offset) + 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 { + %s + } catch { + } } - } - newxhr.offset = current.length; - if (newxhr.onprogress_ori) - return newxhr.onprogress_ori.apply(this, arguments); - }; - } - return newxhr.open_ori.apply(this, arguments); - }; + newxhr.offset = current.length; + if (newxhr.onprogress_ori) + return newxhr.onprogress_ori.apply(this, arguments); + }; + } + return newxhr.open_ori.apply(this, arguments); + }; - return newxhr -} \ No newline at end of file + return newxhr + } +})() \ No newline at end of file diff --git a/LunaTranslator/LunaTranslator/translator/dev_chatglm.py b/LunaTranslator/LunaTranslator/translator/dev_chatglm.py index 9b306709..a62d948a 100644 --- a/LunaTranslator/LunaTranslator/translator/dev_chatglm.py +++ b/LunaTranslator/LunaTranslator/translator/dev_chatglm.py @@ -1,76 +1,19 @@ -from translator.basetranslator_dev import basetransdev -import time, os +from translator.dev_llm_common import commonllmdev -class TS(basetransdev): +class TS(commonllmdev): target_url = "https://chatglm.cn/main/alltoolsdetail" + jsfile = "commonhookfetchstream.js" + function1 = 'input.endsWith("assistant/stream")' + function2 = """const chunk = JSON.parse(line.substring(6)); + thistext = chunk.parts[0].content[0].text""" - def langmap(self): - return { - "zh": "Simplified Chinese", - "ja": "Japanese", - "en": "English", - "ru": "Russian", - "es": "Spanish", - "ko": "Korean", - "fr": "French", - "cht": "Traditional Chinese", - "vi": "Vietnamese", - "tr": "Turkish", - "pl": "Polish", - "uk": "Ukrainian", - "it": "Italian", - "ar": "Arabic", - "th": "Thai", - } - - def injectjs(self): - if self.Runtime_evaluate("window.injectedjs")["result"]["type"] != "undefined": - print(self.Runtime_evaluate("window.injectedjs")["result"]["type"]) - return - with open( - os.path.join(os.path.dirname(__file__), "commonhookfetchstream.js"), - "r", - encoding="utf8", - ) as ff: - js = ff.read() % ( - 'input.endsWith("assistant/stream")', - """const chunk = JSON.parse(line.substring(6)); - thistext = chunk.parts[0].content[0].text""", - ) - self.Runtime_evaluate(js) - self.Runtime_evaluate("window.injectedjs=true") - - def translate(self, content): - self.injectjs() - - self.Runtime_evaluate("hasdone=false") - self.Runtime_evaluate('thistext=""') - if self.config["use_custom_prompt"]: - prompt = self.config["custom_prompt"] - else: - prompt = "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 - ) - content = prompt + content + def dotranslate(self, content): self.Runtime_evaluate( 'document.querySelector("#search-input-box > div.input-wrap.flex.flex-x-between.flex-y-center > div.input-box-inner > textarea").focus()' ) self.send_keys(content) - - self.Runtime_evaluate("""document.querySelector("#search-input-box > div.input-wrap.flex.flex-x-between.flex-y-center > div.enter.m-three-row > img").click()""") - 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 not self.Runtime_evaluate("hasdone")["result"]["value"]: - time.sleep(0.1) - continue - yield self.Runtime_evaluate("thistext")["result"]["value"] + + self.Runtime_evaluate( + """document.querySelector("#search-input-box > div.input-wrap.flex.flex-x-between.flex-y-center > div.enter.m-three-row > img").click()""" + ) diff --git a/LunaTranslator/LunaTranslator/translator/dev_chatgpt.py b/LunaTranslator/LunaTranslator/translator/dev_chatgpt.py index 3f137869..156ba7c9 100644 --- a/LunaTranslator/LunaTranslator/translator/dev_chatgpt.py +++ b/LunaTranslator/LunaTranslator/translator/dev_chatgpt.py @@ -1,57 +1,14 @@ -from translator.basetranslator_dev import basetransdev -import time, os +from translator.dev_llm_common import commonllmdev -class TS(basetransdev): +class TS(commonllmdev): target_url = "https://chatgpt.com/" + jsfile = "commonhookfetchstream.js" + function1 = 'input.includes("conversation")' + function2 = r"""const chunk = JSON.parse(line.substring(6)); + thistext = chunk.message.content.parts[0]""" - def langmap(self): - return { - "zh": "Simplified Chinese", - "ja": "Japanese", - "en": "English", - "ru": "Russian", - "es": "Spanish", - "ko": "Korean", - "fr": "French", - "cht": "Traditional Chinese", - "vi": "Vietnamese", - "tr": "Turkish", - "pl": "Polish", - "uk": "Ukrainian", - "it": "Italian", - "ar": "Arabic", - "th": "Thai", - } - - def injectjs(self): - if self.Runtime_evaluate("window.injectedjs")["result"]["type"] != "undefined": - return - with open( - os.path.join(os.path.dirname(__file__), "commonhookfetchstream.js"), - "r", - encoding="utf8", - ) as ff: - js = ff.read() % ( - 'input.includes("conversation")', - r"""const chunk = JSON.parse(line.substring(6)); - thistext = chunk.message.content.parts[0]""", - ) - self.Runtime_evaluate(js) - self.Runtime_evaluate("window.injectedjs=true") - - def translate(self, content): - self.injectjs() - - self.Runtime_evaluate("hasdone=false") - self.Runtime_evaluate('thistext=""') - if self.config["use_custom_prompt"]: - prompt = self.config["custom_prompt"] - else: - prompt = "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 - ) - content = prompt + content + def dotranslate(self, content): self.Runtime_evaluate( 'textarea=document.querySelector("#prompt-textarea");textarea.value="";event = new Event("input", {{bubbles: true, cancelable: true }});textarea.dispatchEvent(event);textarea.value=`{}`;event = new Event("input", {{bubbles: true, cancelable: true }});textarea.dispatchEvent(event);'.format( content @@ -60,18 +17,3 @@ class TS(basetransdev): self.Runtime_evaluate( 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()""" ) - 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 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/dev_deepseek.py b/LunaTranslator/LunaTranslator/translator/dev_deepseek.py index 4a37f703..af5d3a80 100644 --- a/LunaTranslator/LunaTranslator/translator/dev_deepseek.py +++ b/LunaTranslator/LunaTranslator/translator/dev_deepseek.py @@ -1,73 +1,15 @@ -from translator.basetranslator_dev import basetransdev -import time, os +from translator.dev_llm_common import commonllmdev -class TS(basetransdev): +class TS(commonllmdev): target_url = "https://chat.deepseek.com/" - - def langmap(self): - return { - "zh": "Simplified Chinese", - "ja": "Japanese", - "en": "English", - "ru": "Russian", - "es": "Spanish", - "ko": "Korean", - "fr": "French", - "cht": "Traditional Chinese", - "vi": "Vietnamese", - "tr": "Turkish", - "pl": "Polish", - "uk": "Ukrainian", - "it": "Italian", - "ar": "Arabic", - "th": "Thai", - } - - def injectjs(self): - if self.Runtime_evaluate("window.injectedjs")["result"]["type"] != "undefined": - return - with open( - os.path.join(os.path.dirname(__file__), "commonhookxhrstream.js"), - "r", - encoding="utf8", - ) as ff: - js = ff.read() % ( - "input.endsWith('v0/chat/completions')", - r"""const chunk = JSON.parse(line.substring(6)); + jsfile = "commonhookxhrstream.js" + function1 = "input.endsWith('v0/chat/completions')" + function2 = r"""const chunk = JSON.parse(line.substring(6)); if(!!(chunk.choices[0].delta.content)) - thistext += chunk.choices[0].delta.content""", - ) - self.Runtime_evaluate(js) - self.Runtime_evaluate("window.injectedjs=true") + thistext += chunk.choices[0].delta.content""" - def translate(self, content): - self.injectjs() - - self.Runtime_evaluate("hasdone=false") - self.Runtime_evaluate('thistext=""') - if self.config["use_custom_prompt"]: - prompt = self.config["custom_prompt"] - else: - prompt = "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 - ) - content = prompt + content + def dotranslate(self, content): self.Runtime_evaluate('document.querySelector("#chat-input").click()') self.send_keys(content) self.Runtime_evaluate("document.getElementsByClassName('_89d4d19')[1].click()") - 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 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/dev_llm_common.py b/LunaTranslator/LunaTranslator/translator/dev_llm_common.py new file mode 100644 index 00000000..d0db8a76 --- /dev/null +++ b/LunaTranslator/LunaTranslator/translator/dev_llm_common.py @@ -0,0 +1,46 @@ +from translator.basetranslator_dev import basetransdev +import time, os + + +class commonllmdev(basetransdev): + + def injectjs(self): + with open( + os.path.join(os.path.dirname(__file__), self.jsfile), + "r", + encoding="utf8", + ) as ff: + js = ff.read() % ( + self.function1, + self.function2, + ) + self.Runtime_evaluate(js) + + def dotranslate(self, content): ... + + def translate(self, content): + self.injectjs() + + if self.config["use_custom_prompt"]: + prompt = self.config["custom_prompt"] + else: + prompt = "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 + ) + content = prompt + content + self.dotranslate(content) + 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 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/dev_moonshot.py b/LunaTranslator/LunaTranslator/translator/dev_moonshot.py index e65fdfed..a2e9195c 100644 --- a/LunaTranslator/LunaTranslator/translator/dev_moonshot.py +++ b/LunaTranslator/LunaTranslator/translator/dev_moonshot.py @@ -1,77 +1,19 @@ -from translator.basetranslator_dev import basetransdev -import time, os +from translator.dev_llm_common import commonllmdev -class TS(basetransdev): +class TS(commonllmdev): target_url = "https://kimi.moonshot.cn/" - - def langmap(self): - return { - "zh": "Simplified Chinese", - "ja": "Japanese", - "en": "English", - "ru": "Russian", - "es": "Spanish", - "ko": "Korean", - "fr": "French", - "cht": "Traditional Chinese", - "vi": "Vietnamese", - "tr": "Turkish", - "pl": "Polish", - "uk": "Ukrainian", - "it": "Italian", - "ar": "Arabic", - "th": "Thai", - } - - def injectjs(self): - if self.Runtime_evaluate("window.injectedjs")["result"]["type"] != "undefined": - return - with open( - os.path.join(os.path.dirname(__file__), "commonhookfetchstream.js"), - "r", - encoding="utf8", - ) as ff: - js = ff.read() % ( - 'input.endsWith("completion/stream")', - """const chunk = JSON.parse(line.substring(6)); + jsfile = "commonhookfetchstream.js" + function1 = 'input.endsWith("completion/stream")' + function2 = """const chunk = JSON.parse(line.substring(6)); if(chunk.event!='cmpl')continue; if(chunk.text) - thistext += chunk.text""", - ) - self.Runtime_evaluate(js) - self.Runtime_evaluate("window.injectedjs=true") + thistext += chunk.text""" - def translate(self, content): - self.injectjs() - - self.Runtime_evaluate("hasdone=false") - self.Runtime_evaluate('thistext=""') - if self.config["use_custom_prompt"]: - prompt = self.config["custom_prompt"] - else: - prompt = "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 - ) - content = prompt + content + def dotranslate(self, content): self.Runtime_evaluate( 'document.querySelector("#root > div.MuiBox-root.css-qmryj6 > div > div.layoutContent___NvxZ_ > div.MuiBox-root.css-ar9pyi > div > div > div > div.MuiBox-root.css-8atqhb > div.chatInput___bMC0h.matchHomePageLayout___WewPT > div > div > div.editor___KShcc.editor___DSPKC.matchHomePageLayout___XTlpC > div")? document.querySelector("#root > div.MuiBox-root.css-qmryj6 > div > div.layoutContent___NvxZ_ > div.MuiBox-root.css-ar9pyi > div > div > div > div.MuiBox-root.css-8atqhb > div.chatInput___bMC0h.matchHomePageLayout___WewPT > div > div > div.editor___KShcc.editor___DSPKC.matchHomePageLayout___XTlpC > div").click() : document.querySelector("#root > div.MuiBox-root.css-qmryj6 > div > div.layoutContent___NvxZ_ > div.MuiBox-root.css-ar9pyi > div > div > div > div > div.chatPageLayoutRightBoxLeft___taL5l > div.content___inD6V > div > div.chatBottom___jS9Jd.MuiBox-root.css-jdjpte > div.chatInput___bMC0h.matchHomePageLayout___WewPT > div > div > div.editor___KShcc.editor___DSPKC.matchHomePageLayout___XTlpC > div.editorContentEditable___FZJd9").click()' ) self.send_keys(content) self.wait_for_result('document.querySelector("#send-button").disabled', True) self.Runtime_evaluate("""document.querySelector("#send-button").click()""") - 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 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/dev_qwen.py b/LunaTranslator/LunaTranslator/translator/dev_qwen.py index 54eb3a59..70073374 100644 --- a/LunaTranslator/LunaTranslator/translator/dev_qwen.py +++ b/LunaTranslator/LunaTranslator/translator/dev_qwen.py @@ -1,74 +1,16 @@ -from translator.basetranslator_dev import basetransdev -import time, os +from translator.dev_llm_common import commonllmdev -class TS(basetransdev): +class TS(commonllmdev): target_url = "https://tongyi.aliyun.com/qianwen" + jsfile = "commonhookfetchstream.js" + function1 = 'input.endsWith("dialog/conversation")' + function2 = r"""const chunk = JSON.parse(line.substring(6)); + thistext = chunk.contents[0].content""" - def langmap(self): - return { - "zh": "Simplified Chinese", - "ja": "Japanese", - "en": "English", - "ru": "Russian", - "es": "Spanish", - "ko": "Korean", - "fr": "French", - "cht": "Traditional Chinese", - "vi": "Vietnamese", - "tr": "Turkish", - "pl": "Polish", - "uk": "Ukrainian", - "it": "Italian", - "ar": "Arabic", - "th": "Thai", - } - - def injectjs(self): - if self.Runtime_evaluate("window.injectedjs")["result"]["type"] != "undefined": - return - with open( - os.path.join(os.path.dirname(__file__), "commonhookfetchstream.js"), - "r", - encoding="utf8", - ) as ff: - js = ff.read() % ( - 'input.endsWith("dialog/conversation")', - r"""const chunk = JSON.parse(line.substring(6)); - thistext = chunk.contents[0].content""", - ) - self.Runtime_evaluate(js) - self.Runtime_evaluate("window.injectedjs=true") - - def translate(self, content): - self.injectjs() - - self.Runtime_evaluate("hasdone=false") - self.Runtime_evaluate('thistext=""') - if self.config["use_custom_prompt"]: - prompt = self.config["custom_prompt"] - else: - prompt = "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 - ) - content = prompt + content + def dotranslate(self, content): self.Runtime_evaluate('document.getElementsByTagName("textarea")[0].focus()') self.send_keys(content) self.Runtime_evaluate( r"""document.querySelector("#tongyiPageLayout > div.sc-fQpRED.jsoEZg > div > div.sc-hNGPaV.erDcgy.pageContentWrap--AovzQ5wq > div > div.inputField--PE5FhWzd > div > div.chatInput--eJzBH8LP > div.operateBtn--zFx6rSR0").click()""" ) - 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 not self.Runtime_evaluate("hasdone")["result"]["value"]: - time.sleep(0.1) - continue - yield self.Runtime_evaluate("thistext")["result"]["value"]