Skip to content

Instantly share code, notes, and snippets.

@seanbecker15
Created December 3, 2023 23:37
Show Gist options
  • Save seanbecker15/49a20ef17e77682d7907f5eba8fd507b to your computer and use it in GitHub Desktop.
Save seanbecker15/49a20ef17e77682d7907f5eba8fd507b to your computer and use it in GitHub Desktop.
Chat-GPT Style Completion Using SSE Streaming API
// Read blog here: https://seanbecker.me/posts/chatgpt-text-completion
import { ChangeEvent, useState } from "react";
import { createParser, ParsedEvent, ReconnectInterval } from "eventsource-parser";
// Assumes that you can already fetch a completion from OpenAI
import { fetchCompletion } from "./api";
// Convert the stream to an async iterator.
// Found here https://jakearchibald.com/2017/async-iterators-and-generators/#making-streams-iterate
async function* streamAsyncIterator(stream: ReadableStream) {
const reader = stream.getReader();
try {
while (true) {
const { done, value } = await reader.read();
if (done) return;
yield value;
}
} finally {
reader.releaseLock();
}
}
const Chatbot = () => {
const [prompt, setPrompt] = useState("");
const [completion, setCompletion] = useState("");
const parseEvent = (event: ParsedEvent | ReconnectInterval) => {
if (event.type !== 'event' || event.data === '[DONE]') {
return
}
const delta = JSON.parse(event.data).choices[0]?.delta?.content || "";
setCompletion((prev) => {
if (prev) {
return prev + delta;
} else {
return delta;
}
});
};
const handleResponse = async (response: Response) => {
const stream = response.body;
if (!stream) {
return;
}
const textStream = stream.pipeThrough(new TextDecoderStream());
const asyncIteratorStream = streamAsyncIterator(textStream);
const parser = createParser(parseEvent);
for await (const chunk of asyncIteratorStream) {
parser.feed(chunk);
}
}
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
setPrompt(e.target.value);
};
const handleSubmit = () => fetchCompletion(prompt)
.then(handleResponse)
return (
<div>
<div>
<input type="text" value={prompt} onChange={handleChange} />
<button type="button" onClick={handleSubmit}>Submit</button>
</div>
<p>{completion}</p>
</div>
);
}
export default Chatbot;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment