From 9b73abe0467476a8ad4efa8a88a2d516f39d7e10 Mon Sep 17 00:00:00 2001 From: Bram Adams <3282661+bramses@users.noreply.github.com> Date: Sat, 18 Mar 2023 20:00:11 -0400 Subject: [PATCH] stream cleanup --- main.ts | 66 +------------------ stream.ts | 191 ++++++++++++++++++++++++++++-------------------------- 2 files changed, 101 insertions(+), 156 deletions(-) diff --git a/main.ts b/main.ts index c4af763..280e661 100644 --- a/main.ts +++ b/main.ts @@ -89,8 +89,6 @@ export default class ChatGPT_MD extends Plugin { }; editor.setCursor(newCursor); - let fullstr = ""; - const options = { model: model, messages: messages, @@ -113,7 +111,7 @@ export default class ChatGPT_MD extends Plugin { this.settings.generateAtCursor ); - console.log("response", response); + console.log("response from stream", response); return { fullstr: response, mode: "streaming" } } else { @@ -161,68 +159,6 @@ export default class ChatGPT_MD extends Plugin { } const response = responseUrl.text; - - // if (stream) { - // // split response by new line - // const responseLines = response.split("\n\n"); - - // if (responseLines.length == 0) { - // throw new Error("[ChatGPT MD] no response"); - // } - - // // remove data: from each line - // for (let i = 0; i < responseLines.length; i++) { - // responseLines[i] = responseLines[i].split("data: ")[1]; - // } - - // const newLine = `\n\n
\n\nrole::assistant\n\n`; - // editor.replaceRange(newLine, editor.getCursor()); - - // // move cursor to end of line - // const cursor = editor.getCursor(); - // const newCursor = { - // line: cursor.line, - // ch: cursor.ch + newLine.length, - // }; - // editor.setCursor(newCursor); - - // let fullstr = ""; - - // // loop through response lines - // for (const responseLine of responseLines) { - // // if response line is not [DONE] then parse json and append delta to file - // if (responseLine && !responseLine.includes("[DONE]")) { - // const responseJSON = JSON.parse(responseLine); - // const delta = responseJSON.choices[0].delta.content; - - // // if delta is not undefined then append delta to file - // if (delta) { - // const cursor = editor.getCursor(); - // if (delta === "`") { - // editor.replaceRange(delta, cursor); - // await new Promise((r) => setTimeout(r, 82)); // what in the actual fuck -- why does this work - // } else { - // editor.replaceRange(delta, cursor); - // await new Promise((r) => - // setTimeout(r, this.settings.streamSpeed) - // ); - // } - - // const newCursor = { - // line: cursor.line, - // ch: cursor.ch + delta.length, - // }; - // editor.setCursor(newCursor); - - // fullstr += delta; - // } - // } - // } - - // console.log(fullstr); - - // return { fullstr: fullstr, mode: "streaming" }; - // } else { const responseJSON = JSON.parse(response); return responseJSON.choices[0].message.content; } diff --git a/stream.ts b/stream.ts index fff994c..abde23c 100644 --- a/stream.ts +++ b/stream.ts @@ -29,95 +29,104 @@ export const streamSSE = async ( options: OpenAIStreamPayload, setAtCursor: boolean ) => { - console.log("streamSSE", options); - - const url = "https://api.openai.com/v1/chat/completions"; - - const source = new SSE(url, { - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${apiKey}`, - }, - method: "POST", - payload: JSON.stringify(options), - }); - - let txt = ""; - const initialCursorPosCh = editor.getCursor().ch; - const initialCursorPosLine = editor.getCursor().line; - source.addEventListener("message", (e: any) => { - if (e.data != "[DONE]") { - const payload = JSON.parse(e.data); - const text = payload.choices[0].delta.content; - - // if text undefined, then do nothing - if (!text) { - return; - } - - const cursor = editor.getCursor(); - const convPos = editor.posToOffset(cursor); - - const cm6 = editor.cm; - const transaction = cm6.state.update({ - changes: { from: convPos, to: convPos, insert: text }, - }); - cm6.dispatch(transaction); - - - txt += text; - - const newCursor = { - line: cursor.line, - ch: cursor.ch + text.length, - }; - editor.setCursor(newCursor); - } else { - source.close(); - console.log("txt", txt); - - // replace the text from initialCursor to fix any formatting issues from streaming - const cursor = editor.getCursor(); - editor.replaceRange( - txt, - { line: initialCursorPosLine, ch: initialCursorPosCh }, - cursor - ); - - // set cursor to end of replacement text - const newCursor = { - line: initialCursorPosLine, - ch: initialCursorPosCh + txt.length, - }; - editor.setCursor(newCursor); - - // remove extraneous text - // const textAfterCursor = editor.getRange(newCursor, { - // line: Infinity, - // ch: Infinity, - // }); - - if (!setAtCursor) { - // remove the text after the cursor - editor.replaceRange("", newCursor, { - line: Infinity, - ch: Infinity, - }); - } else { - new Notice( - "[ChatGPT MD] Text pasted at cursor may leave artifacts. Please remove them manually. ChatGPT MD cannot safely remove text when pasting at cursor." - ); - } - - return txt; - } - }); - - source.addEventListener("readystatechange", (e: any) => { - if (e.readyState >= 2) { - console.log("ReadyState: " + e.readyState); - } - }); - - source.stream(); + return new Promise((resolve, reject) => { + try { + console.log("streamSSE", options); + + const url = "https://api.openai.com/v1/chat/completions"; + + const source = new SSE(url, { + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${apiKey}`, + }, + method: "POST", + payload: JSON.stringify(options), + }); + + let txt = ""; + const initialCursorPosCh = editor.getCursor().ch; + const initialCursorPosLine = editor.getCursor().line; + source.addEventListener("message", (e: any) => { + if (e.data != "[DONE]") { + const payload = JSON.parse(e.data); + const text = payload.choices[0].delta.content; + + // if text undefined, then do nothing + if (!text) { + return; + } + + const cursor = editor.getCursor(); + const convPos = editor.posToOffset(cursor); + + // @ts-ignore + const cm6 = editor.cm; + const transaction = cm6.state.update({ + changes: { from: convPos, to: convPos, insert: text }, + }); + cm6.dispatch(transaction); + + + txt += text; + + const newCursor = { + line: cursor.line, + ch: cursor.ch + text.length, + }; + editor.setCursor(newCursor); + } else { + source.close(); + + // replace the text from initialCursor to fix any formatting issues from streaming + const cursor = editor.getCursor(); + editor.replaceRange( + txt, + { line: initialCursorPosLine, ch: initialCursorPosCh }, + cursor + ); + + // set cursor to end of replacement text + const newCursor = { + line: initialCursorPosLine, + ch: initialCursorPosCh + txt.length, + }; + editor.setCursor(newCursor); + + // remove extraneous text + // const textAfterCursor = editor.getRange(newCursor, { + // line: Infinity, + // ch: Infinity, + // }); + + if (!setAtCursor) { + // remove the text after the cursor + editor.replaceRange("", newCursor, { + line: Infinity, + ch: Infinity, + }); + } else { + new Notice( + "[ChatGPT MD] Text pasted at cursor may leave artifacts. Please remove them manually. ChatGPT MD cannot safely remove text when pasting at cursor." + ); + } + + resolve(txt); + // return txt; + } + }); + + source.addEventListener("readystatechange", (e: any) => { + if (e.readyState >= 2) { + console.log("ReadyState: " + e.readyState); + } + }); + + source.stream(); + } catch (err) { + console.error(err); + new Notice("[ChatGPT MD] Error streaming text. Please check console."); + reject(err); + } + }); };