@fencyai/react 0.1.48 → 0.1.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/hooks/useBasicChatCompletions/index.js +7 -1
- package/lib/hooks/useFencyEventSource/index.d.ts +12 -0
- package/lib/hooks/{useEventSource → useFencyEventSource}/index.js +12 -11
- package/lib/hooks/useFiles/index.js +23 -28
- package/lib/hooks/useStream/index.js +4 -25
- package/lib/hooks/useStream/toStreamData.d.ts +2 -0
- package/lib/hooks/useStream/toStreamData.js +106 -0
- package/lib/hooks/useStreamingChatCompletions/index.js +18 -7
- package/lib/hooks/useStructuredChatCompletions/index.js +21 -3
- package/lib/hooks/useWebsites/index.d.ts +1 -1
- package/lib/hooks/useWebsites/index.js +3 -3
- package/lib/index.d.ts +2 -0
- package/lib/index.js +2 -0
- package/lib/types/{CreateUploadParams.d.ts → CreateFileParams.d.ts} +1 -1
- package/lib/types/StreamData.d.ts +52 -0
- package/lib/types/StreamingChatCompletion.d.ts +3 -1
- package/lib/types/UseBasicChatCompletions.d.ts +1 -0
- package/lib/types/UseFiles.d.ts +4 -5
- package/lib/types/UseFilesProps.d.ts +1 -1
- package/lib/types/UseStreamProps.d.ts +1 -2
- package/lib/types/UseStreamingChatCompletions.d.ts +1 -0
- package/lib/types/UseStructuredChatCompletions.d.ts +1 -0
- package/lib/types/UseWebsites.d.ts +3 -2
- package/lib/types/UseWebsitesProps.d.ts +1 -1
- package/lib/types/index.d.ts +7 -2
- package/lib/types/index.js +7 -2
- package/package.json +4 -4
- package/lib/hooks/useEventSource/index.d.ts +0 -14
- package/lib/types/FileUpload.d.ts +0 -11
- package/lib/types/FileUploadStatus.d.ts +0 -1
- package/lib/types/FileUploadStatus.js +0 -1
- /package/lib/types/{CreateUploadParams.js → CreateFileParams.js} +0 -0
- /package/lib/types/{FileUpload.js → StreamData.js} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createChatCompletion } from '@fencyai/js';
|
|
2
|
-
import { useCallback, useState } from 'react';
|
|
2
|
+
import { useCallback, useMemo, useState } from 'react';
|
|
3
3
|
import { useFencyContext } from '../../provider/useFencyContext';
|
|
4
4
|
export const useBasicChatCompletions = () => {
|
|
5
5
|
const context = useFencyContext();
|
|
@@ -101,8 +101,14 @@ export const useBasicChatCompletions = () => {
|
|
|
101
101
|
};
|
|
102
102
|
}
|
|
103
103
|
}, [context]);
|
|
104
|
+
const latest = useMemo(() => {
|
|
105
|
+
return chatCompletions.sort((a, b) => {
|
|
106
|
+
return new Date(b.triggeredAt).getTime() - new Date(a.triggeredAt).getTime();
|
|
107
|
+
})[0];
|
|
108
|
+
}, [chatCompletions]);
|
|
104
109
|
return {
|
|
105
110
|
chatCompletions,
|
|
106
111
|
createBasicChatCompletion,
|
|
112
|
+
latest,
|
|
107
113
|
};
|
|
108
114
|
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type Message = {
|
|
2
|
+
url: string;
|
|
3
|
+
data: string;
|
|
4
|
+
};
|
|
5
|
+
export declare function useFencyEventSource(props?: {
|
|
6
|
+
onError: (streamId: string) => void;
|
|
7
|
+
onMessage: (message: Message) => boolean | void;
|
|
8
|
+
}): {
|
|
9
|
+
setSourceUrl: import("react").Dispatch<import("react").SetStateAction<string | null>>;
|
|
10
|
+
sourceUrl: string | null;
|
|
11
|
+
};
|
|
12
|
+
export declare function base64Decode(base64: string): string;
|
|
@@ -1,31 +1,32 @@
|
|
|
1
1
|
import { useEffect, useState } from 'react';
|
|
2
|
-
export function
|
|
3
|
-
const [
|
|
2
|
+
export function useFencyEventSource(props) {
|
|
3
|
+
const [sourceUrl, setSourceUrl] = useState(null);
|
|
4
4
|
useEffect(() => {
|
|
5
|
-
if (!
|
|
5
|
+
if (!sourceUrl) {
|
|
6
6
|
return;
|
|
7
|
-
|
|
7
|
+
}
|
|
8
|
+
const eventSource = new EventSource(sourceUrl);
|
|
8
9
|
eventSource.onmessage = (message) => {
|
|
9
10
|
props?.onMessage({
|
|
10
|
-
url:
|
|
11
|
+
url: sourceUrl,
|
|
11
12
|
data: base64Decode(message.data),
|
|
12
13
|
});
|
|
13
14
|
};
|
|
14
15
|
eventSource.onerror = (error) => {
|
|
15
16
|
console.error('EventSource error:', error);
|
|
16
|
-
props?.onError(
|
|
17
|
-
|
|
17
|
+
props?.onError(sourceUrl);
|
|
18
|
+
setSourceUrl(null);
|
|
18
19
|
};
|
|
19
20
|
return () => {
|
|
20
21
|
eventSource.close();
|
|
21
22
|
};
|
|
22
|
-
}, [
|
|
23
|
+
}, [sourceUrl]);
|
|
23
24
|
return {
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
setSourceUrl,
|
|
26
|
+
sourceUrl,
|
|
26
27
|
};
|
|
27
28
|
}
|
|
28
|
-
function base64Decode(base64) {
|
|
29
|
+
export function base64Decode(base64) {
|
|
29
30
|
// Decode Base64 -> binary string
|
|
30
31
|
const binary = atob(base64);
|
|
31
32
|
// Convert binary string -> Uint8Array
|
|
@@ -1,66 +1,61 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createFile as createFileApi, } from '@fencyai/js';
|
|
2
2
|
import { useState } from 'react';
|
|
3
3
|
import { useFencyContext } from '../../provider/useFencyContext';
|
|
4
4
|
import { useStream } from '../useStream';
|
|
5
5
|
export function useFiles(props) {
|
|
6
|
-
const [
|
|
6
|
+
const [files, setFiles] = useState([]);
|
|
7
7
|
const context = useFencyContext();
|
|
8
8
|
const { createStream } = useStream({
|
|
9
9
|
onFileUploadCompleted: (streamData) => {
|
|
10
10
|
props.onUploadCompleted?.(streamData);
|
|
11
|
-
|
|
12
|
-
return fileUpload.
|
|
11
|
+
setFiles((prev) => prev.map((fileUpload) => {
|
|
12
|
+
return fileUpload.id === streamData.uploadId
|
|
13
13
|
? { ...fileUpload, status: 'upload_complete' }
|
|
14
14
|
: fileUpload;
|
|
15
15
|
}));
|
|
16
16
|
},
|
|
17
17
|
onFileTextContentReady: (streamData) => {
|
|
18
18
|
props.onTextContentReady?.(streamData);
|
|
19
|
-
|
|
20
|
-
? { ...fileUpload, textContent: streamData.
|
|
19
|
+
setFiles((prev) => prev.map((fileUpload) => fileUpload.id === streamData.fileId
|
|
20
|
+
? { ...fileUpload, textContent: streamData.textContent }
|
|
21
21
|
: fileUpload));
|
|
22
22
|
},
|
|
23
23
|
});
|
|
24
|
-
const
|
|
25
|
-
const
|
|
24
|
+
const createFile = async (params) => {
|
|
25
|
+
const streamResponse = await createStream({
|
|
26
26
|
type: 'FileStream',
|
|
27
27
|
});
|
|
28
|
-
if (
|
|
29
|
-
const
|
|
28
|
+
if (streamResponse.type === 'success') {
|
|
29
|
+
const fileResponse = await createFileApi({
|
|
30
30
|
pk: context.fency.publishableKey,
|
|
31
31
|
request: {
|
|
32
|
-
streamId:
|
|
32
|
+
streamId: streamResponse.stream.id,
|
|
33
33
|
fileName: params.fileName,
|
|
34
34
|
fileType: params.fileType,
|
|
35
35
|
fileSize: params.fileSize,
|
|
36
36
|
},
|
|
37
37
|
baseUrl: context.fency.baseUrl,
|
|
38
38
|
});
|
|
39
|
-
if (
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
onUploadCompleted: props.onUploadCompleted,
|
|
49
|
-
onTextContentReady: props.onTextContentReady,
|
|
50
|
-
},
|
|
51
|
-
]);
|
|
39
|
+
if (fileResponse.type === 'success') {
|
|
40
|
+
setFiles([...files, fileResponse.file]);
|
|
41
|
+
return fileResponse;
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
return {
|
|
45
|
+
type: 'error',
|
|
46
|
+
error: fileResponse.error,
|
|
47
|
+
};
|
|
52
48
|
}
|
|
53
|
-
return response;
|
|
54
49
|
}
|
|
55
50
|
else {
|
|
56
51
|
return {
|
|
57
52
|
type: 'error',
|
|
58
|
-
error:
|
|
53
|
+
error: streamResponse.error,
|
|
59
54
|
};
|
|
60
55
|
}
|
|
61
56
|
};
|
|
62
57
|
return {
|
|
63
|
-
|
|
64
|
-
|
|
58
|
+
createFile,
|
|
59
|
+
files,
|
|
65
60
|
};
|
|
66
61
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { createStream as createStreamApi, } from '@fencyai/js';
|
|
2
2
|
import { useState } from 'react';
|
|
3
3
|
import { useFencyContext } from '../../provider/useFencyContext';
|
|
4
|
-
import {
|
|
4
|
+
import { useFencyEventSource } from '../useFencyEventSource';
|
|
5
|
+
import { toStreamData } from './toStreamData';
|
|
5
6
|
export const useStream = (props) => {
|
|
6
7
|
const context = useFencyContext();
|
|
7
8
|
const [stream, setStream] = useState(null);
|
|
8
|
-
const
|
|
9
|
+
const es = useFencyEventSource({
|
|
9
10
|
onError: (url) => {
|
|
10
11
|
console.error('Stream error:', url);
|
|
11
12
|
props?.onStreamError?.({
|
|
@@ -58,9 +59,7 @@ export const useStream = (props) => {
|
|
|
58
59
|
if (response.type === 'success') {
|
|
59
60
|
setStream(response.stream);
|
|
60
61
|
const url = `${context.fency.baseUrl}/v1/pub/streams/${response.stream.id}?pk=${context.fency.publishableKey}`;
|
|
61
|
-
|
|
62
|
-
url,
|
|
63
|
-
});
|
|
62
|
+
es.setSourceUrl(url);
|
|
64
63
|
}
|
|
65
64
|
return response;
|
|
66
65
|
};
|
|
@@ -69,23 +68,3 @@ export const useStream = (props) => {
|
|
|
69
68
|
stream,
|
|
70
69
|
};
|
|
71
70
|
};
|
|
72
|
-
const toStreamData = (data) => {
|
|
73
|
-
try {
|
|
74
|
-
const json = JSON.parse(data);
|
|
75
|
-
if (isStreamData(json)) {
|
|
76
|
-
return json;
|
|
77
|
-
}
|
|
78
|
-
return null;
|
|
79
|
-
}
|
|
80
|
-
catch (error) {
|
|
81
|
-
console.error('Error parsing message:', error);
|
|
82
|
-
return null;
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
const isStreamData = (data) => {
|
|
86
|
-
return (typeof data === 'object' &&
|
|
87
|
-
data !== null &&
|
|
88
|
-
'type' in data &&
|
|
89
|
-
'streamId' in data &&
|
|
90
|
-
'timestamp' in data);
|
|
91
|
-
};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
export const toStreamData = (data) => {
|
|
2
|
+
try {
|
|
3
|
+
const json = JSON.parse(data);
|
|
4
|
+
return toStreamDataRaw(json);
|
|
5
|
+
}
|
|
6
|
+
catch (error) {
|
|
7
|
+
console.error('Error parsing message:', error);
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
const toStreamDataRaw = (data) => {
|
|
12
|
+
const basicTypeExist = typeof data === 'object' &&
|
|
13
|
+
data !== null &&
|
|
14
|
+
'type' in data &&
|
|
15
|
+
'streamId' in data &&
|
|
16
|
+
'timestamp' in data;
|
|
17
|
+
if (!basicTypeExist) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
switch (data.type) {
|
|
21
|
+
case 'NewChatCompletionStreamChunk':
|
|
22
|
+
return toNewChatCompletionStreamChunk(data);
|
|
23
|
+
case 'ChatCompletionStreamCompleted':
|
|
24
|
+
return toChatCompletionStreamCompleted(data);
|
|
25
|
+
case 'StreamTimeout':
|
|
26
|
+
return toStreamTimeout(data);
|
|
27
|
+
case 'StreamNotFound':
|
|
28
|
+
return toStreamNotFound(data);
|
|
29
|
+
case 'FileUploadCompleted':
|
|
30
|
+
return toFileUploadCompleted(data);
|
|
31
|
+
case 'FileTextContentReady':
|
|
32
|
+
return toFileTextContentReady(data);
|
|
33
|
+
case 'WebsiteHtmlContentReady':
|
|
34
|
+
return toWebsiteHtmlContentReady(data);
|
|
35
|
+
case 'WebsiteTextContentReady':
|
|
36
|
+
return toWebsiteTextContentReady(data);
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
};
|
|
40
|
+
const toNewChatCompletionStreamChunk = (data) => {
|
|
41
|
+
return {
|
|
42
|
+
type: 'NewChatCompletionStreamChunk',
|
|
43
|
+
streamId: data.streamId,
|
|
44
|
+
chatCompletionId: data.chatCompletionId,
|
|
45
|
+
timestamp: data.timestamp,
|
|
46
|
+
content: data.content,
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
const toChatCompletionStreamCompleted = (data) => {
|
|
50
|
+
return {
|
|
51
|
+
type: 'ChatCompletionStreamCompleted',
|
|
52
|
+
streamId: data.streamId,
|
|
53
|
+
chatCompletionId: data.chatCompletionId,
|
|
54
|
+
timestamp: data.timestamp,
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
const toStreamTimeout = (data) => {
|
|
58
|
+
return {
|
|
59
|
+
type: 'StreamTimeout',
|
|
60
|
+
streamId: data.streamId,
|
|
61
|
+
timestamp: data.timestamp,
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
const toStreamNotFound = (data) => {
|
|
65
|
+
return {
|
|
66
|
+
type: 'StreamNotFound',
|
|
67
|
+
streamId: data.streamId,
|
|
68
|
+
timestamp: data.timestamp,
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
const toFileUploadCompleted = (data) => {
|
|
72
|
+
return {
|
|
73
|
+
type: 'FileUploadCompleted',
|
|
74
|
+
streamId: data.streamId,
|
|
75
|
+
uploadId: data.fileId,
|
|
76
|
+
fileId: data.fileId,
|
|
77
|
+
timestamp: data.timestamp,
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
const toFileTextContentReady = (data) => {
|
|
81
|
+
return {
|
|
82
|
+
type: 'FileTextContentReady',
|
|
83
|
+
streamId: data.streamId,
|
|
84
|
+
fileId: data.fileId,
|
|
85
|
+
textContent: data.textContent,
|
|
86
|
+
timestamp: data.timestamp,
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
const toWebsiteHtmlContentReady = (data) => {
|
|
90
|
+
return {
|
|
91
|
+
type: 'WebsiteHtmlContentReady',
|
|
92
|
+
streamId: data.streamId,
|
|
93
|
+
websiteId: data.websiteId,
|
|
94
|
+
htmlContent: data.htmlContent,
|
|
95
|
+
timestamp: data.timestamp,
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
const toWebsiteTextContentReady = (data) => {
|
|
99
|
+
return {
|
|
100
|
+
type: 'WebsiteTextContentReady',
|
|
101
|
+
streamId: data.streamId,
|
|
102
|
+
websiteId: data.websiteId,
|
|
103
|
+
textContent: data.textContent,
|
|
104
|
+
timestamp: data.timestamp,
|
|
105
|
+
};
|
|
106
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createChatCompletion } from '@fencyai/js';
|
|
2
|
-
import { useCallback, useEffect, useState } from 'react';
|
|
3
|
-
import { useStream } from '../useStream';
|
|
2
|
+
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
4
3
|
import { useFencyContext } from '../../provider/useFencyContext';
|
|
4
|
+
import { useStream } from '../useStream';
|
|
5
5
|
export const useStreamingChatCompletions = () => {
|
|
6
6
|
const context = useFencyContext();
|
|
7
7
|
const [chatCompletions, setChatCompletions] = useState([]);
|
|
@@ -9,9 +9,7 @@ export const useStreamingChatCompletions = () => {
|
|
|
9
9
|
const [chunks, setChunks] = useState([]);
|
|
10
10
|
const { stream, createStream } = useStream({
|
|
11
11
|
onNewChatCompletionStreamChunk: (streamData) => {
|
|
12
|
-
|
|
13
|
-
setChunks((prev) => [...prev, streamData]);
|
|
14
|
-
}
|
|
12
|
+
setChunks((prev) => [...prev, streamData]);
|
|
15
13
|
},
|
|
16
14
|
onChatCompletionStreamCompleted: (stream) => {
|
|
17
15
|
setCompletedStreamIds((prev) => [...prev, stream.streamId]);
|
|
@@ -50,12 +48,15 @@ export const useStreamingChatCompletions = () => {
|
|
|
50
48
|
const newChatCompletions = [];
|
|
51
49
|
for (const chatCompletion of chatCompletions) {
|
|
52
50
|
const relevantChunks = chunks
|
|
53
|
-
.filter((chunk) =>
|
|
51
|
+
.filter((chunk) => {
|
|
52
|
+
return chunk.streamId === chatCompletion.streamId;
|
|
53
|
+
})
|
|
54
54
|
.sort((a, b) => a.timestamp.localeCompare(b.timestamp));
|
|
55
55
|
const fullMessage = relevantChunks
|
|
56
56
|
.map((chunk) => chunk.content)
|
|
57
57
|
.join('');
|
|
58
58
|
newChatCompletions.push({
|
|
59
|
+
triggeredAt: chatCompletion.triggeredAt,
|
|
59
60
|
data: chatCompletion.data
|
|
60
61
|
? {
|
|
61
62
|
id: chatCompletion.data.id,
|
|
@@ -83,6 +84,7 @@ export const useStreamingChatCompletions = () => {
|
|
|
83
84
|
...chatCompletions,
|
|
84
85
|
{
|
|
85
86
|
streamId: streamResponse.stream.id,
|
|
87
|
+
triggeredAt: new Date().toISOString(),
|
|
86
88
|
data: null,
|
|
87
89
|
error: null,
|
|
88
90
|
response: '',
|
|
@@ -120,8 +122,8 @@ export const useStreamingChatCompletions = () => {
|
|
|
120
122
|
if (chatCompletion.type === 'success' &&
|
|
121
123
|
chatCompletion.completion) {
|
|
122
124
|
const newCompletion = {
|
|
123
|
-
triggeredAt: new Date().toISOString(),
|
|
124
125
|
streamId: streamResponse.stream.id,
|
|
126
|
+
triggeredAt: new Date().toISOString(),
|
|
125
127
|
data: {
|
|
126
128
|
id: chatCompletion.completion.id,
|
|
127
129
|
createdAt: chatCompletion.completion.createdAt,
|
|
@@ -147,6 +149,7 @@ export const useStreamingChatCompletions = () => {
|
|
|
147
149
|
setChatCompletions((prev) => [
|
|
148
150
|
...prev.filter((c) => c.streamId !== streamResponse.stream.id),
|
|
149
151
|
{
|
|
152
|
+
triggeredAt: new Date().toISOString(),
|
|
150
153
|
streamId: streamResponse.stream.id,
|
|
151
154
|
error: chatCompletion.error,
|
|
152
155
|
response: '',
|
|
@@ -169,6 +172,7 @@ export const useStreamingChatCompletions = () => {
|
|
|
169
172
|
setChatCompletions((prev) => [
|
|
170
173
|
...prev.filter((c) => c.streamId !== streamResponse.stream.id),
|
|
171
174
|
{
|
|
175
|
+
triggeredAt: new Date().toISOString(),
|
|
172
176
|
streamId: streamResponse.stream.id,
|
|
173
177
|
error: error,
|
|
174
178
|
response: '',
|
|
@@ -189,8 +193,15 @@ export const useStreamingChatCompletions = () => {
|
|
|
189
193
|
return streamResponse;
|
|
190
194
|
}
|
|
191
195
|
}, [context]);
|
|
196
|
+
const latest = useMemo(() => {
|
|
197
|
+
return chatCompletions.sort((a, b) => {
|
|
198
|
+
return (new Date(b.triggeredAt).getTime() -
|
|
199
|
+
new Date(a.triggeredAt).getTime());
|
|
200
|
+
})[0];
|
|
201
|
+
}, [chatCompletions]);
|
|
192
202
|
return {
|
|
193
203
|
chatCompletions,
|
|
194
204
|
createStreamingChatCompletion,
|
|
205
|
+
latest,
|
|
195
206
|
};
|
|
196
207
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createChatCompletion } from '@fencyai/js';
|
|
2
|
-
import { useCallback, useState } from 'react';
|
|
2
|
+
import { useCallback, useMemo, useState } from 'react';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import { useFencyContext } from '../../provider/useFencyContext';
|
|
5
5
|
export const useStructuredChatCompletions = () => {
|
|
@@ -17,6 +17,16 @@ export const useStructuredChatCompletions = () => {
|
|
|
17
17
|
},
|
|
18
18
|
]);
|
|
19
19
|
const jsonSchema = z.toJSONSchema(params.responseFormat);
|
|
20
|
+
const parseResponse = (response, params) => {
|
|
21
|
+
try {
|
|
22
|
+
return params.responseFormat.parse(JSON.parse(response));
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
console.error('could not parse response', response);
|
|
26
|
+
console.error(error);
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
};
|
|
20
30
|
const parsedJsonSchema = JSON.stringify(jsonSchema);
|
|
21
31
|
const response = await createChatCompletion({
|
|
22
32
|
pk: context.fency.publishableKey,
|
|
@@ -40,11 +50,12 @@ export const useStructuredChatCompletions = () => {
|
|
|
40
50
|
});
|
|
41
51
|
if (response.type === 'success') {
|
|
42
52
|
if (response.completion.response) {
|
|
53
|
+
const structuredResponse = parseResponse(response.completion.response, params);
|
|
43
54
|
const data = {
|
|
44
55
|
id: response.completion.id,
|
|
45
56
|
createdAt: response.completion.createdAt,
|
|
46
|
-
response:
|
|
47
|
-
structuredResponse:
|
|
57
|
+
response: structuredResponse,
|
|
58
|
+
structuredResponse: structuredResponse,
|
|
48
59
|
};
|
|
49
60
|
const structuredChatCompletion = {
|
|
50
61
|
triggeredAt,
|
|
@@ -94,8 +105,15 @@ export const useStructuredChatCompletions = () => {
|
|
|
94
105
|
return response;
|
|
95
106
|
}
|
|
96
107
|
}, [context]);
|
|
108
|
+
const latest = useMemo(() => {
|
|
109
|
+
return chatCompletions.sort((a, b) => {
|
|
110
|
+
return (new Date(b.triggeredAt).getTime() -
|
|
111
|
+
new Date(a.triggeredAt).getTime());
|
|
112
|
+
})[0];
|
|
113
|
+
}, [chatCompletions]);
|
|
97
114
|
return {
|
|
98
115
|
chatCompletions,
|
|
99
116
|
createStructuredChatCompletion,
|
|
117
|
+
latest,
|
|
100
118
|
};
|
|
101
119
|
};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { UseWebsites } from '../../types/UseWebsites';
|
|
2
2
|
import { UseWebsitesProps } from '../../types/UseWebsitesProps';
|
|
3
|
-
export declare function useWebsites(props
|
|
3
|
+
export declare function useWebsites(props?: UseWebsitesProps): UseWebsites;
|
|
@@ -7,15 +7,15 @@ export function useWebsites(props) {
|
|
|
7
7
|
const [websites, setWebsites] = useState([]);
|
|
8
8
|
const { createStream } = useStream({
|
|
9
9
|
onWebsiteHtmlContentReady: (streamData) => {
|
|
10
|
-
props
|
|
10
|
+
props?.onHtmlContentReady?.(streamData);
|
|
11
11
|
setWebsites((prev) => prev.map((website) => {
|
|
12
12
|
return website.id === streamData.websiteId
|
|
13
|
-
? { ...website,
|
|
13
|
+
? { ...website, htmlContent: streamData.htmlContent }
|
|
14
14
|
: website;
|
|
15
15
|
}));
|
|
16
16
|
},
|
|
17
17
|
onWebsiteTextContentReady: (streamData) => {
|
|
18
|
-
props
|
|
18
|
+
props?.onTextContentReady?.(streamData);
|
|
19
19
|
setWebsites((prev) => prev.map((website) => website.id === streamData.websiteId
|
|
20
20
|
? { ...website, textContent: streamData.textContent }
|
|
21
21
|
: website));
|
package/lib/index.d.ts
CHANGED
|
@@ -3,5 +3,7 @@ export { useFiles } from './hooks/useFiles';
|
|
|
3
3
|
export { useStreamingChatCompletions } from './hooks/useStreamingChatCompletions';
|
|
4
4
|
export { useStructuredChatCompletions } from './hooks/useStructuredChatCompletions';
|
|
5
5
|
export { useWebsites } from './hooks/useWebsites';
|
|
6
|
+
export { useStream } from './hooks/useStream';
|
|
7
|
+
export { useFencyEventSource } from './hooks/useFencyEventSource';
|
|
6
8
|
export { FencyProvider } from './provider/FencyProvider';
|
|
7
9
|
export * from './types';
|
package/lib/index.js
CHANGED
|
@@ -4,6 +4,8 @@ export { useFiles } from './hooks/useFiles';
|
|
|
4
4
|
export { useStreamingChatCompletions } from './hooks/useStreamingChatCompletions';
|
|
5
5
|
export { useStructuredChatCompletions } from './hooks/useStructuredChatCompletions';
|
|
6
6
|
export { useWebsites } from './hooks/useWebsites';
|
|
7
|
+
export { useStream } from './hooks/useStream';
|
|
8
|
+
export { useFencyEventSource } from './hooks/useFencyEventSource';
|
|
7
9
|
// Re-export providers
|
|
8
10
|
export { FencyProvider } from './provider/FencyProvider';
|
|
9
11
|
// Re-export all types from centralized location
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export type NewChatCompletionStreamChunk = {
|
|
2
|
+
type: 'NewChatCompletionStreamChunk';
|
|
3
|
+
streamId: string;
|
|
4
|
+
chatCompletionId: string;
|
|
5
|
+
timestamp: string;
|
|
6
|
+
content: string;
|
|
7
|
+
};
|
|
8
|
+
export type ChatCompletionStreamCompleted = {
|
|
9
|
+
type: 'ChatCompletionStreamCompleted';
|
|
10
|
+
streamId: string;
|
|
11
|
+
chatCompletionId: string;
|
|
12
|
+
timestamp: string;
|
|
13
|
+
};
|
|
14
|
+
export type StreamTimeout = {
|
|
15
|
+
type: 'StreamTimeout';
|
|
16
|
+
streamId: string;
|
|
17
|
+
timestamp: string;
|
|
18
|
+
};
|
|
19
|
+
export type StreamNotFound = {
|
|
20
|
+
type: 'StreamNotFound';
|
|
21
|
+
streamId: string;
|
|
22
|
+
timestamp: string;
|
|
23
|
+
};
|
|
24
|
+
export type FileUploadCompleted = {
|
|
25
|
+
type: 'FileUploadCompleted';
|
|
26
|
+
streamId: string;
|
|
27
|
+
uploadId: string;
|
|
28
|
+
fileId: string;
|
|
29
|
+
timestamp: string;
|
|
30
|
+
};
|
|
31
|
+
export type FileTextContentReady = {
|
|
32
|
+
type: 'FileTextContentReady';
|
|
33
|
+
streamId: string;
|
|
34
|
+
fileId: string;
|
|
35
|
+
textContent: string;
|
|
36
|
+
timestamp: string;
|
|
37
|
+
};
|
|
38
|
+
export type WebsiteHtmlContentReady = {
|
|
39
|
+
type: 'WebsiteHtmlContentReady';
|
|
40
|
+
streamId: string;
|
|
41
|
+
websiteId: string;
|
|
42
|
+
htmlContent: string;
|
|
43
|
+
timestamp: string;
|
|
44
|
+
};
|
|
45
|
+
export type WebsiteTextContentReady = {
|
|
46
|
+
type: 'WebsiteTextContentReady';
|
|
47
|
+
streamId: string;
|
|
48
|
+
websiteId: string;
|
|
49
|
+
textContent: string;
|
|
50
|
+
timestamp: string;
|
|
51
|
+
};
|
|
52
|
+
export type StreamData = NewChatCompletionStreamChunk | ChatCompletionStreamCompleted | StreamTimeout | StreamNotFound | FileUploadCompleted | FileTextContentReady | WebsiteHtmlContentReady | WebsiteTextContentReady;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { ApiError
|
|
1
|
+
import { ApiError } from '@fencyai/js';
|
|
2
2
|
import { StreamingChatCompletionData } from './StreamingChatCompletionData';
|
|
3
|
+
import { NewChatCompletionStreamChunk } from './StreamData';
|
|
3
4
|
export interface StreamingChatCompletion {
|
|
5
|
+
triggeredAt: string;
|
|
4
6
|
streamId: string;
|
|
5
7
|
data: StreamingChatCompletionData | null;
|
|
6
8
|
error: ApiError | null;
|
|
@@ -4,4 +4,5 @@ import { BasicChatCompletionResponse } from "./BasicChatCompletionResponse";
|
|
|
4
4
|
export interface UseBasicChatCompletions {
|
|
5
5
|
chatCompletions: BasicChatCompletion[];
|
|
6
6
|
createBasicChatCompletion: (params: CreateBasicChatCompletionParams) => Promise<BasicChatCompletionResponse>;
|
|
7
|
+
latest: BasicChatCompletion | null;
|
|
7
8
|
}
|
package/lib/types/UseFiles.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { FileUpload } from './FileUpload';
|
|
1
|
+
import { CreateFileResponse, FencyFile } from '@fencyai/js';
|
|
2
|
+
import { CreateFileParams } from './CreateFileParams';
|
|
4
3
|
export interface UseFiles {
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
createFile: (params: CreateFileParams) => Promise<CreateFileResponse>;
|
|
5
|
+
files: FencyFile[];
|
|
7
6
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FileTextContentReady, FileUploadCompleted } from '
|
|
1
|
+
import { FileTextContentReady, FileUploadCompleted } from './StreamData';
|
|
2
2
|
export interface UseFilesProps {
|
|
3
3
|
onUploadCompleted?: (event: FileUploadCompleted) => void;
|
|
4
4
|
onTextContentReady?: (event: FileTextContentReady) => void;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { ChatCompletionStreamCompleted, NewChatCompletionStreamChunk, StreamNotFound, StreamTimeout } from '
|
|
2
|
-
import { FileUploadCompleted, FileTextContentReady, WebsiteHtmlContentReady, WebsiteTextContentReady } from '@fencyai/js/lib/types/StreamData';
|
|
1
|
+
import { ChatCompletionStreamCompleted, NewChatCompletionStreamChunk, StreamNotFound, StreamTimeout, FileUploadCompleted, FileTextContentReady, WebsiteHtmlContentReady, WebsiteTextContentReady } from './StreamData';
|
|
3
2
|
import { StreamError } from './StreamError';
|
|
4
3
|
export interface UseStreamProps {
|
|
5
4
|
onNewChatCompletionStreamChunk?: (streamData: NewChatCompletionStreamChunk) => void;
|
|
@@ -4,4 +4,5 @@ import { StreamingChatCompletion } from "./StreamingChatCompletion";
|
|
|
4
4
|
export interface UseStreamingChatCompletions {
|
|
5
5
|
chatCompletions: StreamingChatCompletion[];
|
|
6
6
|
createStreamingChatCompletion: (params: CreateStreamingChatCompletionParams) => Promise<CreateStreamingChatCompletionResponse>;
|
|
7
|
+
latest: StreamingChatCompletion | null;
|
|
7
8
|
}
|
|
@@ -5,4 +5,5 @@ import { StructuredChatCompletionResponse } from './StructuredChatCompletionResp
|
|
|
5
5
|
export interface UseStructuredChatCompletions {
|
|
6
6
|
chatCompletions: StructuredChatCompletion<ZodTypeAny>[];
|
|
7
7
|
createStructuredChatCompletion: <T extends ZodTypeAny>(params: CreateStructuredChatCompletionParams<T>) => Promise<StructuredChatCompletionResponse<T>>;
|
|
8
|
+
latest: StructuredChatCompletion<ZodTypeAny> | null;
|
|
8
9
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CreateWebsiteResponse, Website } from '@fencyai/js';
|
|
2
|
+
import { CreateWebsiteParams } from './CreateWebsiteParams';
|
|
2
3
|
export interface UseWebsites {
|
|
3
4
|
websites: Website[];
|
|
4
|
-
createWebsite: (params:
|
|
5
|
+
createWebsite: (params: CreateWebsiteParams) => Promise<CreateWebsiteResponse>;
|
|
5
6
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { WebsiteHtmlContentReady, WebsiteTextContentReady } from '
|
|
1
|
+
import { WebsiteHtmlContentReady, WebsiteTextContentReady } from './StreamData';
|
|
2
2
|
export interface UseWebsitesProps {
|
|
3
3
|
onHtmlContentReady?: (event: WebsiteHtmlContentReady) => void;
|
|
4
4
|
onTextContentReady?: (event: WebsiteTextContentReady) => void;
|
package/lib/types/index.d.ts
CHANGED
|
@@ -7,19 +7,24 @@ export * from './BasicChatCompletionData';
|
|
|
7
7
|
export * from './BasicChatCompletion';
|
|
8
8
|
export * from './BasicChatCompletionResponse';
|
|
9
9
|
export * from './CreateBasicChatCompletionParams';
|
|
10
|
+
export * from './UseBasicChatCompletions';
|
|
10
11
|
export * from './StreamingChatCompletionData';
|
|
11
12
|
export * from './StreamingChatCompletion';
|
|
12
13
|
export * from './CreateStreamingChatCompletionParams';
|
|
14
|
+
export * from './CreateStreamingChatCompletionResponse';
|
|
15
|
+
export * from './UseStreamingChatCompletions';
|
|
13
16
|
export * from './StructuredChatCompletionData';
|
|
14
17
|
export * from './StructuredChatCompletion';
|
|
15
18
|
export * from './StructuredChatCompletionResponse';
|
|
16
19
|
export * from './CreateStructuredChatCompletionParams';
|
|
20
|
+
export * from './UseStructuredChatCompletions';
|
|
17
21
|
export * from './UseStream';
|
|
18
22
|
export * from './CreateStreamResponse';
|
|
19
23
|
export * from './StreamError';
|
|
20
24
|
export * from './UseStreamProps';
|
|
21
25
|
export * from './UseFiles';
|
|
22
26
|
export * from './UseFilesProps';
|
|
23
|
-
export * from './
|
|
24
|
-
export * from './FileUpload';
|
|
27
|
+
export * from './CreateFileParams';
|
|
25
28
|
export * from './UseWebsites';
|
|
29
|
+
export * from './UseWebsitesProps';
|
|
30
|
+
export * from './CreateWebsiteParams';
|
package/lib/types/index.js
CHANGED
|
@@ -10,15 +10,19 @@ export * from './BasicChatCompletionData';
|
|
|
10
10
|
export * from './BasicChatCompletion';
|
|
11
11
|
export * from './BasicChatCompletionResponse';
|
|
12
12
|
export * from './CreateBasicChatCompletionParams';
|
|
13
|
+
export * from './UseBasicChatCompletions';
|
|
13
14
|
// Streaming chat completion types
|
|
14
15
|
export * from './StreamingChatCompletionData';
|
|
15
16
|
export * from './StreamingChatCompletion';
|
|
16
17
|
export * from './CreateStreamingChatCompletionParams';
|
|
18
|
+
export * from './CreateStreamingChatCompletionResponse';
|
|
19
|
+
export * from './UseStreamingChatCompletions';
|
|
17
20
|
// Structured chat completion types
|
|
18
21
|
export * from './StructuredChatCompletionData';
|
|
19
22
|
export * from './StructuredChatCompletion';
|
|
20
23
|
export * from './StructuredChatCompletionResponse';
|
|
21
24
|
export * from './CreateStructuredChatCompletionParams';
|
|
25
|
+
export * from './UseStructuredChatCompletions';
|
|
22
26
|
// Stream types
|
|
23
27
|
export * from './UseStream';
|
|
24
28
|
export * from './CreateStreamResponse';
|
|
@@ -27,7 +31,8 @@ export * from './UseStreamProps';
|
|
|
27
31
|
// File upload types
|
|
28
32
|
export * from './UseFiles';
|
|
29
33
|
export * from './UseFilesProps';
|
|
30
|
-
export * from './
|
|
31
|
-
export * from './FileUpload';
|
|
34
|
+
export * from './CreateFileParams';
|
|
32
35
|
// Website types
|
|
33
36
|
export * from './UseWebsites';
|
|
37
|
+
export * from './UseWebsitesProps';
|
|
38
|
+
export * from './CreateWebsiteParams';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fencyai/react",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.50",
|
|
4
4
|
"description": "> TODO: description",
|
|
5
5
|
"author": "staklau <steinaageklaussen@gmail.com>",
|
|
6
6
|
"homepage": "",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"zod": "^4.0.5"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@fencyai/js": "^0.1.
|
|
39
|
+
"@fencyai/js": "^0.1.50",
|
|
40
40
|
"@types/jest": "^29.5.11",
|
|
41
41
|
"@types/node": "^20.10.5",
|
|
42
42
|
"@types/react": "^18.2.45",
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
"typescript": "^5.3.3"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
|
-
"@fencyai/js": "^0.1.
|
|
48
|
+
"@fencyai/js": "^0.1.50",
|
|
49
49
|
"react": ">=16.8.0"
|
|
50
50
|
},
|
|
51
|
-
"gitHead": "
|
|
51
|
+
"gitHead": "d1be8f911659567ce9fb76fa130397a8ae8d38f3"
|
|
52
52
|
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export type Message = {
|
|
2
|
-
url: string;
|
|
3
|
-
data: string;
|
|
4
|
-
};
|
|
5
|
-
export type EventSource = {
|
|
6
|
-
url: string;
|
|
7
|
-
};
|
|
8
|
-
export declare function useEventSource(props?: {
|
|
9
|
-
onError: (streamId: string) => void;
|
|
10
|
-
onMessage: (message: Message) => void;
|
|
11
|
-
}): {
|
|
12
|
-
setSource: import("react").Dispatch<import("react").SetStateAction<EventSource | null>>;
|
|
13
|
-
source: EventSource | null;
|
|
14
|
-
};
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { ApiError, FencyFile, FileUploadCompleted, FileTextContentReady, Upload } from '@fencyai/js';
|
|
2
|
-
import { FileUploadStatus } from './FileUploadStatus';
|
|
3
|
-
export interface FileUpload {
|
|
4
|
-
status: FileUploadStatus;
|
|
5
|
-
upload: Upload;
|
|
6
|
-
file: FencyFile | null;
|
|
7
|
-
error: ApiError | null;
|
|
8
|
-
textContent: string | null;
|
|
9
|
-
onUploadCompleted?: (event: FileUploadCompleted) => void;
|
|
10
|
-
onTextContentReady?: (event: FileTextContentReady) => void;
|
|
11
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export type FileUploadStatus = 'uploading' | 'upload_failed' | 'upload_complete';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
File without changes
|
|
File without changes
|