mirror of
https://github.com/logancyang/obsidian-copilot.git
synced 2026-07-22 07:50:24 +00:00
Add openaistream
This commit is contained in:
parent
b9e8b7dc78
commit
27eea8d7d2
3 changed files with 113 additions and 0 deletions
9
package-lock.json
generated
9
package-lock.json
generated
|
|
@ -11,6 +11,7 @@
|
|||
"dependencies": {
|
||||
"axios": "^1.3.4",
|
||||
"esbuild-plugin-svg": "^0.1.0",
|
||||
"eventsource-parser": "^1.0.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
},
|
||||
|
|
@ -1465,6 +1466,14 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eventsource-parser": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-1.0.0.tgz",
|
||||
"integrity": "sha512-9jgfSCa3dmEme2ES3mPByGXfgZ87VbP97tng1G2nWwWx6bV2nYxm2AWCrbQjXToSe+yYlqaZNtxffR9IeQr95g==",
|
||||
"engines": {
|
||||
"node": ">=14.18"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-deep-equal": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
"dependencies": {
|
||||
"axios": "^1.3.4",
|
||||
"esbuild-plugin-svg": "^0.1.0",
|
||||
"eventsource-parser": "^1.0.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
}
|
||||
|
|
|
|||
103
src/openAiStream.ts
Normal file
103
src/openAiStream.ts
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
import {
|
||||
createParser,
|
||||
ParsedEvent,
|
||||
ReconnectInterval,
|
||||
} from 'eventsource-parser';
|
||||
import { ChatMessage } from '@/sharedState';
|
||||
|
||||
export class OpenAIError extends Error {
|
||||
type: string;
|
||||
param: string;
|
||||
code: string;
|
||||
|
||||
constructor(message: string, type: string, param: string, code: string) {
|
||||
super(message);
|
||||
this.name = 'OpenAIError';
|
||||
this.type = type;
|
||||
this.param = param;
|
||||
this.code = code;
|
||||
}
|
||||
}
|
||||
|
||||
export const OpenAIStream = async (
|
||||
model: string,
|
||||
key: string,
|
||||
messages: ChatMessage[],
|
||||
) => {
|
||||
const res = await fetch(`https://api.openai.com/v1/chat/completions`, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${key ? key : process.env.OPENAI_API_KEY}`,
|
||||
...(process.env.OPENAI_ORGANIZATION && {
|
||||
'OpenAI-Organization': process.env.OPENAI_ORGANIZATION,
|
||||
}),
|
||||
},
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
model,
|
||||
messages: [
|
||||
{
|
||||
role: 'system',
|
||||
content: 'You are a helpful assistant.',
|
||||
},
|
||||
...messages,
|
||||
],
|
||||
max_tokens: 1000,
|
||||
temperature: 1,
|
||||
stream: true,
|
||||
}),
|
||||
});
|
||||
|
||||
const encoder = new TextEncoder();
|
||||
const decoder = new TextDecoder();
|
||||
|
||||
if (res.status !== 200) {
|
||||
const result = await res.json();
|
||||
if (result.error) {
|
||||
throw new OpenAIError(
|
||||
result.error.message,
|
||||
result.error.type,
|
||||
result.error.param,
|
||||
result.error.code,
|
||||
);
|
||||
} else {
|
||||
throw new Error(
|
||||
`OpenAI API returned an error: ${
|
||||
decoder.decode(result?.value) || result.statusText
|
||||
}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const stream = new ReadableStream({
|
||||
async start(controller) {
|
||||
const onParse = (event: ParsedEvent | ReconnectInterval) => {
|
||||
if (event.type === 'event') {
|
||||
const data = event.data;
|
||||
|
||||
if (data === '[DONE]') {
|
||||
controller.close();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const json = JSON.parse(data);
|
||||
const text = json.choices[0].delta.content;
|
||||
const queue = encoder.encode(text);
|
||||
controller.enqueue(queue);
|
||||
} catch (e) {
|
||||
controller.error(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const parser = createParser(onParse);
|
||||
|
||||
for await (const chunk of res.body as any) {
|
||||
parser.feed(decoder.decode(chunk));
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return stream;
|
||||
};
|
||||
Loading…
Reference in a new issue