From be52a742449dfaeced50cd2d33a41a9ffd5118ec Mon Sep 17 00:00:00 2001 From: Irakli Murusidze Date: Thu, 21 Sep 2023 03:04:53 +0400 Subject: [PATCH 1/3] fixed empty response --- src/commands/chat.ts | 2 +- src/helpers/completion.ts | 53 +++++++++++++++-------------- src/helpers/strip-regex-patterns.ts | 9 +++++ 3 files changed, 37 insertions(+), 27 deletions(-) create mode 100644 src/helpers/strip-regex-patterns.ts diff --git a/src/commands/chat.ts b/src/commands/chat.ts index ff234d8..898010f 100644 --- a/src/commands/chat.ts +++ b/src/commands/chat.ts @@ -94,5 +94,5 @@ async function getResponse({ const iterableStream = streamToIterable(stream); - return { readResponse: readData(iterableStream, () => true) }; + return { readResponse: readData(iterableStream) }; } diff --git a/src/helpers/completion.ts b/src/helpers/completion.ts index e726fee..0f51460 100644 --- a/src/helpers/completion.ts +++ b/src/helpers/completion.ts @@ -8,6 +8,7 @@ import type { AxiosError } from 'axios'; import { streamToString } from './stream-to-string'; import './replace-all-polyfill'; import i18n from './i18n'; +import { stripRegexPatterns } from './strip-regex-patterns'; const explainInSecondRequest = true; @@ -20,7 +21,8 @@ function getOpenAi(key: string, apiEndpoint: string) { // Openai outputs markdown format for code blocks. It oftne uses // a github style like: "```bash" -const shellCodeStartRegex = /```[^\n]*/gi; +const shellCodeStartRegex = /```[a-zA-Z]*\n/gi; +const shellCodeEndRegex = /```[a-zA-Z]*/gi; export async function getScriptAndInfo({ prompt, @@ -42,14 +44,13 @@ export async function getScriptAndInfo({ apiEndpoint, }); const iterableStream = streamToIterable(stream); - const codeBlock = '```'; return { - readScript: readData(iterableStream, () => true, shellCodeStartRegex), - readInfo: readData( + readScript: readData( iterableStream, - (content) => content.endsWith(codeBlock), - shellCodeStartRegex + shellCodeStartRegex, + shellCodeEndRegex ), + readInfo: readData(iterableStream, shellCodeStartRegex, shellCodeEndRegex), }; } @@ -154,7 +155,7 @@ export async function getExplanation({ apiEndpoint, }); const iterableStream = streamToIterable(stream); - return { readExplanation: readData(iterableStream, () => true) }; + return { readExplanation: readData(iterableStream) }; } export async function getRevision({ @@ -180,22 +181,23 @@ export async function getRevision({ }); const iterableStream = streamToIterable(stream); return { - readScript: readData(iterableStream, () => true), + readScript: readData(iterableStream), }; } export const readData = ( iterableStream: AsyncGenerator, - startSignal: (content: string) => boolean, - excluded?: RegExp + excludedPrefix?: RegExp, + excludedSuffix?: RegExp ) => (writer: (data: string) => void): Promise => new Promise(async (resolve) => { let data = ''; let content = ''; let dataStart = false; - let waitUntilNewline = false; + // This buffer will temporarily hold incoming data only for detecting the start + let buffer = ''; for await (const chunk of iterableStream) { const payloads = chunk.toString().split('\n\n'); @@ -209,25 +211,24 @@ export const readData = if (payload.startsWith('data:')) { content = parseContent(payload); - if (!dataStart && content.match(excluded ?? '')) { - dataStart = startSignal(content); - if (!content.includes('\n')) { - waitUntilNewline = true; + // Use buffer only for start detection + if (!dataStart) { + // Append content to the buffer + buffer += content; + if (buffer.match(excludedPrefix ?? '')) { + dataStart = true; + // Clear the buffer once it has served its purpose + buffer = ''; + if (excludedPrefix) break; } - if (excluded) break; - } - - if (content && waitUntilNewline) { - if (!content.includes('\n')) { - continue; - } - waitUntilNewline = false; } if (dataStart && content) { - const contentWithoutExcluded = excluded - ? content.replaceAll(excluded, '') - : content; + const contentWithoutExcluded = stripRegexPatterns(content, [ + excludedPrefix, + excludedSuffix, + ]); + data += contentWithoutExcluded; writer(contentWithoutExcluded); } diff --git a/src/helpers/strip-regex-patterns.ts b/src/helpers/strip-regex-patterns.ts new file mode 100644 index 0000000..dbee154 --- /dev/null +++ b/src/helpers/strip-regex-patterns.ts @@ -0,0 +1,9 @@ +export const stripRegexPatterns = ( + inputString: string, + patternList: (RegExp | undefined)[] +) => + patternList.reduce( + (currentString, pattern) => + pattern ? currentString.replaceAll(pattern, '') : currentString, + inputString + ); From 6b3be66ad53fab786517d8bec070cdbfbbc3dbff Mon Sep 17 00:00:00 2001 From: Irakli Murusidze Date: Thu, 21 Sep 2023 03:56:21 +0400 Subject: [PATCH 2/3] fixed removing backticks from revision --- src/helpers/completion.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/helpers/completion.ts b/src/helpers/completion.ts index 0f51460..346f6c7 100644 --- a/src/helpers/completion.ts +++ b/src/helpers/completion.ts @@ -181,7 +181,11 @@ export async function getRevision({ }); const iterableStream = streamToIterable(stream); return { - readScript: readData(iterableStream), + readScript: readData( + iterableStream, + shellCodeStartRegex, + shellCodeEndRegex + ), }; } From 09c9daad530381bf08e5a22f944719a6c347a468 Mon Sep 17 00:00:00 2001 From: Irakli Murusidze Date: Thu, 21 Sep 2023 04:27:07 +0400 Subject: [PATCH 3/3] fixed editing script --- src/helpers/completion.ts | 30 +++++++++++------------------ src/helpers/strip-regex-patterns.ts | 4 ++-- 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/src/helpers/completion.ts b/src/helpers/completion.ts index 346f6c7..fe98323 100644 --- a/src/helpers/completion.ts +++ b/src/helpers/completion.ts @@ -21,8 +21,7 @@ function getOpenAi(key: string, apiEndpoint: string) { // Openai outputs markdown format for code blocks. It oftne uses // a github style like: "```bash" -const shellCodeStartRegex = /```[a-zA-Z]*\n/gi; -const shellCodeEndRegex = /```[a-zA-Z]*/gi; +const shellCodeExclusions = [/```[a-zA-Z]*\n/gi, /```[a-zA-Z]*/gi, '\n']; export async function getScriptAndInfo({ prompt, @@ -45,12 +44,8 @@ export async function getScriptAndInfo({ }); const iterableStream = streamToIterable(stream); return { - readScript: readData( - iterableStream, - shellCodeStartRegex, - shellCodeEndRegex - ), - readInfo: readData(iterableStream, shellCodeStartRegex, shellCodeEndRegex), + readScript: readData(iterableStream, ...shellCodeExclusions), + readInfo: readData(iterableStream, ...shellCodeExclusions), }; } @@ -181,19 +176,14 @@ export async function getRevision({ }); const iterableStream = streamToIterable(stream); return { - readScript: readData( - iterableStream, - shellCodeStartRegex, - shellCodeEndRegex - ), + readScript: readData(iterableStream, ...shellCodeExclusions), }; } export const readData = ( iterableStream: AsyncGenerator, - excludedPrefix?: RegExp, - excludedSuffix?: RegExp + ...excluded: (RegExp | string | undefined)[] ) => (writer: (data: string) => void): Promise => new Promise(async (resolve) => { @@ -203,6 +193,8 @@ export const readData = // This buffer will temporarily hold incoming data only for detecting the start let buffer = ''; + const [excludedPrefix] = excluded; + for await (const chunk of iterableStream) { const payloads = chunk.toString().split('\n\n'); @@ -228,10 +220,10 @@ export const readData = } if (dataStart && content) { - const contentWithoutExcluded = stripRegexPatterns(content, [ - excludedPrefix, - excludedSuffix, - ]); + const contentWithoutExcluded = stripRegexPatterns( + content, + excluded + ); data += contentWithoutExcluded; writer(contentWithoutExcluded); diff --git a/src/helpers/strip-regex-patterns.ts b/src/helpers/strip-regex-patterns.ts index dbee154..3654186 100644 --- a/src/helpers/strip-regex-patterns.ts +++ b/src/helpers/strip-regex-patterns.ts @@ -1,9 +1,9 @@ export const stripRegexPatterns = ( inputString: string, - patternList: (RegExp | undefined)[] + patternList: (RegExp | string | undefined)[] ) => patternList.reduce( - (currentString, pattern) => + (currentString: string, pattern) => pattern ? currentString.replaceAll(pattern, '') : currentString, inputString );