telygent-ui 0.1.6 → 0.1.8
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/README.md
CHANGED
|
@@ -18,9 +18,9 @@ import {ChatProvider, type SendMessageInput, type SendMessageResult, type ChatMe
|
|
|
18
18
|
import {ChatInterface} from "@/components/ai/ChatInterface";
|
|
19
19
|
|
|
20
20
|
const adapter = {
|
|
21
|
-
async sendMessage({message, conversationId}: SendMessageInput): Promise<SendMessageResult> {
|
|
21
|
+
async sendMessage({message, conversationId, messageContext}: SendMessageInput): Promise<SendMessageResult> {
|
|
22
22
|
// Use React Query, Axios, RTK Query, etc.
|
|
23
|
-
const response = await api.send({message, conversationId});
|
|
23
|
+
const response = await api.send({message, conversationId, messageContext});
|
|
24
24
|
return {
|
|
25
25
|
conversationId: response.conversationId,
|
|
26
26
|
message: {
|
|
@@ -45,9 +45,10 @@ const adapter = {
|
|
|
45
45
|
|
|
46
46
|
export default function Page() {
|
|
47
47
|
const conversationId = "your-conversation-id";
|
|
48
|
+
const messageContext = "Viewing document id: 3283823883";
|
|
48
49
|
return (
|
|
49
50
|
<ChatProvider adapter={adapter}>
|
|
50
|
-
<ChatInterface conversationId={conversationId} aiName="Telygent" />
|
|
51
|
+
<ChatInterface conversationId={conversationId} aiName="Telygent" messageContext={messageContext} />
|
|
51
52
|
</ChatProvider>
|
|
52
53
|
);
|
|
53
54
|
}
|
|
@@ -68,6 +69,7 @@ async function* streamChat(input: SendMessageInput): AsyncIterable<ChatStreamEve
|
|
|
68
69
|
body: JSON.stringify({
|
|
69
70
|
question: input.message,
|
|
70
71
|
conversationId: input.conversationId,
|
|
72
|
+
messageContext: input.messageContext,
|
|
71
73
|
}),
|
|
72
74
|
});
|
|
73
75
|
|
|
@@ -111,7 +113,7 @@ const adapter = {
|
|
|
111
113
|
export default function Page() {
|
|
112
114
|
return (
|
|
113
115
|
<ChatProvider adapter={adapter}>
|
|
114
|
-
<ChatInterface conversationId="conv_123" />
|
|
116
|
+
<ChatInterface conversationId="conv_123" messageContext="Viewing transaction id: txn_123" />
|
|
115
117
|
</ChatProvider>
|
|
116
118
|
);
|
|
117
119
|
}
|
package/package.json
CHANGED
|
@@ -6,9 +6,9 @@ import {MarkdownRenderer} from "./MarkdownRenderer";
|
|
|
6
6
|
import AIWriter from "react-aiwriter";
|
|
7
7
|
import * as echarts from "echarts";
|
|
8
8
|
import type {EChartsOption} from "echarts";
|
|
9
|
-
import {Check, Copy} from "lucide-react";
|
|
9
|
+
import {Check, Copy, Download} from "lucide-react";
|
|
10
10
|
|
|
11
|
-
import {cn} from "
|
|
11
|
+
import {cn} from "./utils";
|
|
12
12
|
import {type ChatMessage, type ChatSummaryCard, type ChatVisualization} from "./ChatProvider";
|
|
13
13
|
import {useDatabaseChat} from "../hooks/use-database-chat";
|
|
14
14
|
|
|
@@ -18,8 +18,17 @@ const MemoizedAIWriter = React.memo(({children}: {children: React.ReactNode}) =>
|
|
|
18
18
|
});
|
|
19
19
|
MemoizedAIWriter.displayName = "MemoizedAIWriter";
|
|
20
20
|
|
|
21
|
-
const
|
|
21
|
+
const getChartFilename = (seed: string) => {
|
|
22
|
+
const normalized = seed
|
|
23
|
+
.toLowerCase()
|
|
24
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
25
|
+
.replace(/^-+|-+$/g, "");
|
|
26
|
+
return normalized || "chart";
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const EChart = ({option, fileName}: {option: EChartsOption; fileName: string}) => {
|
|
22
30
|
const chartRef = React.useRef<HTMLDivElement>(null);
|
|
31
|
+
const chartInstanceRef = React.useRef<echarts.ECharts | null>(null);
|
|
23
32
|
|
|
24
33
|
React.useEffect(() => {
|
|
25
34
|
if (!chartRef.current) {
|
|
@@ -27,6 +36,7 @@ const EChart = ({option}: {option: EChartsOption}) => {
|
|
|
27
36
|
}
|
|
28
37
|
|
|
29
38
|
const instance = echarts.init(chartRef.current);
|
|
39
|
+
chartInstanceRef.current = instance;
|
|
30
40
|
instance.setOption(option);
|
|
31
41
|
|
|
32
42
|
const handleResize = () => instance.resize();
|
|
@@ -35,10 +45,48 @@ const EChart = ({option}: {option: EChartsOption}) => {
|
|
|
35
45
|
return () => {
|
|
36
46
|
window.removeEventListener("resize", handleResize);
|
|
37
47
|
instance.dispose();
|
|
48
|
+
chartInstanceRef.current = null;
|
|
38
49
|
};
|
|
39
50
|
}, [option]);
|
|
40
51
|
|
|
41
|
-
|
|
52
|
+
const handleExportChart = React.useCallback(() => {
|
|
53
|
+
const instance = chartInstanceRef.current;
|
|
54
|
+
if (!instance) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
const dataUrl = instance.getDataURL({
|
|
60
|
+
type: "png",
|
|
61
|
+
pixelRatio: 2,
|
|
62
|
+
backgroundColor: "#ffffff",
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const link = document.createElement("a");
|
|
66
|
+
link.href = dataUrl;
|
|
67
|
+
link.download = `${getChartFilename(fileName)}.png`;
|
|
68
|
+
document.body.appendChild(link);
|
|
69
|
+
link.click();
|
|
70
|
+
document.body.removeChild(link);
|
|
71
|
+
} catch (error) {
|
|
72
|
+
console.error("Unable to export chart image.", error);
|
|
73
|
+
}
|
|
74
|
+
}, [fileName]);
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<div>
|
|
78
|
+
<div ref={chartRef} className="h-64 w-full" />
|
|
79
|
+
<button
|
|
80
|
+
type="button"
|
|
81
|
+
onClick={handleExportChart}
|
|
82
|
+
className="mt-2 inline-flex items-center gap-1 text-xs font-medium text-slate-600 transition hover:text-slate-700"
|
|
83
|
+
aria-label="Export chart as PNG"
|
|
84
|
+
>
|
|
85
|
+
<Download className="h-4 w-4" />
|
|
86
|
+
<span>Export PNG</span>
|
|
87
|
+
</button>
|
|
88
|
+
</div>
|
|
89
|
+
);
|
|
42
90
|
};
|
|
43
91
|
|
|
44
92
|
const inlineComputedStyles = (source: Element, target: Element) => {
|
|
@@ -128,12 +176,13 @@ const renderVisualization = (viz: ChatVisualization, key: string) => {
|
|
|
128
176
|
return null;
|
|
129
177
|
}
|
|
130
178
|
|
|
179
|
+
const chartName = viz.title || key || "chart";
|
|
131
180
|
return (
|
|
132
181
|
<div key={key} className="rounded-2xl border border-slate-200 bg-white p-3">
|
|
133
182
|
{viz.title ? (
|
|
134
183
|
<p className="mb-2 text-sm font-semibold text-slate-700">{viz.title}</p>
|
|
135
184
|
) : null}
|
|
136
|
-
<EChart option={viz.options as EChartsOption} />
|
|
185
|
+
<EChart option={viz.options as EChartsOption} fileName={chartName} />
|
|
137
186
|
</div>
|
|
138
187
|
);
|
|
139
188
|
};
|
|
@@ -336,7 +385,7 @@ UserMessageBody.displayName = "UserMessageBody";
|
|
|
336
385
|
|
|
337
386
|
export type ChatInterfaceProps = {
|
|
338
387
|
className?: string;
|
|
339
|
-
|
|
388
|
+
messageContext?: string;
|
|
340
389
|
placeholder?: string;
|
|
341
390
|
defaultPrompts?: {label: string; accent?: string}[];
|
|
342
391
|
conversationId: string;
|
|
@@ -347,7 +396,7 @@ export type ChatInterfaceProps = {
|
|
|
347
396
|
|
|
348
397
|
export function ChatInterface({
|
|
349
398
|
className,
|
|
350
|
-
|
|
399
|
+
messageContext,
|
|
351
400
|
placeholder,
|
|
352
401
|
defaultPrompts,
|
|
353
402
|
conversationId,
|
|
@@ -364,7 +413,7 @@ export function ChatInterface({
|
|
|
364
413
|
loading,
|
|
365
414
|
loadingHistory,
|
|
366
415
|
prompts,
|
|
367
|
-
} = useDatabaseChat({
|
|
416
|
+
} = useDatabaseChat({messageContext, defaultPrompts, conversationId});
|
|
368
417
|
|
|
369
418
|
const containerRef = React.useRef<HTMLDivElement>(null);
|
|
370
419
|
const scrollRef = React.useRef<HTMLDivElement>(null);
|
|
@@ -571,10 +620,10 @@ export function ChatInterface({
|
|
|
571
620
|
</div>
|
|
572
621
|
|
|
573
622
|
<div className="border-t border-slate-200 bg-white px-6 py-4">
|
|
574
|
-
{
|
|
623
|
+
{messageContext ? (
|
|
575
624
|
<div className="mb-2 flex w-6/12">
|
|
576
625
|
<div className="truncate rounded-full border border-[dodgerblue] bg-[dodgerblue]/10 px-2 text-xs">
|
|
577
|
-
{
|
|
626
|
+
{messageContext}
|
|
578
627
|
</div>
|
|
579
628
|
</div>
|
|
580
629
|
) : null}
|
|
@@ -5,12 +5,12 @@ import {useChatAdapter, type ChatMessage, type ChatStreamEvent} from "../compone
|
|
|
5
5
|
|
|
6
6
|
export type UseDatabaseChatOptions = {
|
|
7
7
|
conversationId: string;
|
|
8
|
-
|
|
8
|
+
messageContext?: string;
|
|
9
9
|
defaultPrompts?: {label: string; accent?: string}[];
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
export function useDatabaseChat(options: UseDatabaseChatOptions) {
|
|
13
|
-
const {conversationId: initialConversationId,
|
|
13
|
+
const {conversationId: initialConversationId, messageContext, defaultPrompts} = options;
|
|
14
14
|
const adapter = useChatAdapter();
|
|
15
15
|
|
|
16
16
|
const [conversationId] = React.useState<string>(initialConversationId);
|
|
@@ -74,7 +74,6 @@ export function useDatabaseChat(options: UseDatabaseChatOptions) {
|
|
|
74
74
|
return;
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
const withContext = `${viewContext ?? ""} ${outgoing}`.trim();
|
|
78
77
|
addMessage({role: "user", content: outgoing, createdAt: new Date()});
|
|
79
78
|
setMessage("");
|
|
80
79
|
|
|
@@ -93,9 +92,9 @@ export function useDatabaseChat(options: UseDatabaseChatOptions) {
|
|
|
93
92
|
|
|
94
93
|
const stream =
|
|
95
94
|
(await adapter.sendMessageStream({
|
|
96
|
-
message:
|
|
95
|
+
message: outgoing,
|
|
97
96
|
conversationId,
|
|
98
|
-
|
|
97
|
+
messageContext,
|
|
99
98
|
})) as AsyncIterable<ChatStreamEvent>;
|
|
100
99
|
|
|
101
100
|
for await (const event of stream) {
|
|
@@ -135,9 +134,9 @@ export function useDatabaseChat(options: UseDatabaseChatOptions) {
|
|
|
135
134
|
}
|
|
136
135
|
} else {
|
|
137
136
|
const result = await adapter.sendMessage({
|
|
138
|
-
message:
|
|
137
|
+
message: outgoing,
|
|
139
138
|
conversationId,
|
|
140
|
-
|
|
139
|
+
messageContext,
|
|
141
140
|
});
|
|
142
141
|
addMessage(result.message);
|
|
143
142
|
}
|
|
@@ -145,7 +144,7 @@ export function useDatabaseChat(options: UseDatabaseChatOptions) {
|
|
|
145
144
|
setLoading(false);
|
|
146
145
|
}
|
|
147
146
|
},
|
|
148
|
-
[adapter, addMessage, conversationId, message,
|
|
147
|
+
[adapter, addMessage, conversationId, message, messageContext]
|
|
149
148
|
);
|
|
150
149
|
|
|
151
150
|
return {
|
package/registry/index.json
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
"components/ChatProvider.tsx",
|
|
8
8
|
"components/ChatInterface.tsx",
|
|
9
9
|
"components/MarkdownRenderer.tsx",
|
|
10
|
+
"components/utils.ts",
|
|
10
11
|
"components/ai-mdx.css",
|
|
11
12
|
"hooks/use-database-chat.ts",
|
|
12
13
|
"hooks/use-rtk-stream-adapter.ts"
|
|
@@ -16,7 +17,9 @@
|
|
|
16
17
|
"markdown-to-jsx",
|
|
17
18
|
"react-aiwriter",
|
|
18
19
|
"moment",
|
|
19
|
-
"lucide-react"
|
|
20
|
+
"lucide-react",
|
|
21
|
+
"clsx",
|
|
22
|
+
"tailwind-merge"
|
|
20
23
|
],
|
|
21
24
|
"peerDependencies": [
|
|
22
25
|
"@reduxjs/toolkit"
|