@amaster.ai/components-templates 1.4.11 → 1.6.0

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.
Files changed (39) hide show
  1. package/README.md +12 -8
  2. package/components/ai-assistant/amaster.config.json +3 -0
  3. package/components/ai-assistant/package.json +3 -3
  4. package/components/ai-assistant/template/components/chat-assistant-message.tsx +1 -1
  5. package/components/ai-assistant/template/components/chat-banner.tsx +1 -1
  6. package/components/ai-assistant/template/components/chat-display-mode-switcher.tsx +6 -6
  7. package/components/ai-assistant/template/components/chat-floating-button.tsx +4 -5
  8. package/components/ai-assistant/template/components/chat-floating-card.tsx +3 -3
  9. package/components/ai-assistant/template/components/chat-header.tsx +5 -5
  10. package/components/ai-assistant/template/components/chat-input.tsx +21 -22
  11. package/components/ai-assistant/template/components/chat-messages.tsx +10 -2
  12. package/components/ai-assistant/template/components/chat-recommends.tsx +12 -14
  13. package/components/ai-assistant/template/components/chat-user-message.tsx +1 -1
  14. package/components/ai-assistant/template/components/ui-renderer.tsx +1 -1
  15. package/components/ai-assistant/template/components/voice-input.tsx +1 -1
  16. package/components/ai-assistant/template/hooks/useVoiceInput.ts +18 -20
  17. package/components/ai-assistant/template/inline-ai-assistant.tsx +1 -1
  18. package/components/ai-assistant-taro/amaster.config.json +3 -0
  19. package/components/ai-assistant-taro/package.json +94 -0
  20. package/components/ai-assistant-taro/template/components/ChatAssistantMessage.tsx +154 -0
  21. package/components/ai-assistant-taro/template/components/ChatHeader.tsx +27 -0
  22. package/components/ai-assistant-taro/template/components/ChatInput.tsx +204 -0
  23. package/components/ai-assistant-taro/template/components/ChatMessages.tsx +126 -0
  24. package/components/ai-assistant-taro/template/components/ChatUserMessage.tsx +25 -0
  25. package/components/ai-assistant-taro/template/components/VoiceInput.tsx +169 -0
  26. package/components/ai-assistant-taro/template/components/markdown.tsx +156 -0
  27. package/components/ai-assistant-taro/template/hooks/useConversation.ts +787 -0
  28. package/components/ai-assistant-taro/template/hooks/useSafeArea.ts +20 -0
  29. package/components/ai-assistant-taro/template/hooks/useVoiceInput.ts +204 -0
  30. package/components/ai-assistant-taro/template/i18n.ts +157 -0
  31. package/components/ai-assistant-taro/template/index.config.ts +10 -0
  32. package/components/ai-assistant-taro/template/index.tsx +83 -0
  33. package/components/ai-assistant-taro/template/types.ts +58 -0
  34. package/package.json +5 -2
  35. package/packages/cli/dist/index.js +14 -3
  36. package/packages/cli/dist/index.js.map +1 -1
  37. package/packages/cli/package.json +1 -1
  38. package/components/ai-assistant/example.md +0 -34
  39. package/components/ai-assistant/others.md +0 -16
package/README.md CHANGED
@@ -137,12 +137,14 @@ npm run create:component
137
137
 
138
138
  1. 在 `components/` 目录下创建新组件目录
139
139
  2. 添加 `package.json` 配置文件
140
- 3. `template/` 目录下放置模板文件
140
+ 3. 添加 `amaster.config.json` 配置文件(配置目标目录)
141
+ 4. 在 `template/` 目录下放置模板文件
141
142
 
142
143
  ```
143
144
  components/
144
145
  └── your-component/
145
- ├── package.json # 组件配置
146
+ ├── package.json # 组件依赖配置
147
+ ├── amaster.config.json # 组件模板配置
146
148
  └── template/ # 模板文件
147
149
  ├── index.ts
148
150
  └── ...
@@ -155,12 +157,6 @@ components/
155
157
  "name": "your-component",
156
158
  "version": "1.0.0",
157
159
  "description": "组件描述",
158
- "template": {
159
- "name": "your-component",
160
- "targetDir": "src/components/your-component",
161
- "files": ["**/*"],
162
- "ignore": ["node_modules", "*.log", ".DS_Store"]
163
- },
164
160
  "dependencies": {
165
161
  "some-lib": "^1.0.0"
166
162
  },
@@ -173,6 +169,14 @@ components/
173
169
  }
174
170
  ```
175
171
 
172
+ ### 组件 amaster.config.json 配置
173
+
174
+ ```json
175
+ {
176
+ "targetDir": "src/components/your-component"
177
+ }
178
+ ```
179
+
176
180
  ## 发布
177
181
 
178
182
  ```bash
@@ -0,0 +1,3 @@
1
+ {
2
+ "targetDir": "src/components/ai-assistant"
3
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "amaster-react-project",
3
- "version": "1.4.11",
3
+ "version": "1.6.0",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "dev": "vite --force",
@@ -17,8 +17,8 @@
17
17
  },
18
18
  "dependencies": {
19
19
  "@a2a-js/sdk": "^0.3.7",
20
- "@amaster.ai/client": "1.1.0-beta.56",
21
- "@amaster.ai/vite-plugins": "1.1.0-beta.56",
20
+ "@amaster.ai/client": "1.1.0-beta.59",
21
+ "@amaster.ai/vite-plugins": "1.1.0-beta.59",
22
22
  "@fontsource-variable/inter": "^5.2.8",
23
23
  "@fortawesome/fontawesome-free": "^6.1.1",
24
24
  "@hookform/resolvers": "^5.2.2",
@@ -195,7 +195,7 @@ const ChatAssistantMessage: React.FC<
195
195
  )}
196
196
  >
197
197
  {showAvatar && (
198
- <MessageSquare className="h-3.5 w-3.5 text-white" strokeWidth={2} />
198
+ <MessageSquare className="h-3.5 w-3.5 text-primary-foreground" strokeWidth={2} />
199
199
  )}
200
200
  </div>
201
201
  <MessageContentRenderer message={message} {...rest} />
@@ -8,7 +8,7 @@ const ChatBanner: React.FC<{
8
8
  return null;
9
9
  }
10
10
  return (
11
- <h1 className="text-center text-3xl text-[#000] font-medium p-4">
11
+ <h1 className="text-center text-3xl text-foreground font-medium p-4">
12
12
  {text || getText().greeting}
13
13
  </h1>
14
14
  );
@@ -16,22 +16,22 @@ const ChatDisplayModeSwitcher: React.FC<{
16
16
  }[] = [
17
17
  {
18
18
  mode: "floating",
19
- icon: <Layers2 className="h-4 w-4" strokeWidth={1.75} />,
19
+ icon: <Layers2 className="size-4" strokeWidth={1.75} />,
20
20
  title: getText().displayMode.floating,
21
21
  },
22
22
  {
23
23
  mode: "side-right",
24
- icon: <Sidebar className="h-4 w-4 rotate-180" strokeWidth={1.75} />,
24
+ icon: <Sidebar className="size-4 rotate-180" strokeWidth={1.75} />,
25
25
  title: getText().displayMode.sideRight,
26
26
  },
27
27
  {
28
28
  mode: "side-left",
29
- icon: <Sidebar className="h-4 w-4 " strokeWidth={1.75} />,
29
+ icon: <Sidebar className="size-4 " strokeWidth={1.75} />,
30
30
  title: getText().displayMode.sideLeft,
31
31
  },
32
32
  {
33
33
  mode: "fullscreen",
34
- icon: <Maximize className="h-4 w-4" strokeWidth={1.75} />,
34
+ icon: <Maximize className="size-4" strokeWidth={1.75} />,
35
35
  title: getText().displayMode.fullscreen,
36
36
  },
37
37
  ];
@@ -39,7 +39,7 @@ const ChatDisplayModeSwitcher: React.FC<{
39
39
  return (
40
40
  <HoverCard openDelay={0}>
41
41
  <HoverCardTrigger asChild>
42
- <Button variant="ghost" size="icon" className="hover:bg-transparent text-black/50 hover:text-black">
42
+ <Button variant="ghost" size="icon" className="size-8">
43
43
  {modes.find((m) => m.mode === displayMode)?.icon}
44
44
  </Button>
45
45
  </HoverCardTrigger>
@@ -48,7 +48,7 @@ const ChatDisplayModeSwitcher: React.FC<{
48
48
  <Button
49
49
  key={mode}
50
50
  variant="ghost"
51
- className="justify-start hover:bg-gray-200 text-black/80 hover:text-black data-[state=open]:bg-transparent"
51
+ className="justify-start"
52
52
  onClick={() => onChange(mode)}
53
53
  size="sm"
54
54
  disabled={mode === displayMode}
@@ -10,7 +10,6 @@ interface ChatFloatingButtonProps {
10
10
  style: React.CSSProperties;
11
11
  }
12
12
 
13
-
14
13
  const ChatFloatingButton: React.FC<ChatFloatingButtonProps> = ({
15
14
  onClick,
16
15
  onMouseDown,
@@ -32,14 +31,14 @@ const ChatFloatingButton: React.FC<ChatFloatingButtonProps> = ({
32
31
  className={`
33
32
  group relative h-full w-full rounded-full
34
33
  bg-gradient-to-br from-primary to-primary/40
35
- text-white
34
+ text-primary-foreground
36
35
  border-0
37
36
  transition-all duration-300 ease-out select-none
38
37
  cursor-pointer
39
38
  ${
40
39
  isDragging
41
- ? "shadow-[0_8px_30px_rgba(99,102,241,0.5)] scale-105"
42
- : "shadow-[0_4px_20px_rgba(99,102,241,0.35)] hover:shadow-[0_8px_30px_rgba(99,102,241,0.5)] hover:scale-105"
40
+ ? "shadow-2xl scale-105"
41
+ : "shadow-lg hover:shadow-2xl hover:scale-105"
43
42
  }
44
43
  `}
45
44
  >
@@ -53,4 +52,4 @@ const ChatFloatingButton: React.FC<ChatFloatingButtonProps> = ({
53
52
  );
54
53
  };
55
54
 
56
- export default ChatFloatingButton;
55
+ export default ChatFloatingButton;
@@ -23,14 +23,14 @@ const ChatFloatingCard: React.FC<ChatFloatingCardProps> = ({
23
23
  <Card
24
24
  ref={containerRef}
25
25
  className={cn(
26
- `flex flex-col overflow-hidden bg-[#F9FAFB] border border-[#E5E7EB] z-50`,
26
+ `flex flex-col overflow-hidden bg-card border border-border z-50`,
27
27
  {
28
28
  "fixed inset-0 w-auto h-auto animate-in fade-in-0 zoom-in-[0.98] duration-300 origin-top-left rounded-none": displayMode === "fullscreen",
29
29
  "fixed top-0 right-0 w-[420px] h-full rounded-none": displayMode === "side-right",
30
30
  "fixed top-0 left-0 w-[420px] h-full rounded-none": displayMode === "side-left",
31
31
  "rounded-2xl": displayMode === "floating",
32
- "shadow-[0_25px_50px_-12px_rgba(0,0,0,0.25)]": displayMode === "floating" && isDragging,
33
- "shadow-[0_10px_40px_-10px_rgba(0,0,0,0.1),0_4px_6px_-4px_rgba(0,0,0,0.1)]": displayMode === "floating" && !isDragging,
32
+ "shadow-2xl": displayMode === "floating" && isDragging,
33
+ "shadow-lg": displayMode === "floating" && !isDragging,
34
34
  }
35
35
  )}
36
36
  style={displayMode !== "floating" ? {} : style}
@@ -27,14 +27,14 @@ const ChatHeader: React.FC<ChatHeaderProps> = ({
27
27
  return (
28
28
  <div
29
29
  className={cn(
30
- "flex items-center justify-between px-4",
30
+ "flex items-center justify-between px-4 py-1 pr-2",
31
31
  !disabledDrag && onMouseDown
32
32
  ? isDragging
33
33
  ? "cursor-grabbing"
34
34
  : "cursor-grab"
35
35
  : "",
36
36
  {
37
- 'border-b border-[#E5E7EB] bg-white': displayMode === "floating",
37
+ 'border-b border-border': displayMode === "floating",
38
38
  },
39
39
  )}
40
40
  onMouseDown={!disabledDrag ? onMouseDown : undefined}
@@ -42,7 +42,7 @@ const ChatHeader: React.FC<ChatHeaderProps> = ({
42
42
  >
43
43
  <div className="flex items-center gap-2.5">
44
44
  <div className="flex flex-col">
45
- <span className="text-sm font-semibold text-[#111827]">
45
+ <span className="text-sm font-semibold text-foreground">
46
46
  {getText().assistantName}
47
47
  </span>
48
48
  </div>
@@ -55,9 +55,9 @@ const ChatHeader: React.FC<ChatHeaderProps> = ({
55
55
  variant="ghost"
56
56
  size="icon"
57
57
  onClick={onClose}
58
- className="h-8 w-8 text-[#6B7280] hover:text-[#374151] hover:bg-[#F3F4F6] rounded-lg transition-colors duration-200 cursor-pointer"
58
+ className="size-8"
59
59
  >
60
- <X className="h-4 w-4" strokeWidth={1.75} />
60
+ <X className="size-4" strokeWidth={1.75} />
61
61
  </Button>
62
62
  )}
63
63
  </div>
@@ -19,7 +19,10 @@ import {
19
19
  } from "@/components/ui/tooltip";
20
20
  import VoiceInputButton from "./voice-input";
21
21
 
22
- const NewConvButton: React.FC<{ onNew?: () => void; disabled?: boolean }> = ({ onNew, disabled }) => {
22
+ const NewConvButton: React.FC<{ onNew?: () => void; disabled?: boolean }> = ({
23
+ onNew,
24
+ disabled,
25
+ }) => {
23
26
  if (!onNew) return null;
24
27
  return (
25
28
  <TooltipProvider>
@@ -32,7 +35,7 @@ const NewConvButton: React.FC<{ onNew?: () => void; disabled?: boolean }> = ({ o
32
35
  size="icon"
33
36
  onClick={onNew}
34
37
  disabled={disabled}
35
- className="h-8 w-8 text-[#6B7280] hover:text-[#374151] hover:bg-[#F3F4F6] rounded-lg transition-colors duration-200 cursor-pointer"
38
+ className="h-8 w-8 cursor-pointer"
36
39
  >
37
40
  <MessageCirclePlus className="size-5" />
38
41
  </Button>
@@ -49,12 +52,11 @@ const SubmitButton: React.FC<{
49
52
  }> = ({ disabled, starting, onClick }) => {
50
53
  return (
51
54
  <Button
52
- type="button"
53
55
  onClick={onClick}
54
56
  disabled={disabled || starting}
55
57
  size="icon"
56
58
  className={cn(
57
- "size-8 text-white rounded-xl transition-all duration-200 cursor-pointer shadow-[0_2px_8px_rgba(99,102,241,0.3)] hover:shadow-[0_4px_12px_rgba(99,102,241,0.4)]",
59
+ "rounded-xl size-8 text-primary-foreground transition-all duration-200 cursor-pointer shadow-sm hover:shadow-2xl",
58
60
  "bg-gradient-to-r from-primary to-primary/80",
59
61
  "hover:from-primary/90 hover:to-primary/70",
60
62
  "disabled:opacity-40 disabled:cursor-not-allowed",
@@ -76,20 +78,10 @@ const StopButton: React.FC<{ onClick: () => void; disabled?: boolean }> = ({
76
78
  }) => {
77
79
  return (
78
80
  <Button
79
- type="button"
80
81
  onClick={onClick}
81
82
  size="icon"
82
83
  disabled={disabled}
83
- className="
84
- size-8
85
- bg-foreground
86
- hover:bg-foreground/50
87
- text-white
88
- rounded-xl
89
- transition-all duration-200
90
- cursor-pointer
91
- shadow-[0_2px_8px_rgba(239,68,68,0.3)]
92
- hover:shadow-[0_4px_12px_rgba(239,68,68,0.4)]"
84
+ className="size-8 bg-success hover:bg-success/50 text-success-foreground rounded-xl transition-all duration-200 cursor-pointer shadow-sm hover:shadow-2xl"
93
85
  >
94
86
  <Square className="h-3 w-3 fill-current" strokeWidth={2} />
95
87
  </Button>
@@ -117,14 +109,14 @@ const ChatInput: React.FC<ChatInputProps> = ({
117
109
  onNew,
118
110
  onCancel,
119
111
  starting,
120
- displayMode
112
+ displayMode,
121
113
  }) => {
122
114
  const hasConversations = conversations.length > 0;
123
115
  const lastConv =
124
116
  conversations.length > 0 ? conversations[conversations.length - 1] : null;
125
117
  const lastIsDivider = useMemo(() => {
126
118
  if (!lastConv) return false;
127
- return (lastConv.system?.level === "newConversation");
119
+ return lastConv.system?.level === "newConversation";
128
120
  }, [lastConv]);
129
121
 
130
122
  const [focus, setFocus] = useState(false);
@@ -139,7 +131,7 @@ const ChatInput: React.FC<ChatInputProps> = ({
139
131
  <div className="py-3 px-4">
140
132
  <div
141
133
  className={cn(
142
- "w-full rounded-xl bg-white transition-all duration-200 p-3 border border-primary/80",
134
+ "w-full rounded-xl bg-card transition-all duration-200 p-3 border border-primary/80",
143
135
  {
144
136
  "border-primary ring-2 ring-primary/20": focus,
145
137
  },
@@ -154,12 +146,19 @@ const ChatInput: React.FC<ChatInputProps> = ({
154
146
  placeholder={getText().typePlaceholder}
155
147
  onFocus={() => setFocus(true)}
156
148
  onBlur={() => setFocus(false)}
157
- className="w-full text-sm text-[#111827] placeholder:text-[#9CA3AF] outline-none resize-none leading-5 disabled:bg-transparent"
149
+ className="w-full text-sm text-foreground placeholder:text-muted-foreground outline-none resize-none leading-5 bg-card"
158
150
  rows={4}
159
151
  />
160
152
  <div className="flex items-center justify-between gap-2 mt-1">
161
153
  <div className="flex items-center gap-1">
162
- {onNew && <NewConvButton onNew={onNew} disabled={!hasConversations || lastIsDivider || starting || isLoading} />}
154
+ {onNew && (
155
+ <NewConvButton
156
+ onNew={onNew}
157
+ disabled={
158
+ !hasConversations || lastIsDivider || starting || isLoading
159
+ }
160
+ />
161
+ )}
163
162
  </div>
164
163
  <div className="flex items-center gap-2">
165
164
  <VoiceInputButton
@@ -170,7 +169,7 @@ const ChatInput: React.FC<ChatInputProps> = ({
170
169
  value={inputValue}
171
170
  disabled={isLoading || starting}
172
171
  />
173
- {isLoading ? (
172
+ {!isLoading ? (
174
173
  <StopButton onClick={onCancel || (() => {})} />
175
174
  ) : (
176
175
  <SubmitButton
@@ -184,7 +183,7 @@ const ChatInput: React.FC<ChatInputProps> = ({
184
183
  </div>
185
184
 
186
185
  {(conversations.length > 0 || displayMode !== "inline") && (
187
- <p className="text-[10px] text-[#9CA3AF] mt-2 text-center">
186
+ <p className="text-[10px] text-muted-foreground/50 mt-2 text-center">
188
187
  {getText().footerAiWarning}
189
188
  </p>
190
189
  )}
@@ -71,6 +71,13 @@ const ChatMessages: React.FC<ChatMessagesProps> = ({
71
71
  },
72
72
  className,
73
73
  )}
74
+ style={{
75
+ maskImage:
76
+ "linear-gradient(to bottom, transparent, black 10px, black calc(100% - 10px), transparent)",
77
+ WebkitMaskImage:
78
+ "linear-gradient(to bottom, transparent, black 10px, black calc(100% - 10px), transparent)",
79
+ maskSize: "80% 100%",
80
+ }}
74
81
  data-role="chat-messages"
75
82
  >
76
83
  {isLoadingHistory ? (
@@ -94,7 +101,8 @@ const ChatMessages: React.FC<ChatMessagesProps> = ({
94
101
  const historyId = conversation.historyId || "";
95
102
  const lastHistoryId = conversations[index - 1]?.historyId || "";
96
103
  let addDivider =
97
- index > 0 && historyId !== lastHistoryId || conversation.system?.level === "newConversation";
104
+ (index > 0 && historyId !== lastHistoryId) ||
105
+ conversation.system?.level === "newConversation";
98
106
 
99
107
  return (
100
108
  <div key={conversation.taskId} className="flex flex-col gap-4">
@@ -148,4 +156,4 @@ const ChatMessages: React.FC<ChatMessagesProps> = ({
148
156
  );
149
157
  };
150
158
 
151
- export default ChatMessages;
159
+ export default ChatMessages;
@@ -1,3 +1,4 @@
1
+ import { Button } from "@/components/ui/button";
1
2
  import { getText } from "../i18n";
2
3
 
3
4
  const ChatRecommends: React.FC<{
@@ -5,31 +6,28 @@ const ChatRecommends: React.FC<{
5
6
  data?: string[];
6
7
  onSend: (prompt: string) => void;
7
8
  disabled?: boolean;
8
- }> = ({ hidden, data = getText().defaultRecommendedQuestions, onSend, disabled }) => {
9
+ }> = ({
10
+ hidden,
11
+ data = getText().defaultRecommendedQuestions,
12
+ onSend,
13
+ disabled,
14
+ }) => {
9
15
  if (hidden || !data || data.length === 0) return null;
10
16
  return (
11
17
  <div className="flex flex-wrap gap-2 pt-2 px-4">
12
18
  {data.map((prompt, index) => (
13
- <button
14
- type="button"
19
+ <Button
15
20
  key={prompt}
21
+ variant="outline"
16
22
  onClick={() => onSend(prompt)}
17
23
  disabled={disabled}
18
24
  className="
19
- text-xs px-2 py-1.5
20
- bg-[#F3F4F6] hover:bg-[#E5E7EB]
21
- text-[#374151] hover:text-[#111827]
22
- rounded-full
23
- border border-[#D1D5DB]
24
- transition-all duration-200
25
- cursor-pointer
26
- animate-in fade-in-0 slide-in-from-bottom-1
27
- text-nowrap
28
- "
25
+ text-xs px-2 py-1 h-auto rounded-full cursor-pointer text-nowrap
26
+ transition-all duration-200 animate-in fade-in-0 slide-in-from-bottom-1"
29
27
  style={{ animationDelay: `${index * 50}ms` }}
30
28
  >
31
29
  {prompt}
32
- </button>
30
+ </Button>
33
31
  ))}
34
32
  </div>
35
33
  );
@@ -12,7 +12,7 @@ const ChatUserMessage: React.FC<{
12
12
  className={`
13
13
  px-4 py-2.5 rounded-2xl
14
14
  transition-all duration-200 min-w-0 overflow-hidden max-w-full
15
- bg-[#E0E7FF] text-[#1E1B4B] rounded-br-md
15
+ bg-primary/10 text-foreground rounded-br-md
16
16
  `}
17
17
  >
18
18
  <div className="text-sm leading-relaxed whitespace-pre-wrap break-words">
@@ -29,7 +29,7 @@ export const UIRenderer: React.FC<UIRendererProps> = ({ spec, className }) => {
29
29
  return (
30
30
  <Suspense
31
31
  fallback={
32
- <Skeleton className={cn("w-full h-[120px] bg-gray-200 flex items-center justify-center gap-2", className)}>
32
+ <Skeleton className={cn("w-full h-[120px] bg-primary/20 flex items-center justify-center gap-2", className)}>
33
33
  <LoaderCircle className="size-4 animate-spin" />
34
34
  <span>{getText().loading}...</span>
35
35
  </Skeleton>
@@ -29,7 +29,7 @@ const VoiceInputButton: React.FC<{
29
29
  onClick={stoppable ? stop : status === "idle" ? start : undefined}
30
30
  disabled={finalDisabled}
31
31
  className={cn("h-8 w-8 rounded-lg cursor-pointer text-xs ", {
32
- "bg-gradient-to-r from-blue-500 to-blue-800 hover:from-blue-400 hover:to-blue-600 text-white animate-pulse":
32
+ "bg-gradient-to-r from-primary to-primary/80 hover:from-primary/90 hover:to-primary/70 text-primary-foreground animate-pulse":
33
33
  running,
34
34
  "w-auto": statusText,
35
35
  })}
@@ -8,10 +8,7 @@ type Status =
8
8
  | "idle"
9
9
  | "starting"
10
10
  | "ready"
11
- | "speaking"
12
- | "recording"
13
11
  | "stopping"
14
- | "ended"
15
12
  | "error"
16
13
  | "closed";
17
14
 
@@ -30,10 +27,10 @@ export const useVoiceInput = ({
30
27
  const AsrClientRef = useRef<ASRClient | null>(null);
31
28
  const runningRef = useRef(false);
32
29
  const stoppable = useMemo(() => {
33
- return ["ready", "speaking", "recording"].includes(status);
30
+ return ["ready"].includes(status);
34
31
  }, [status]);
35
32
  const disabledClick = useMemo(() => {
36
- return ["starting", "ended", "closed", "error", "stopping"].includes(
33
+ return ["starting", "stopping", "closed", "error"].includes(
37
34
  status,
38
35
  );
39
36
  }, [status]);
@@ -53,13 +50,6 @@ export const useVoiceInput = ({
53
50
  onReady() {
54
51
  setStatus("ready");
55
52
  },
56
- onSpeechStart() {
57
- setStatus((status) => (status !== "stopping" ? "recording" : status));
58
- },
59
-
60
- onSpeechEnd() {
61
- setStatus((status) => (status !== "stopping" ? "recording" : status));
62
- },
63
53
  onTranscript(text, isFinal) {
64
54
  if (!isFinal) {
65
55
  temp = text;
@@ -70,10 +60,21 @@ export const useVoiceInput = ({
70
60
  onChange(result);
71
61
  }
72
62
  },
73
- onSessionFinished() {
74
- setStatus("ended");
63
+ onAudioBufferCommitted() {
64
+ console.debug("音频缓冲区已提交");
75
65
  },
76
- onError() {
66
+ onError(error) {
67
+ if (error.message === "NO_DEVICES_AVAILABLE") {
68
+ toast({
69
+ title: getText().voiceInputError.microphoneAccessDenied,
70
+ variant: "destructive",
71
+ });
72
+ } else {
73
+ toast({
74
+ title: getText().voiceInputError.unknownError,
75
+ variant: "destructive",
76
+ });
77
+ }
77
78
  reset();
78
79
  },
79
80
  onClose() {
@@ -89,7 +90,7 @@ export const useVoiceInput = ({
89
90
  AsrClientRef.current = asrClient;
90
91
  } catch (error) {
91
92
  const message = error.message;
92
- const showError = (title: string) => toast({title})
93
+ const showError = (title: string) => toast({ title });
93
94
  if (message.includes("Microphone access denied")) {
94
95
  showError(getText().voiceInputError.microphoneAccessDenied);
95
96
  } else if (message.includes("No speech detected")) {
@@ -147,15 +148,12 @@ export const useVoiceInput = ({
147
148
  }
148
149
  }, [status]);
149
150
 
150
- const statusTextMap = {
151
+ const statusTextMap: Record<Status, string> = {
151
152
  // idle: t('translation:voiceInputStatus.idle'),
152
153
  idle: "",
153
154
  starting: getText().voiceInputStatus.starting,
154
155
  ready: getText().voiceInputStatus.ready,
155
- speaking: getText().voiceInputStatus.speaking,
156
- recording: getText().voiceInputStatus.recording,
157
156
  stopping: getText().voiceInputStatus.stopping,
158
- ended: getText().voiceInputStatus.ended,
159
157
  error: getText().voiceInputStatus.error,
160
158
  closed: getText().voiceInputStatus.closed,
161
159
  };
@@ -45,7 +45,7 @@ const InlineAIAssistant: React.FC<InlineAIAssistantProps> = ({
45
45
  return (
46
46
  <div
47
47
  className={cn(
48
- "w-full h-full max-h-screen relative flex flex-col justify-center overflow-hidden max-w-[1000px] mx-auto",
48
+ "w-full h-full max-h-screen relative flex flex-col justify-center overflow-hidden max-w-6xl mx-auto",
49
49
  className,
50
50
  )}
51
51
  style={style}
@@ -0,0 +1,3 @@
1
+ {
2
+ "targetDir": "src/pages/ai-assistant"
3
+ }
@@ -0,0 +1,94 @@
1
+ {
2
+ "name": "taro-project",
3
+ "version": "1.6.0",
4
+ "description": "开箱即用的基于Taro + React + Zustand + TailwindCSS + TypeScript的模板",
5
+ "author": "amaster.ai",
6
+ "license": "MIT",
7
+ "templateInfo": {
8
+ "name": "default",
9
+ "typescript": true,
10
+ "css": "sass"
11
+ },
12
+ "scripts": {
13
+ "dev": "bun run build:h5 -- --watch",
14
+ "build:weapp": "taro build --type weapp",
15
+ "build:swan": "taro build --type swan",
16
+ "build:alipay": "taro build --type alipay",
17
+ "build:tt": "taro build --type tt",
18
+ "build:h5": "taro build --type h5",
19
+ "build:rn": "taro build --type rn",
20
+ "build:qq": "taro build --type qq",
21
+ "build:jd": "taro build --type jd",
22
+ "build:quickapp": "taro build --type quickapp",
23
+ "lint": "biome check --write .",
24
+ "lint:check": "biome check .",
25
+ "lint:fix": "biome check --write --unsafe .",
26
+ "lint:format": "prettier --write 'src/**/*.{ts,tsx,js,jsx,json,css,scss,md}'",
27
+ "type-check": "tsc --noEmit",
28
+ "check:build": "node scripts/check-build.mjs",
29
+ "precommit": "bun run lint:check && bun run type-check",
30
+ "prepare": "husky || true",
31
+ "postinstall": "weapp-tw patch || true",
32
+ "patch": "weapp-tw patch"
33
+ },
34
+ "browserslist": [
35
+ "last 5 years",
36
+ "Android >= 9",
37
+ "iOS >= 13",
38
+ "not dead"
39
+ ],
40
+ "dependencies": {
41
+ "@a2a-js/sdk": "^0.3.7",
42
+ "@amaster.ai/bpm-ui": "1.1.0-beta.57",
43
+ "@amaster.ai/client": "1.1.0-beta.57",
44
+ "@amaster.ai/taro-echarts-ui": "1.1.0-beta.57",
45
+ "@amaster.ai/vite-plugins": "1.1.0-beta.57",
46
+ "@babel/runtime": "^7.28.3",
47
+ "@tarojs/components": "4.1.5",
48
+ "@tarojs/helper": "4.1.5",
49
+ "@tarojs/plugin-framework-react": "4.1.5",
50
+ "@tarojs/plugin-generator": "4.1.5",
51
+ "@tarojs/plugin-html": "4.1.5",
52
+ "@tarojs/plugin-http": "4.1.5",
53
+ "@tarojs/plugin-platform-h5": "4.1.5",
54
+ "@tarojs/plugin-platform-weapp": "4.1.5",
55
+ "@tarojs/react": "4.1.5",
56
+ "@tarojs/runtime": "4.1.5",
57
+ "@tarojs/shared": "4.1.5",
58
+ "@tarojs/taro": "4.1.5",
59
+ "immer": "^10.1.1",
60
+ "markdown-it": "^14.1.1",
61
+ "react": "^18.3.1",
62
+ "react-dom": "^18.3.1",
63
+ "zustand": "^5.0.8"
64
+ },
65
+ "devDependencies": {
66
+ "@babel/core": "^7.28.3",
67
+ "@babel/preset-react": "^7.24.1",
68
+ "@biomejs/biome": "^2.2.3",
69
+ "@egoist/tailwindcss-icons": "^1.9.0",
70
+ "@iconify-json/lucide": "^1.2.64",
71
+ "@iconify-json/mdi": "^1.2.3",
72
+ "@tarojs/cli": "4.1.5",
73
+ "@tarojs/taro-loader": "4.1.5",
74
+ "@tarojs/vite-runner": "4.1.5",
75
+ "@types/node": "^24.3.0",
76
+ "@types/react": "^18.3.24",
77
+ "@typescript/native-preview": "7.0.0-dev.20250827.1",
78
+ "@vitejs/plugin-react": "^4.7.0",
79
+ "babel-preset-taro": "4.1.5",
80
+ "husky": "^9.1.7",
81
+ "postcss": "^8.5.6",
82
+ "prettier": "^3.8.1",
83
+ "react-refresh": "^0.14.0",
84
+ "tailwindcss": "^3.4.17",
85
+ "ts-node": "^10.9.2",
86
+ "typescript": "^5.9.2",
87
+ "vite": "^4.5.14",
88
+ "weapp-tailwindcss": "^4.2.6"
89
+ },
90
+ "optionalDependencies": {
91
+ "@tarojs/binding-linux-arm64-gnu": "^4.1.10",
92
+ "@tarojs/binding-linux-x64-gnu": "4.1.5"
93
+ }
94
+ }