Skip to content

Commit

Permalink
Optimize chat experience (#129)
Browse files Browse the repository at this point in the history
Co-authored-by: Germey <[email protected]>
Co-authored-by: AceDataCloud <[email protected]>
  • Loading branch information
3 people authored Aug 25, 2024
1 parent ddcfb52 commit 27bb9ee
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 25 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "optimize chat experience",
"packageName": "@acedatacloud/nexior",
"email": "[email protected]",
"dependentChangeType": "patch"
}
145 changes: 120 additions & 25 deletions src/operators/chat.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import axios, { AxiosProgressEvent, AxiosResponse } from 'axios';
import axios, { AxiosResponse } from 'axios';
import {
IChatConversation,
IChatConversationAction,
Expand All @@ -13,31 +13,126 @@ class ChatOperator {
async chatConversation(
data: IChatConversationRequest,
options: IChatConversationOptions
): Promise<AxiosResponse<IChatConversationResponse>> {
return await axios.post('/aichat/conversations', data, {
headers: {
authorization: `Bearer ${options.token}`,
accept: 'application/x-ndjson',
'content-type': 'application/json'
},
baseURL: BASE_URL_API,
signal: options.signal,
responseType: 'stream',
onDownloadProgress: ({ event }: AxiosProgressEvent) => {
const response = event.target.response;
const lines = response.split('\r\n').filter((line: string) => !!line);
const lastLine = lines[lines.length - 1];
if (lastLine) {
try {
const jsonData = JSON.parse(lastLine);
if (options?.stream) {
options?.stream(jsonData as IChatConversationResponse);
}
} catch (e) {
console.error(e);
): Promise<IChatConversationResponse> {
return new Promise((resolve, reject) => {
let finalAnswer = '';
let id: string | undefined = undefined;
fetch(`${BASE_URL_API}/aichat/conversations`, {
method: 'POST',
headers: {
authorization: `Bearer ${options.token}`,
'Content-Type': 'application/json',
Accept: 'text/event-stream'
},
body: JSON.stringify(data)
})
.then((response) => {
if (!response?.body) {
throw new Error('ReadableStream not yet supported in this browser.');
}
}
}
const reader = response?.body?.getReader();
const decoder = new TextDecoder();

return new ReadableStream({
start(controller) {
const push = () => {
reader.read().then(({ done, value }) => {
if (done) {
controller.close();
return;
}
controller.enqueue(decoder.decode(value, { stream: true }));
push();
});
};
push();
}
});
})
.then((stream) => {
const linesStream = stream.pipeThrough(
new TransformStream({
transform(chunk, controller) {
chunk.split('\n').forEach((line: string) => {
if (line.trim()) {
controller.enqueue(line);
}
});
}
})
);

const reader = linesStream.getReader();
let accumulatedData = '';
let updateTimeout: number | null = null;

reader.read().then(function processText({ done, value }) {
if (done) {
console.log('Stream complete');
if (options?.stream) {
options?.stream({
answer: finalAnswer,
delta_answer: '',
id
});
}
resolve({
answer: finalAnswer as string,
delta_answer: ''
});
return;
}

if (value.startsWith('data: ')) {
const subValue = value.substring(6);
if (subValue === '[DONE]') {
console.log('finalAnswer', finalAnswer);
console.log('Stream complete');
if (options?.stream) {
options?.stream({
answer: finalAnswer,
delta_answer: '',
id
});
}
resolve({
answer: finalAnswer as string,
delta_answer: ''
});
} else {
const json = JSON.parse(subValue);
if (json.delta_answer) {
finalAnswer += json.delta_answer;
}
if (json.id) {
id = json.id;
}

accumulatedData += json.delta_answer || '';

if (!updateTimeout) {
updateTimeout = window.setTimeout(() => {
if (options?.stream) {
options?.stream({
answer: finalAnswer,
delta_answer: accumulatedData,
id
});
}
accumulatedData = '';
updateTimeout = null;
}, 0);
}
}
}

reader.read().then(processText);
});
})
.catch((error) => {
console.error('Error:', error);
reject(error);
});
});
}

Expand Down

0 comments on commit 27bb9ee

Please sign in to comment.