@magicul/react-chat-stream
Advanced tools
Comparing version 0.2.3 to 0.3.0
@@ -1,33 +0,14 @@ | ||
import { ChangeEvent, Dispatch, FormEvent, SetStateAction } from 'react'; | ||
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'; | ||
type ChatMessage = { | ||
role: 'bot' | 'user'; | ||
content: string; | ||
id: string; | ||
}; | ||
export type UseChatStreamOptions = { | ||
url: string; | ||
method: HttpMethod; | ||
query?: Record<string, string>; | ||
headers?: HeadersInit; | ||
body?: Record<string, string>; | ||
}; | ||
export type UseChatStreamInputMethod = { | ||
type: 'body' | 'query'; | ||
key: string; | ||
}; | ||
type UseChatStreamInput = { | ||
options: UseChatStreamOptions; | ||
method: UseChatStreamInputMethod; | ||
}; | ||
import { ChangeEvent, FormEvent } from 'react'; | ||
import { UseChatStreamChatMessage, UseChatStreamInput } from '../types'; | ||
declare const useChatStream: (input: UseChatStreamInput) => { | ||
messages: ChatMessage[]; | ||
setMessages: Dispatch<SetStateAction<ChatMessage[]>>; | ||
messages: UseChatStreamChatMessage[]; | ||
setMessages: import("react").Dispatch<import("react").SetStateAction<UseChatStreamChatMessage[]>>; | ||
input: string; | ||
setInput: Dispatch<SetStateAction<string>>; | ||
setInput: import("react").Dispatch<import("react").SetStateAction<string>>; | ||
handleInputChange: (e: ChangeEvent<HTMLInputElement> | ChangeEvent<HTMLTextAreaElement>) => void; | ||
handleSubmit: (e?: FormEvent<HTMLFormElement>, newMessage?: string) => Promise<void>; | ||
isLoading: boolean; | ||
handleSubmit: (e?: FormEvent<HTMLFormElement>) => Promise<void>; | ||
submitMessage: (message: string) => Promise<void>; | ||
isStreaming: boolean; | ||
}; | ||
export default useChatStream; | ||
//# sourceMappingURL=useChatStream.d.ts.map |
@@ -68,14 +68,26 @@ "use strict"; | ||
var streams_1 = require("../utils/streams"); | ||
var uuid_1 = require("uuid"); | ||
var BOT_ERROR_MESSAGE = 'Something went wrong fetching AI response.'; | ||
var useChatStream = function (input) { | ||
var _a = (0, react_1.useState)([]), messages = _a[0], setMessages = _a[1]; | ||
var _b = (0, react_1.useState)(''), message = _b[0], setMessage = _b[1]; | ||
var _c = (0, react_1.useState)(false), isLoading = _c[0], setIsLoading = _c[1]; | ||
var _b = (0, react_1.useState)(''), formInput = _b[0], setFormInput = _b[1]; | ||
var _c = (0, react_1.useState)(false), isStreaming = _c[0], setIsStreaming = _c[1]; | ||
var handleInputChange = function (e) { | ||
setMessage(e.target.value); | ||
setFormInput(e.target.value); | ||
}; | ||
var addMessageToChat = function (message, role) { | ||
if (role === void 0) { role = 'user'; } | ||
setMessages(function (messages) { return __spreadArray(__spreadArray([], messages, true), [{ role: role, content: message, id: (0, uuid_1.v4)() }], false); }); | ||
var handleSubmit = function (e) { return __awaiter(void 0, void 0, void 0, function () { | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
e === null || e === void 0 ? void 0 : e.preventDefault(); | ||
return [4 /*yield*/, resetInputAndGetResponse()]; | ||
case 1: | ||
_a.sent(); | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
}); }; | ||
var addMessage = function (message) { | ||
var messageWithId = __assign(__assign({}, message), { id: crypto.randomUUID() }); | ||
setMessages(function (messages) { return __spreadArray(__spreadArray([], messages, true), [messageWithId], false); }); | ||
return messageWithId; | ||
}; | ||
@@ -91,3 +103,3 @@ var appendMessageToChat = function (message) { | ||
var fetchAndUpdateAIResponse = function (message) { return __awaiter(void 0, void 0, void 0, function () { | ||
var stream, _a, _b, _c, message_1, e_1_1; | ||
var stream, initialMessage, response, _a, _b, _c, message_1, e_1_1; | ||
var _d, e_1, _e, _f; | ||
@@ -99,5 +111,4 @@ return __generator(this, function (_g) { | ||
stream = _g.sent(); | ||
if (!stream) | ||
throw new Error(); | ||
addMessageToChat('', 'bot'); | ||
initialMessage = addMessage({ content: '', role: 'bot' }); | ||
response = ''; | ||
_g.label = 2; | ||
@@ -115,2 +126,3 @@ case 2: | ||
appendMessageToChat(message_1); | ||
response += message_1; | ||
_g.label = 5; | ||
@@ -137,29 +149,42 @@ case 5: | ||
case 12: return [7 /*endfinally*/]; | ||
case 13: return [2 /*return*/]; | ||
case 13: return [2 /*return*/, __assign(__assign({}, initialMessage), { content: response })]; | ||
} | ||
}); | ||
}); }; | ||
var handleSubmit = function (e, newMessage) { return __awaiter(void 0, void 0, void 0, function () { | ||
var _a; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
var submitMessage = function (message) { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) { | ||
return [2 /*return*/, resetInputAndGetResponse(message)]; | ||
}); }); }; | ||
var resetInputAndGetResponse = function (message) { return __awaiter(void 0, void 0, void 0, function () { | ||
var addedMessage, addedMessage_1, _a, addedMessage_2; | ||
var _b, _c, _d, _e, _f, _g; | ||
return __generator(this, function (_h) { | ||
switch (_h.label) { | ||
case 0: | ||
setIsLoading(true); | ||
e === null || e === void 0 ? void 0 : e.preventDefault(); | ||
addMessageToChat(newMessage !== null && newMessage !== void 0 ? newMessage : message); | ||
setMessage(''); | ||
_b.label = 1; | ||
setIsStreaming(true); | ||
addedMessage = addMessage({ content: message !== null && message !== void 0 ? message : formInput, role: 'user' }); | ||
return [4 /*yield*/, ((_c = (_b = input.handlers).onMessageAdded) === null || _c === void 0 ? void 0 : _c.call(_b, addedMessage))]; | ||
case 1: | ||
_b.trys.push([1, 3, , 4]); | ||
return [4 /*yield*/, fetchAndUpdateAIResponse(newMessage !== null && newMessage !== void 0 ? newMessage : message)]; | ||
_h.sent(); | ||
setFormInput(''); | ||
_h.label = 2; | ||
case 2: | ||
_b.sent(); | ||
return [3 /*break*/, 4]; | ||
_h.trys.push([2, 5, 7, 8]); | ||
return [4 /*yield*/, fetchAndUpdateAIResponse(formInput)]; | ||
case 3: | ||
_a = _b.sent(); | ||
addMessageToChat(BOT_ERROR_MESSAGE, 'bot'); | ||
return [3 /*break*/, 4]; | ||
addedMessage_1 = _h.sent(); | ||
return [4 /*yield*/, ((_e = (_d = input.handlers).onMessageAdded) === null || _e === void 0 ? void 0 : _e.call(_d, addedMessage_1))]; | ||
case 4: | ||
setIsLoading(false); | ||
return [2 /*return*/]; | ||
_h.sent(); | ||
return [3 /*break*/, 8]; | ||
case 5: | ||
_a = _h.sent(); | ||
addedMessage_2 = addMessage({ content: BOT_ERROR_MESSAGE, role: 'bot' }); | ||
return [4 /*yield*/, ((_g = (_f = input.handlers).onMessageAdded) === null || _g === void 0 ? void 0 : _g.call(_f, addedMessage_2))]; | ||
case 6: | ||
_h.sent(); | ||
return [3 /*break*/, 8]; | ||
case 7: | ||
setIsStreaming(false); | ||
return [7 /*endfinally*/]; | ||
case 8: return [2 /*return*/]; | ||
} | ||
@@ -171,7 +196,8 @@ }); | ||
setMessages: setMessages, | ||
input: message, | ||
setInput: setMessage, | ||
input: formInput, | ||
setInput: setFormInput, | ||
handleInputChange: handleInputChange, | ||
handleSubmit: handleSubmit, | ||
isLoading: isLoading, | ||
submitMessage: submitMessage, | ||
isStreaming: isStreaming, | ||
}; | ||
@@ -178,0 +204,0 @@ }; |
import useChatStream from './hooks/useChatStream'; | ||
export * from './types'; | ||
export default useChatStream; | ||
//# sourceMappingURL=index.d.ts.map |
"use strict"; | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
var desc = Object.getOwnPropertyDescriptor(m, k); | ||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { | ||
desc = { enumerable: true, get: function() { return m[k]; } }; | ||
} | ||
Object.defineProperty(o, k2, desc); | ||
}) : (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
o[k2] = m[k]; | ||
})); | ||
var __exportStar = (this && this.__exportStar) || function(m, exports) { | ||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
@@ -7,3 +21,4 @@ return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
var useChatStream_1 = __importDefault(require("./hooks/useChatStream")); | ||
__exportStar(require("./types"), exports); | ||
exports.default = useChatStream_1.default; | ||
//# sourceMappingURL=index.js.map |
@@ -1,4 +0,4 @@ | ||
import type { UseChatStreamInputMethod, UseChatStreamOptions } from '../hooks/useChatStream'; | ||
export declare const getStream: (input: string, options: UseChatStreamOptions, method: UseChatStreamInputMethod) => Promise<ReadableStream<Uint8Array> | null>; | ||
import { UseChatStreamHttpOptions, UseChatStreamInputMethod } from '../types'; | ||
export declare const getStream: (input: string, options: UseChatStreamHttpOptions, method: UseChatStreamInputMethod) => Promise<ReadableStream<Uint8Array> | null>; | ||
export declare function decodeStreamToJson(data: ReadableStream<Uint8Array> | null): AsyncIterableIterator<string>; | ||
//# sourceMappingURL=streams.d.ts.map |
@@ -53,4 +53,5 @@ "use strict"; | ||
var g = generator.apply(thisArg, _arguments || []), i, q = []; | ||
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i; | ||
function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; } | ||
return i = {}, verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i; | ||
function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; } | ||
function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } } | ||
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } | ||
@@ -80,3 +81,2 @@ function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } | ||
params = '?' + new URLSearchParams(options.query).toString(); | ||
console.log(JSON.stringify(options.body, function (_k, v) { return v === null ? undefined : v; })); | ||
return [4 /*yield*/, fetch(options.url + params, { | ||
@@ -83,0 +83,0 @@ method: options.method, |
{ | ||
"name": "@magicul/react-chat-stream", | ||
"description": "A React hook that lets you easily integrate your custom ChatGPT-like chat in React.", | ||
"version": "0.2.3", | ||
"version": "0.3.0", | ||
"main": "dist/index.js", | ||
@@ -35,20 +35,18 @@ "types": "dist/index.d.ts", | ||
"devDependencies": { | ||
"@types/react": "^18.2.14", | ||
"@typescript-eslint/eslint-plugin": "^5.59.11", | ||
"@typescript-eslint/parser": "^5.61.0", | ||
"eslint": "8.46.0", | ||
"eslint-config-airbnb": "^19.0.4", | ||
"eslint-plugin-jsx-a11y": "^6.7.1", | ||
"eslint-plugin-prettier": "^5.0.0", | ||
"eslint-plugin-react": "^7.32.2", | ||
"eslint-plugin-react-hooks": "^4.6.0", | ||
"prettier": "^3.0.0", | ||
"react": "^18.2.0", | ||
"react-dom": "^18.2.0", | ||
"typescript": "^5.1.6" | ||
}, | ||
"dependencies": { | ||
"uuid": "^9.0.0", | ||
"@types/uuid": "^9.0.2" | ||
"@types/react": "18.2.56", | ||
"@typescript-eslint/eslint-plugin": "7.0.1", | ||
"@typescript-eslint/parser": "7.0.1", | ||
"eslint": "8.56.0", | ||
"eslint-config-airbnb": "19.0.4", | ||
"eslint-config-next": "14.1.0", | ||
"eslint-config-prettier": "9.1.0", | ||
"eslint-plugin-import": "2.29.1", | ||
"eslint-plugin-jsx-a11y": "6.8.0", | ||
"eslint-plugin-prettier": "5.1.3", | ||
"eslint-plugin-react": "7.33.2", | ||
"prettier": "3.2.5", | ||
"react": "18.2.0", | ||
"react-dom": "18.2.0", | ||
"typescript": "5.3.3" | ||
} | ||
} |
@@ -1,46 +0,28 @@ | ||
import { ChangeEvent, Dispatch, FormEvent, SetStateAction, useState } from 'react'; | ||
import { ChangeEvent, FormEvent, useState } from 'react'; | ||
import { decodeStreamToJson, getStream } from '../utils/streams'; | ||
import { v4 as uuidv4 } from 'uuid'; | ||
import { UseChatStreamChatMessage, UseChatStreamInput } from '../types'; | ||
const BOT_ERROR_MESSAGE = 'Something went wrong fetching AI response.'; | ||
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'; | ||
type ChatMessage = { | ||
role: 'bot' | 'user'; | ||
content: string; | ||
id: string; | ||
} | ||
export type UseChatStreamOptions = { | ||
url: string; | ||
method: HttpMethod; | ||
query?: Record<string, string>; | ||
headers?: HeadersInit; | ||
body?: Record<string, string>; | ||
} | ||
export type UseChatStreamInputMethod = { | ||
type: 'body' | 'query', | ||
key: string; | ||
} | ||
type UseChatStreamInput = { | ||
options: UseChatStreamOptions, | ||
method: UseChatStreamInputMethod, | ||
}; | ||
const useChatStream = (input: UseChatStreamInput) => { | ||
const [messages, setMessages] = useState<ChatMessage[]>([]); | ||
const [message, setMessage] = useState(''); | ||
const [isLoading, setIsLoading] = useState(false); | ||
const [messages, setMessages] = useState<UseChatStreamChatMessage[]>([]); | ||
const [formInput, setFormInput] = useState(''); | ||
const [isStreaming, setIsStreaming] = useState(false); | ||
const handleInputChange = (e: ChangeEvent<HTMLInputElement> | ChangeEvent<HTMLTextAreaElement>) => { | ||
setMessage(e.target.value); | ||
setFormInput(e.target.value); | ||
}; | ||
const addMessageToChat = (message: string, role: ChatMessage['role'] = 'user') => { | ||
setMessages(messages => [...messages, { role, content: message, id: uuidv4() }]); | ||
const handleSubmit = async (e?: FormEvent<HTMLFormElement>) => { | ||
e?.preventDefault(); | ||
await resetInputAndGetResponse(); | ||
}; | ||
const addMessage = (message: Omit<UseChatStreamChatMessage, 'id'>) => { | ||
const messageWithId = { ...message, id: crypto.randomUUID() as string }; | ||
setMessages(messages => [...messages, messageWithId]); | ||
return messageWithId; | ||
}; | ||
const appendMessageToChat = (message: string) => { | ||
@@ -59,34 +41,41 @@ setMessages(messages => { | ||
const stream = await getStream(message, input.options, input.method); | ||
if (!stream) throw new Error(); | ||
const initialMessage = addMessage({ content: '', role: 'bot' }); | ||
let response = ''; | ||
addMessageToChat('', 'bot'); | ||
for await (const message of decodeStreamToJson(stream)) { | ||
appendMessageToChat(message); | ||
response += message; | ||
} | ||
return { ...initialMessage, content: response }; | ||
}; | ||
const handleSubmit = async (e?: FormEvent<HTMLFormElement>, newMessage?: string) => { | ||
setIsLoading(true); | ||
e?.preventDefault(); | ||
addMessageToChat(newMessage ?? message); | ||
setMessage(''); | ||
const submitMessage = async (message: string) => resetInputAndGetResponse(message); | ||
const resetInputAndGetResponse = async (message?: string) => { | ||
setIsStreaming(true); | ||
const addedMessage = addMessage({ content: message ?? formInput, role: 'user' }); | ||
await input.handlers.onMessageAdded?.(addedMessage); | ||
setFormInput(''); | ||
try { | ||
await fetchAndUpdateAIResponse(newMessage ?? message); | ||
const addedMessage = await fetchAndUpdateAIResponse(formInput); | ||
await input.handlers.onMessageAdded?.(addedMessage); | ||
} catch { | ||
addMessageToChat(BOT_ERROR_MESSAGE, 'bot'); | ||
const addedMessage = addMessage({ content: BOT_ERROR_MESSAGE, role: 'bot' }); | ||
await input.handlers.onMessageAdded?.(addedMessage); | ||
} finally { | ||
setIsStreaming(false); | ||
} | ||
} | ||
setIsLoading(false); | ||
}; | ||
return { | ||
messages, | ||
setMessages, | ||
input: message, | ||
setInput: setMessage, | ||
input: formInput, | ||
setInput: setFormInput, | ||
handleInputChange, | ||
handleSubmit, | ||
isLoading, | ||
submitMessage, | ||
isStreaming, | ||
}; | ||
@@ -93,0 +82,0 @@ }; |
import useChatStream from './hooks/useChatStream'; | ||
export * from './types'; | ||
export default useChatStream; |
@@ -1,5 +0,2 @@ | ||
import type { | ||
UseChatStreamInputMethod, | ||
UseChatStreamOptions | ||
} from '../hooks/useChatStream'; | ||
import { UseChatStreamHttpOptions, UseChatStreamInputMethod } from '../types'; | ||
@@ -10,3 +7,3 @@ const DEFAULT_HEADERS = { | ||
const mergeInputInOptions = (input: string, options: UseChatStreamOptions, method: UseChatStreamInputMethod) => { | ||
const mergeInputInOptions = (input: string, options: UseChatStreamHttpOptions, method: UseChatStreamInputMethod) => { | ||
options.query = options.query ?? {}; | ||
@@ -18,14 +15,10 @@ (options[method.type] as Record<string, unknown>)[method.key] = input; | ||
export const getStream = async (input: string, options: UseChatStreamOptions, method: UseChatStreamInputMethod) => { | ||
export const getStream = async (input: string, options: UseChatStreamHttpOptions, method: UseChatStreamInputMethod) => { | ||
options = mergeInputInOptions(input, options, method); | ||
const params = '?' + new URLSearchParams(options.query).toString(); | ||
console.log(JSON.stringify(options.body, (_k, v) => v === null ? undefined : v)); | ||
const response = await fetch(options.url + params, { | ||
method: options.method, | ||
headers: { | ||
...DEFAULT_HEADERS, | ||
...options.headers | ||
}, | ||
headers: { ...DEFAULT_HEADERS, ...options.headers }, | ||
body: JSON.stringify(options.body, (_k, v) => v === null ? undefined : v) | ||
@@ -32,0 +25,0 @@ }); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
45025
1
27
664
15
- Removed@types/uuid@^9.0.2
- Removeduuid@^9.0.0
- Removed@types/uuid@9.0.8(transitive)
- Removeduuid@9.0.1(transitive)