@pmate/chat-sdk 0.1.21 → 0.2.1
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/components/ChatInputDesktop.js +7 -7
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -1
- package/lib/services/{agentSdkASRClient.d.ts → functionASRClient.d.ts} +7 -7
- package/lib/services/{agentSdkASRClient.js → functionASRClient.js} +2 -2
- package/lib/tokens/chatInputThemes.d.ts +72 -1
- package/lib/tokens/chatInputThemes.js +44 -0
- package/lib/tokens/defaultTokens.js +10 -0
- package/lib/types/chatInput.d.ts +10 -0
- package/package.json +18 -16
- package/lib/recorder-processor.js +0 -20
- package/lib/stories/ChatInput.stories.d.ts +0 -15
- package/lib/stories/ChatInput.stories.js +0 -38
- package/lib/tests/agentSdkASRClient.test.d.ts +0 -1
- package/lib/tests/agentSdkASRClient.test.js +0 -39
- package/lib/tests/defaultTokens.test.d.ts +0 -1
- package/lib/tests/defaultTokens.test.js +0 -16
- package/lib/tests/transcriptComposer.test.d.ts +0 -1
- package/lib/tests/transcriptComposer.test.js +0 -10
|
@@ -168,8 +168,8 @@ function DesktopInner(props) {
|
|
|
168
168
|
display: "inline-flex",
|
|
169
169
|
alignItems: "center",
|
|
170
170
|
justifyContent: "center",
|
|
171
|
-
width:
|
|
172
|
-
height:
|
|
171
|
+
width: tokens.sizing.desktopSideAction,
|
|
172
|
+
height: tokens.sizing.desktopSideAction,
|
|
173
173
|
border: 0,
|
|
174
174
|
borderRadius: 999,
|
|
175
175
|
background: "transparent",
|
|
@@ -207,7 +207,7 @@ function DesktopInner(props) {
|
|
|
207
207
|
backdropFilter: "blur(18px)",
|
|
208
208
|
zIndex: 3,
|
|
209
209
|
}, children: [_jsxs("button", { type: "button", style: attachmentActionStyle, disabled: props.disabled || isUploadingImage, onClick: () => imageInputRef.current?.click(), children: [_jsx("span", { style: attachmentIconStyle, children: _jsx(ImageOutlineIcon, { size: 24 }) }), "\u56FE\u7247"] }), _jsxs("button", { type: "button", style: attachmentActionStyle, disabled: props.disabled, onClick: () => fileInputRef.current?.click(), children: [_jsx("span", { style: attachmentIconStyle, children: _jsx(FileOutlineIcon, { size: 24 }) }), "\u6587\u4EF6"] })] })) : null, voice.status === "recording" ? (_jsxs("div", { className: "flex items-center gap-3", children: [_jsx(WaveformFeedback, { levels: voice.waveformLevels, tokens: tokens, compact: true }), _jsxs("span", { style: { color: tokens.color.textSecondary, fontSize: 12 }, children: [Math.max(1, Math.round(voice.durationMs / 1000)), "s"] })] })) : null, props.multiline ? (_jsxs(InputSurface, { tokens: tokens, status: state.status, styleOverride: {
|
|
210
|
-
minHeight:
|
|
210
|
+
minHeight: tokens.sizing.multilineMinHeight,
|
|
211
211
|
padding: "16px 18px 12px",
|
|
212
212
|
display: "flex",
|
|
213
213
|
flexDirection: "column",
|
|
@@ -227,12 +227,12 @@ function DesktopInner(props) {
|
|
|
227
227
|
props.onChange?.(event.target.value);
|
|
228
228
|
}, style: {
|
|
229
229
|
flex: 1,
|
|
230
|
-
minHeight:
|
|
231
|
-
maxHeight:
|
|
230
|
+
minHeight: tokens.sizing.multilineTextMinHeight,
|
|
231
|
+
maxHeight: tokens.sizing.multilineTextMaxHeight,
|
|
232
232
|
padding: 0,
|
|
233
233
|
overflowY: "auto",
|
|
234
234
|
caretColor: tokens.color.brandPrimary,
|
|
235
|
-
} }), _jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 12 }, children: [_jsx(MoreTrigger, { "data-icon-size":
|
|
235
|
+
} }), _jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 12 }, children: [_jsx(MoreTrigger, { "data-icon-size": tokens.sizing.desktopIcon, onClick: () => { setIsEmojiOpen(false); setIsMoreOpen((prev) => !prev); }, disabled: props.disabled, style: { ...sideActionStyle, color: isMoreOpen ? tokens.color.iconActive : tokens.color.iconDefault, opacity: props.disabled ? 0.4 : 1 } }), _jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [_jsx("button", { type: "button", onClick: () => {
|
|
236
236
|
if (props.disabled || props.enableVoice === false)
|
|
237
237
|
return;
|
|
238
238
|
if (voice.status === "recording") {
|
|
@@ -248,7 +248,7 @@ function DesktopInner(props) {
|
|
|
248
248
|
color: voice.status === "recording" || voice.status === "transcribing" ? tokens.color.iconActive : tokens.color.iconDefault,
|
|
249
249
|
cursor: props.disabled || props.enableVoice === false ? "not-allowed" : "pointer",
|
|
250
250
|
opacity: props.disabled || props.enableVoice === false ? 0.4 : 1,
|
|
251
|
-
}, "aria-label": voice.status === "recording" ? "停止录音并转文字" : voice.status === "transcribing" ? "正在转写语音" : "开始语音输入", children: voice.status === "recording" ? _jsx(StopCircleOutlineIcon, { size:
|
|
251
|
+
}, "aria-label": voice.status === "recording" ? "停止录音并转文字" : voice.status === "transcribing" ? "正在转写语音" : "开始语音输入", children: voice.status === "recording" ? _jsx(StopCircleOutlineIcon, { size: tokens.sizing.desktopIcon }) : _jsx(MicOutlineIcon, { size: tokens.sizing.desktopIcon, strokeWidth: 2 }) }), _jsx(EmojiTrigger, { ref: emojiAnchorRef, "data-icon-size": tokens.sizing.desktopIcon, style: sideActionStyle, onClick: () => { setIsMoreOpen(false); setIsEmojiOpen((prev) => !prev); } }), _jsx(SendAction, { tokens: tokens, disabled: props.disabled || state.status === "sending" || (!state.text.trim() && state.attachments.length === 0), "aria-label": "\u53D1\u9001\u6D88\u606F", onClick: () => void onSend(), style: { width: tokens.sizing.desktopSendAction, height: tokens.sizing.desktopSendAction, padding: 0, borderRadius: 999, fontSize: tokens.sizing.desktopSendIcon, lineHeight: `${tokens.sizing.desktopSendAction}px` }, children: "\u2191" })] })] })] })) : _jsxs("div", { style: {
|
|
252
252
|
display: "grid",
|
|
253
253
|
gridTemplateColumns: "32px minmax(0, 1fr) 32px 32px",
|
|
254
254
|
alignItems: "center",
|
package/lib/index.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export * from "./hooks/useAttachmentState";
|
|
|
14
14
|
export * from "./hooks/useChatInputState";
|
|
15
15
|
export * from "./hooks/useTranscriptComposer";
|
|
16
16
|
export * from "./hooks/useVoiceInputController";
|
|
17
|
-
export * from "./services/
|
|
17
|
+
export * from "./services/functionASRClient";
|
|
18
18
|
export * from "./services/authTokenResolver";
|
|
19
19
|
export * from "./runtime/botAuth";
|
|
20
20
|
export * from "./runtime/botKey";
|
package/lib/index.js
CHANGED
|
@@ -14,7 +14,7 @@ export * from "./hooks/useAttachmentState";
|
|
|
14
14
|
export * from "./hooks/useChatInputState";
|
|
15
15
|
export * from "./hooks/useTranscriptComposer";
|
|
16
16
|
export * from "./hooks/useVoiceInputController";
|
|
17
|
-
export * from "./services/
|
|
17
|
+
export * from "./services/functionASRClient";
|
|
18
18
|
export * from "./services/authTokenResolver";
|
|
19
19
|
export * from "./runtime/botAuth";
|
|
20
20
|
export * from "./runtime/botKey";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AsyncStream } from "./AsyncStream";
|
|
2
|
-
export type
|
|
2
|
+
export type FunctionStreamLike = {
|
|
3
3
|
stream<TFinal = unknown, TChunk = Blob>(request: {
|
|
4
|
-
|
|
4
|
+
functionId: string;
|
|
5
5
|
stream: AsyncStream<TChunk>;
|
|
6
6
|
params?: Record<string, unknown>;
|
|
7
7
|
minChunkSizeBytes?: number;
|
|
@@ -9,17 +9,17 @@ export type AgentSdkStreamLike = {
|
|
|
9
9
|
finish(): Promise<TFinal | null>;
|
|
10
10
|
};
|
|
11
11
|
};
|
|
12
|
-
export type
|
|
13
|
-
client:
|
|
14
|
-
|
|
12
|
+
export type FunctionASRClientOptions = {
|
|
13
|
+
client: FunctionStreamLike;
|
|
14
|
+
functionId: string;
|
|
15
15
|
tokenResolver?: {
|
|
16
16
|
getToken(): string;
|
|
17
17
|
};
|
|
18
18
|
minChunkSizeBytes?: number;
|
|
19
19
|
};
|
|
20
|
-
export declare class
|
|
20
|
+
export declare class FunctionASRClient {
|
|
21
21
|
private readonly options;
|
|
22
|
-
constructor(options:
|
|
22
|
+
constructor(options: FunctionASRClientOptions);
|
|
23
23
|
transcribe(blob: Blob, input?: {
|
|
24
24
|
lang?: string;
|
|
25
25
|
}): Promise<{
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AsyncStream } from "./AsyncStream";
|
|
2
|
-
export class
|
|
2
|
+
export class FunctionASRClient {
|
|
3
3
|
options;
|
|
4
4
|
constructor(options) {
|
|
5
5
|
this.options = options;
|
|
@@ -8,7 +8,7 @@ export class AgentSdkASRClient {
|
|
|
8
8
|
const token = this.options.tokenResolver?.getToken() ?? "";
|
|
9
9
|
const stream = new AsyncStream();
|
|
10
10
|
const task = this.options.client.stream({
|
|
11
|
-
|
|
11
|
+
functionId: this.options.functionId,
|
|
12
12
|
stream,
|
|
13
13
|
params: {
|
|
14
14
|
lang: input?.lang ?? "auto",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type ChatInputThemeName = "pmate" | "dark" | "cli" | "compact";
|
|
1
|
+
export type ChatInputThemeName = "pmate" | "dark" | "issues" | "cli" | "compact";
|
|
2
2
|
export declare const chatInputThemes: {
|
|
3
3
|
pmate: {};
|
|
4
4
|
dark: {
|
|
@@ -29,6 +29,77 @@ export declare const chatInputThemes: {
|
|
|
29
29
|
recordingActive: string;
|
|
30
30
|
};
|
|
31
31
|
};
|
|
32
|
+
issues: {
|
|
33
|
+
color: {
|
|
34
|
+
brandPrimary: string;
|
|
35
|
+
surfaceInputDefault: string;
|
|
36
|
+
surfaceInputFocus: string;
|
|
37
|
+
surfaceInputRecording: string;
|
|
38
|
+
surfaceInputError: string;
|
|
39
|
+
textPrimary: string;
|
|
40
|
+
textSecondary: string;
|
|
41
|
+
iconDefault: string;
|
|
42
|
+
iconActive: string;
|
|
43
|
+
actionSendDefault: string;
|
|
44
|
+
actionSendDisabled: string;
|
|
45
|
+
actionSendTextOnPrimary: string;
|
|
46
|
+
borderDefault: string;
|
|
47
|
+
borderFocus: string;
|
|
48
|
+
borderError: string;
|
|
49
|
+
statusError: string;
|
|
50
|
+
statusWarning: string;
|
|
51
|
+
statusSuccess: string;
|
|
52
|
+
voiceWaveformActive: string;
|
|
53
|
+
voiceWaveformBackground: string;
|
|
54
|
+
};
|
|
55
|
+
spacing: {
|
|
56
|
+
inputOuter: number;
|
|
57
|
+
inputInner: number;
|
|
58
|
+
actionGap: number;
|
|
59
|
+
desktopToolbarGap: number;
|
|
60
|
+
};
|
|
61
|
+
radius: {
|
|
62
|
+
inputSurface: number;
|
|
63
|
+
desktopInputSurface: number;
|
|
64
|
+
actionButton: number;
|
|
65
|
+
};
|
|
66
|
+
sizing: {
|
|
67
|
+
desktopIcon: number;
|
|
68
|
+
desktopSideAction: number;
|
|
69
|
+
desktopSendAction: number;
|
|
70
|
+
desktopSendIcon: number;
|
|
71
|
+
multilineMinHeight: number;
|
|
72
|
+
multilineTextMinHeight: number;
|
|
73
|
+
multilineTextMaxHeight: number;
|
|
74
|
+
};
|
|
75
|
+
shadow: {
|
|
76
|
+
inputElevated: string;
|
|
77
|
+
};
|
|
78
|
+
typography: {
|
|
79
|
+
familyBase: string;
|
|
80
|
+
familyMono: string;
|
|
81
|
+
inputText: {
|
|
82
|
+
size: number;
|
|
83
|
+
lineHeight: number;
|
|
84
|
+
weight: number;
|
|
85
|
+
};
|
|
86
|
+
statusHint: {
|
|
87
|
+
size: number;
|
|
88
|
+
lineHeight: number;
|
|
89
|
+
weight: number;
|
|
90
|
+
};
|
|
91
|
+
actionLabel: {
|
|
92
|
+
size: number;
|
|
93
|
+
lineHeight: number;
|
|
94
|
+
weight: number;
|
|
95
|
+
};
|
|
96
|
+
voiceHoldToTalk: {
|
|
97
|
+
size: number;
|
|
98
|
+
lineHeight: number;
|
|
99
|
+
weight: number;
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
};
|
|
32
103
|
cli: {
|
|
33
104
|
color: {
|
|
34
105
|
brandPrimary: string;
|
|
@@ -28,6 +28,50 @@ export const chatInputThemes = {
|
|
|
28
28
|
recordingActive: "0 0 0 4px rgba(139, 124, 246, 0.18)",
|
|
29
29
|
},
|
|
30
30
|
},
|
|
31
|
+
issues: {
|
|
32
|
+
color: {
|
|
33
|
+
brandPrimary: "#8B7CF6",
|
|
34
|
+
surfaceInputDefault: "#171C23",
|
|
35
|
+
surfaceInputFocus: "#1D242D",
|
|
36
|
+
surfaceInputRecording: "#202839",
|
|
37
|
+
surfaceInputError: "#2B191D",
|
|
38
|
+
textPrimary: "#D7DCE3",
|
|
39
|
+
textSecondary: "#77818D",
|
|
40
|
+
iconDefault: "#737E8A",
|
|
41
|
+
iconActive: "#A99FFF",
|
|
42
|
+
actionSendDefault: "#4A5060",
|
|
43
|
+
actionSendDisabled: "#282E38",
|
|
44
|
+
actionSendTextOnPrimary: "#F3F5F8",
|
|
45
|
+
borderDefault: "#303844",
|
|
46
|
+
borderFocus: "#665CBF",
|
|
47
|
+
borderError: "#A84D59",
|
|
48
|
+
statusError: "#FF7D87",
|
|
49
|
+
statusWarning: "#E5A85E",
|
|
50
|
+
statusSuccess: "#45D495",
|
|
51
|
+
voiceWaveformActive: "#A99FFF",
|
|
52
|
+
voiceWaveformBackground: "#3B365F",
|
|
53
|
+
},
|
|
54
|
+
spacing: { inputOuter: 8, inputInner: 9, actionGap: 6, desktopToolbarGap: 6 },
|
|
55
|
+
radius: { inputSurface: 12, desktopInputSurface: 12, actionButton: 999 },
|
|
56
|
+
sizing: {
|
|
57
|
+
desktopIcon: 18,
|
|
58
|
+
desktopSideAction: 28,
|
|
59
|
+
desktopSendAction: 32,
|
|
60
|
+
desktopSendIcon: 18,
|
|
61
|
+
multilineMinHeight: 112,
|
|
62
|
+
multilineTextMinHeight: 46,
|
|
63
|
+
multilineTextMaxHeight: 144,
|
|
64
|
+
},
|
|
65
|
+
shadow: { inputElevated: "none" },
|
|
66
|
+
typography: {
|
|
67
|
+
familyBase: '"SF Mono", "JetBrains Mono", monospace',
|
|
68
|
+
familyMono: '"SF Mono", "JetBrains Mono", monospace',
|
|
69
|
+
inputText: { size: 13, lineHeight: 19, weight: 400 },
|
|
70
|
+
statusHint: { size: 10, lineHeight: 14, weight: 500 },
|
|
71
|
+
actionLabel: { size: 11, lineHeight: 15, weight: 600 },
|
|
72
|
+
voiceHoldToTalk: { size: 12, lineHeight: 17, weight: 600 },
|
|
73
|
+
},
|
|
74
|
+
},
|
|
31
75
|
cli: {
|
|
32
76
|
color: {
|
|
33
77
|
brandPrimary: "#25D6A0",
|
|
@@ -49,6 +49,15 @@ export const defaultChatInputTokens = {
|
|
|
49
49
|
inputElevated: "0 1px 2px rgba(15, 23, 42, 0.04)",
|
|
50
50
|
recordingActive: "0 0 0 4px rgba(18, 184, 134, 0.14)",
|
|
51
51
|
},
|
|
52
|
+
sizing: {
|
|
53
|
+
desktopIcon: 24,
|
|
54
|
+
desktopSideAction: 32,
|
|
55
|
+
desktopSendAction: 40,
|
|
56
|
+
desktopSendIcon: 24,
|
|
57
|
+
multilineMinHeight: 144,
|
|
58
|
+
multilineTextMinHeight: 64,
|
|
59
|
+
multilineTextMaxHeight: 180,
|
|
60
|
+
},
|
|
52
61
|
typography: {
|
|
53
62
|
familyBase: '"SF Pro Text", "PingFang SC", "Helvetica Neue", sans-serif',
|
|
54
63
|
familyMono: '"SF Mono", "JetBrains Mono", monospace',
|
|
@@ -67,6 +76,7 @@ export function mergeChatInputTokens(overrides) {
|
|
|
67
76
|
radius: { ...defaultChatInputTokens.radius, ...overrides?.radius },
|
|
68
77
|
motion: { ...defaultChatInputTokens.motion, ...overrides?.motion },
|
|
69
78
|
shadow: { ...defaultChatInputTokens.shadow, ...overrides?.shadow },
|
|
79
|
+
sizing: { ...defaultChatInputTokens.sizing, ...overrides?.sizing },
|
|
70
80
|
typography: {
|
|
71
81
|
...defaultChatInputTokens.typography,
|
|
72
82
|
...overrides?.typography,
|
package/lib/types/chatInput.d.ts
CHANGED
|
@@ -56,6 +56,15 @@ export type ChatInputShadowTokens = {
|
|
|
56
56
|
inputElevated: string;
|
|
57
57
|
recordingActive: string;
|
|
58
58
|
};
|
|
59
|
+
export type ChatInputSizingTokens = {
|
|
60
|
+
desktopIcon: number;
|
|
61
|
+
desktopSideAction: number;
|
|
62
|
+
desktopSendAction: number;
|
|
63
|
+
desktopSendIcon: number;
|
|
64
|
+
multilineMinHeight: number;
|
|
65
|
+
multilineTextMinHeight: number;
|
|
66
|
+
multilineTextMaxHeight: number;
|
|
67
|
+
};
|
|
59
68
|
export type ChatInputTypographyScale = {
|
|
60
69
|
size: number;
|
|
61
70
|
lineHeight: number;
|
|
@@ -75,6 +84,7 @@ export type ChatInputTokens = {
|
|
|
75
84
|
radius: ChatInputRadiusTokens;
|
|
76
85
|
motion: ChatInputMotionTokens;
|
|
77
86
|
shadow: ChatInputShadowTokens;
|
|
87
|
+
sizing: ChatInputSizingTokens;
|
|
78
88
|
typography: ChatInputTypographyTokens;
|
|
79
89
|
};
|
|
80
90
|
export type ChatInputSlotProps = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pmate/chat-sdk",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Cross-platform PMate chat input components, voice input primitives, and ASR helpers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -29,10 +29,18 @@
|
|
|
29
29
|
"publishConfig": {
|
|
30
30
|
"access": "public"
|
|
31
31
|
},
|
|
32
|
+
"scripts": {
|
|
33
|
+
"clean": "rimraf lib",
|
|
34
|
+
"build": "pnpm run clean && tsc -p tsconfig.build.json && cp src/voice/recorder-processor.js lib/voice/recorder-processor.js",
|
|
35
|
+
"prepack": "pnpm run build",
|
|
36
|
+
"npm:publish": "pnpm run build && npm publish --access public --registry https://registry.npmjs.org/",
|
|
37
|
+
"test": "vitest run",
|
|
38
|
+
"storybook": "storybook dev -p 6009",
|
|
39
|
+
"build-storybook": "storybook build --output-dir dist"
|
|
40
|
+
},
|
|
32
41
|
"dependencies": {
|
|
33
42
|
"@emoji-mart/data": "^1.2.1",
|
|
34
43
|
"@emoji-mart/react": "^1.1.1",
|
|
35
|
-
"@pmate/agent-sdk": "^1.1.2",
|
|
36
44
|
"@msgpack/msgpack": "^3.1.2",
|
|
37
45
|
"jotai": "^2.16.1"
|
|
38
46
|
},
|
|
@@ -43,21 +51,15 @@
|
|
|
43
51
|
"devDependencies": {
|
|
44
52
|
"@storybook/addon-docs": "^9.0.17",
|
|
45
53
|
"@storybook/react-vite": "9.0.17",
|
|
46
|
-
"@tailwindcss/vite": "
|
|
47
|
-
"@types/react": "
|
|
48
|
-
"@types/react-dom": "
|
|
49
|
-
"react": "
|
|
50
|
-
"react-dom": "
|
|
54
|
+
"@tailwindcss/vite": "catalog:",
|
|
55
|
+
"@types/react": "catalog:",
|
|
56
|
+
"@types/react-dom": "catalog:",
|
|
57
|
+
"react": "catalog:",
|
|
58
|
+
"react-dom": "catalog:",
|
|
59
|
+
"rimraf": "^6.1.2",
|
|
51
60
|
"storybook": "^9.0.17",
|
|
52
|
-
"tailwindcss": "
|
|
61
|
+
"tailwindcss": "catalog:",
|
|
53
62
|
"typescript": "5.9.2",
|
|
54
63
|
"vitest": "^4.0.17"
|
|
55
|
-
},
|
|
56
|
-
"scripts": {
|
|
57
|
-
"build": "tsc -p tsconfig.build.json && cp src/voice/recorder-processor.js lib/voice/recorder-processor.js",
|
|
58
|
-
"npm:publish": "pnpm run build && npm publish --access public --registry https://registry.npmjs.org/",
|
|
59
|
-
"test": "vitest run",
|
|
60
|
-
"storybook": "storybook dev -p 6009",
|
|
61
|
-
"build-storybook": "storybook build --output-dir dist"
|
|
62
64
|
}
|
|
63
|
-
}
|
|
65
|
+
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
class RecorderProcessor extends AudioWorkletProcessor {
|
|
2
|
-
process(inputs) {
|
|
3
|
-
const input = inputs[0]
|
|
4
|
-
if (!input || !input[0]) {
|
|
5
|
-
return true
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
const samples = input[0]
|
|
9
|
-
const pcm = new Int16Array(samples.length)
|
|
10
|
-
for (let i = 0; i < samples.length; i += 1) {
|
|
11
|
-
const sample = Math.max(-1, Math.min(1, samples[i]))
|
|
12
|
-
pcm[i] = sample < 0 ? sample * 0x8000 : sample * 0x7fff
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
this.port.postMessage({ type: "pcm", data: pcm.buffer }, [pcm.buffer])
|
|
16
|
-
return true
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
registerProcessor("pmate-mic-recorder-processor", RecorderProcessor)
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { StoryObj } from "@storybook/react-vite";
|
|
2
|
-
declare const meta: {
|
|
3
|
-
title: string;
|
|
4
|
-
parameters: {
|
|
5
|
-
layout: string;
|
|
6
|
-
};
|
|
7
|
-
};
|
|
8
|
-
export default meta;
|
|
9
|
-
type Story = StoryObj<typeof meta>;
|
|
10
|
-
export declare const MobileIdle: Story;
|
|
11
|
-
export declare const MobileVoiceReady: Story;
|
|
12
|
-
export declare const MobileRecording: Story;
|
|
13
|
-
export declare const DesktopTyping: Story;
|
|
14
|
-
export declare const DesktopAttachment: Story;
|
|
15
|
-
export declare const WaveformActive: Story;
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { ChatInputDesktop } from "../components/ChatInputDesktop";
|
|
3
|
-
import { ChatInputMobile } from "../components/ChatInputMobile";
|
|
4
|
-
import { WaveformFeedback } from "../components/WaveformFeedback";
|
|
5
|
-
import { mergeChatInputTokens } from "../tokens/defaultTokens";
|
|
6
|
-
const meta = {
|
|
7
|
-
title: "@pmate/chat-sdk/ChatInput",
|
|
8
|
-
parameters: {
|
|
9
|
-
layout: "centered",
|
|
10
|
-
},
|
|
11
|
-
};
|
|
12
|
-
export default meta;
|
|
13
|
-
export const MobileIdle = {
|
|
14
|
-
render: () => _jsx("div", { style: { width: 360 }, children: _jsx(ChatInputMobile, {}) }),
|
|
15
|
-
};
|
|
16
|
-
export const MobileVoiceReady = {
|
|
17
|
-
render: () => (_jsx("div", { style: { width: 360 }, children: _jsx(ChatInputMobile, { initialState: { mode: "voice", status: "voice-mode-ready" } }) })),
|
|
18
|
-
};
|
|
19
|
-
export const MobileRecording = {
|
|
20
|
-
render: () => (_jsx("div", { style: { width: 360 }, children: _jsx(ChatInputMobile, { initialState: {
|
|
21
|
-
mode: "voice",
|
|
22
|
-
status: "recording",
|
|
23
|
-
waveformLevels: [0.25, 0.5, 0.88, 0.52, 0.28],
|
|
24
|
-
} }) })),
|
|
25
|
-
};
|
|
26
|
-
export const DesktopTyping = {
|
|
27
|
-
render: () => (_jsx("div", { style: { width: 720 }, children: _jsx(ChatInputDesktop, { initialState: { text: "Ship chat-sdk storybook first", status: "typing" } }) })),
|
|
28
|
-
};
|
|
29
|
-
export const DesktopAttachment = {
|
|
30
|
-
render: () => (_jsx("div", { style: { width: 720 }, children: _jsx(ChatInputDesktop, { initialState: {
|
|
31
|
-
text: "Desktop attachment state",
|
|
32
|
-
status: "attachment-selected",
|
|
33
|
-
attachments: [{ id: "1", kind: "image", name: "spec.png" }],
|
|
34
|
-
} }) })),
|
|
35
|
-
};
|
|
36
|
-
export const WaveformActive = {
|
|
37
|
-
render: () => (_jsx(WaveformFeedback, { levels: [0.2, 0.5, 0.9, 0.55, 0.3], tokens: mergeChatInputTokens() })),
|
|
38
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { AgentSdkASRClient, } from "../services/agentSdkASRClient";
|
|
3
|
-
describe("AgentSdkASRClient", () => {
|
|
4
|
-
it("streams audio blobs through agent-sdk and returns final text", async () => {
|
|
5
|
-
const seen = {
|
|
6
|
-
blobSizes: [],
|
|
7
|
-
};
|
|
8
|
-
const client = new AgentSdkASRClient({
|
|
9
|
-
client: {
|
|
10
|
-
stream(request) {
|
|
11
|
-
seen.agentId = request.agentId;
|
|
12
|
-
seen.lang = String(request.params?.lang ?? "");
|
|
13
|
-
seen.token = String(request.params?.token ?? "");
|
|
14
|
-
return {
|
|
15
|
-
async finish() {
|
|
16
|
-
for await (const chunk of request.stream) {
|
|
17
|
-
seen.blobSizes.push(chunk.size);
|
|
18
|
-
}
|
|
19
|
-
return "transcribed text";
|
|
20
|
-
},
|
|
21
|
-
};
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
agentId: "agent:transcribe",
|
|
25
|
-
tokenResolver: {
|
|
26
|
-
getToken: () => "user-token",
|
|
27
|
-
},
|
|
28
|
-
minChunkSizeBytes: 0,
|
|
29
|
-
});
|
|
30
|
-
const result = await client.transcribe(new Blob(["voice-bytes"]), {
|
|
31
|
-
lang: "en",
|
|
32
|
-
});
|
|
33
|
-
expect(result.text).toBe("transcribed text");
|
|
34
|
-
expect(seen.agentId).toBe("agent:transcribe");
|
|
35
|
-
expect(seen.lang).toBe("en");
|
|
36
|
-
expect(seen.token).toBe("user-token");
|
|
37
|
-
expect(seen.blobSizes).toEqual([11]);
|
|
38
|
-
});
|
|
39
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { defaultChatInputTokens, mergeChatInputTokens } from "../tokens/defaultTokens";
|
|
3
|
-
describe("chat-sdk tokens", () => {
|
|
4
|
-
it("keeps purple brand as default", () => {
|
|
5
|
-
expect(defaultChatInputTokens.color.brandPrimary).toBe("#6D4AFF");
|
|
6
|
-
});
|
|
7
|
-
it("merges nested token overrides", () => {
|
|
8
|
-
const merged = mergeChatInputTokens({
|
|
9
|
-
color: {
|
|
10
|
-
brandPrimary: "#000000",
|
|
11
|
-
},
|
|
12
|
-
});
|
|
13
|
-
expect(merged.color.brandPrimary).toBe("#000000");
|
|
14
|
-
expect(merged.color.voiceWaveformActive).toBe(defaultChatInputTokens.color.voiceWaveformActive);
|
|
15
|
-
});
|
|
16
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { insertTranscriptText } from "../hooks/useTranscriptComposer";
|
|
3
|
-
describe("insertTranscriptText", () => {
|
|
4
|
-
it("returns transcript when current text is empty", () => {
|
|
5
|
-
expect(insertTranscriptText("", "hello")).toBe("hello");
|
|
6
|
-
});
|
|
7
|
-
it("appends transcript to existing text", () => {
|
|
8
|
-
expect(insertTranscriptText("draft", "hello")).toBe("draft hello");
|
|
9
|
-
});
|
|
10
|
-
});
|