Skip to content

Commit

Permalink
feat(MAG-3597): add option to set the amount of characters streamed b…
Browse files Browse the repository at this point in the history
…ack per second (#40)

* feat(MAG-3597): add option to set the amount of characters that should be streamed back per second (max)

* chore: bump version
  • Loading branch information
niels-bosman authored May 24, 2024
1 parent a72d57b commit a826d81
Show file tree
Hide file tree
Showing 5 changed files with 28 additions and 11 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ properties:
- headers: `object (optional)` - the headers to include in the
request.
- body: `object (optional)` - the body of the request.
- fakeCharactersPerSecond: `number (optional)` - the number of
characters to display per second. If this is unused the hook will display the messages as they come in.

#### method

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@magicul/react-chat-stream",
"description": "A React hook that lets you easily integrate your custom ChatGPT-like chat in React.",
"version": "0.3.1",
"version": "0.4.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"homepage": "https://github.com/XD2Sketch/react-chat-stream#readme",
Expand Down
20 changes: 17 additions & 3 deletions src/hooks/useChatStream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,27 @@ const useChatStream = (input: UseChatStreamInput) => {
};

const fetchAndUpdateAIResponse = async (message: string) => {
const charactersPerSecond = input.options.fakeCharactersPerSecond;
const stream = await getStream(message, input.options, input.method);
const initialMessage = addMessage({ content: '', role: 'bot' });
let response = '';

for await (const message of decodeStreamToJson(stream)) {
appendMessageToChat(message);
response += message;
for await (const chunk of decodeStreamToJson(stream)) {
if (!charactersPerSecond) {
appendMessageToChat(chunk);
response += chunk;
continue;
}

// Stream characters one by one based on the characters per second that is set.
for (const char of chunk) {
appendMessageToChat(char);
response += char;

if (charactersPerSecond > 0) {
await new Promise(resolve => setTimeout(resolve, 1000 / charactersPerSecond));
}
}
}

return { ...initialMessage, content: response };
Expand Down
9 changes: 5 additions & 4 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ export type UseChatStreamChatMessage = {
id: string,
}

export type UseChatStreamHttpOptions = {
export type UseChatStreamOptions = {
url: string;
method: HttpMethod;
query?: Record<string, string>;
headers?: HeadersInit;
body?: Record<string, string>;
fakeCharactersPerSecond?: number;
}

export type UseChatStreamEventHandlers = {
Expand All @@ -28,9 +29,9 @@ export type UseChatStreamInputMethod = {
}

export type UseChatStreamInput = {
options: UseChatStreamHttpOptions,
options: UseChatStreamOptions,
method: UseChatStreamInputMethod,
handlers: UseChatStreamEventHandlers
handlers: UseChatStreamEventHandlers,
};

export type UseChatStreamResult = ReturnType<typeof useChatStream>;
export type UseChatStreamResult = ReturnType<typeof useChatStream>;
6 changes: 3 additions & 3 deletions src/utils/streams.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { UseChatStreamHttpOptions, UseChatStreamInputMethod } from '../types';
import { UseChatStreamOptions, UseChatStreamInputMethod } from '../types';

const DEFAULT_HEADERS = {
'Content-Type': 'application/json',
};

const mergeInputInOptions = (input: string, options: UseChatStreamHttpOptions, method: UseChatStreamInputMethod) => {
const mergeInputInOptions = (input: string, options: UseChatStreamOptions, method: UseChatStreamInputMethod) => {
options.query = options.query ?? {};
(options[method.type] as Record<string, unknown>)[method.key] = input;

return options;
};

export const getStream = async (input: string, options: UseChatStreamHttpOptions, method: UseChatStreamInputMethod) => {
export const getStream = async (input: string, options: UseChatStreamOptions, method: UseChatStreamInputMethod) => {
options = mergeInputInOptions(input, options, method);

const params = '?' + new URLSearchParams(options.query).toString();
Expand Down

0 comments on commit a826d81

Please sign in to comment.