@huyooo/ai-chat-frontend-react 0.2.13 → 0.2.14
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 +99 -84
- package/dist/KaTeX_AMS-Regular-CYEKBG2K.woff +0 -0
- package/dist/KaTeX_AMS-Regular-JKX5W2C4.ttf +0 -0
- package/dist/KaTeX_AMS-Regular-U6PRYMIZ.woff2 +0 -0
- package/dist/KaTeX_Caligraphic-Bold-5QL5CMTE.woff2 +0 -0
- package/dist/KaTeX_Caligraphic-Bold-WZ3QSGD3.woff +0 -0
- package/dist/KaTeX_Caligraphic-Bold-ZTS3R3HK.ttf +0 -0
- package/dist/KaTeX_Caligraphic-Regular-3LKEU76G.woff +0 -0
- package/dist/KaTeX_Caligraphic-Regular-A7XRTZ5Q.ttf +0 -0
- package/dist/KaTeX_Caligraphic-Regular-KX5MEWCF.woff2 +0 -0
- package/dist/KaTeX_Fraktur-Bold-2QVFK6NQ.woff2 +0 -0
- package/dist/KaTeX_Fraktur-Bold-T4SWXBMT.woff +0 -0
- package/dist/KaTeX_Fraktur-Bold-WGHVTYOR.ttf +0 -0
- package/dist/KaTeX_Fraktur-Regular-2PEIFJSJ.woff2 +0 -0
- package/dist/KaTeX_Fraktur-Regular-5U4OPH2X.ttf +0 -0
- package/dist/KaTeX_Fraktur-Regular-PQMHCIK6.woff +0 -0
- package/dist/KaTeX_Main-Bold-2GA4IZIN.woff +0 -0
- package/dist/KaTeX_Main-Bold-W5FBVCZM.ttf +0 -0
- package/dist/KaTeX_Main-Bold-YP5VVQRP.woff2 +0 -0
- package/dist/KaTeX_Main-BoldItalic-4P4C7HJH.woff +0 -0
- package/dist/KaTeX_Main-BoldItalic-N4V3DX7S.woff2 +0 -0
- package/dist/KaTeX_Main-BoldItalic-ODMLBJJQ.ttf +0 -0
- package/dist/KaTeX_Main-Italic-I43T2HSR.ttf +0 -0
- package/dist/KaTeX_Main-Italic-RELBIK7M.woff2 +0 -0
- package/dist/KaTeX_Main-Italic-SASNQFN2.woff +0 -0
- package/dist/KaTeX_Main-Regular-ARRPAO67.woff2 +0 -0
- package/dist/KaTeX_Main-Regular-P5I74A2A.woff +0 -0
- package/dist/KaTeX_Main-Regular-W74P5G27.ttf +0 -0
- package/dist/KaTeX_Math-BoldItalic-6EBV3DK5.woff +0 -0
- package/dist/KaTeX_Math-BoldItalic-K4WTGH3J.woff2 +0 -0
- package/dist/KaTeX_Math-BoldItalic-VB447A4D.ttf +0 -0
- package/dist/KaTeX_Math-Italic-6KGCHLFN.woff2 +0 -0
- package/dist/KaTeX_Math-Italic-KKK3USB2.woff +0 -0
- package/dist/KaTeX_Math-Italic-SON4MRCA.ttf +0 -0
- package/dist/KaTeX_SansSerif-Bold-RRNVJFFW.woff2 +0 -0
- package/dist/KaTeX_SansSerif-Bold-STQ6RXC7.ttf +0 -0
- package/dist/KaTeX_SansSerif-Bold-X5M5EMOD.woff +0 -0
- package/dist/KaTeX_SansSerif-Italic-HMPFTM52.woff2 +0 -0
- package/dist/KaTeX_SansSerif-Italic-PSN4QKYX.woff +0 -0
- package/dist/KaTeX_SansSerif-Italic-WTBAZBGY.ttf +0 -0
- package/dist/KaTeX_SansSerif-Regular-2TL3USAE.ttf +0 -0
- package/dist/KaTeX_SansSerif-Regular-OQCII6EP.woff +0 -0
- package/dist/KaTeX_SansSerif-Regular-XIQ62X4E.woff2 +0 -0
- package/dist/KaTeX_Script-Regular-72OLXYNA.ttf +0 -0
- package/dist/KaTeX_Script-Regular-A5IFOEBS.woff +0 -0
- package/dist/KaTeX_Script-Regular-APUWIHLP.woff2 +0 -0
- package/dist/KaTeX_Size1-Regular-4HRHTS65.woff +0 -0
- package/dist/KaTeX_Size1-Regular-5LRUTBFT.woff2 +0 -0
- package/dist/KaTeX_Size1-Regular-7K6AASVL.ttf +0 -0
- package/dist/KaTeX_Size2-Regular-222HN3GT.ttf +0 -0
- package/dist/KaTeX_Size2-Regular-K5ZHAIS6.woff +0 -0
- package/dist/KaTeX_Size2-Regular-LELKET5D.woff2 +0 -0
- package/dist/KaTeX_Size3-Regular-TLFPAHDE.woff +0 -0
- package/dist/KaTeX_Size3-Regular-UFCO6WCA.ttf +0 -0
- package/dist/KaTeX_Size3-Regular-WQRQ47UD.woff2 +0 -0
- package/dist/KaTeX_Size4-Regular-7PGNVPQK.ttf +0 -0
- package/dist/KaTeX_Size4-Regular-CDMV7U5C.woff2 +0 -0
- package/dist/KaTeX_Size4-Regular-PKMWZHNC.woff +0 -0
- package/dist/KaTeX_Typewriter-Regular-3F5K6SQ6.ttf +0 -0
- package/dist/KaTeX_Typewriter-Regular-MJMFSK64.woff +0 -0
- package/dist/KaTeX_Typewriter-Regular-VBYJ4NRC.woff2 +0 -0
- package/dist/index.css +2156 -603
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +126 -92
- package/dist/index.js +1599 -981
- package/dist/index.js.map +1 -1
- package/dist/style.css +130 -0
- package/package.json +3 -3
- package/src/components/ChatPanel.tsx +82 -19
- package/src/components/common/SettingsPanel.css +81 -0
- package/src/components/common/SettingsPanel.tsx +96 -1
- package/src/components/input/ChatInput.css +0 -1
- package/src/components/input/ChatInput.tsx +48 -26
- package/src/components/input/DropdownSelector.css +66 -0
- package/src/components/input/DropdownSelector.tsx +157 -19
- package/src/components/message/MessageBubble.css +5 -2
- package/src/components/message/MessageBubble.tsx +44 -35
- package/src/components/message/PartsRenderer.css +8 -0
- package/src/components/message/PartsRenderer.tsx +137 -83
- package/src/components/message/parts/CollapsibleCard.css +4 -2
- package/src/components/message/parts/CollapsibleCard.tsx +4 -1
- package/src/components/message/parts/ImagePart.css +0 -1
- package/src/components/message/parts/TextPart.css +574 -5
- package/src/components/message/parts/TextPart.tsx +201 -8
- package/src/components/message/parts/ToolCallPart.css +139 -115
- package/src/components/message/parts/ToolCallPart.tsx +138 -134
- package/src/components/message/parts/ToolResultPart.css +0 -1
- package/src/components/message/parts/index.ts +3 -1
- package/src/components/message/parts/visual-predicate.ts +43 -0
- package/src/components/message/parts/visual-render.ts +19 -0
- package/src/components/message/parts/visual.ts +12 -0
- package/src/context/RenderersContext.tsx +19 -25
- package/src/hooks/useChat.ts +567 -79
- package/src/hooks/useImageUpload.ts +104 -12
- package/src/index.ts +19 -16
- package/src/styles.css +130 -0
- package/src/types/index.ts +52 -68
- package/src/components/message/ContentRenderer.tsx +0 -63
- package/src/components/message/ToolResultRenderer.tsx +0 -21
- package/src/components/message/blocks/CodeBlock.tsx +0 -60
- package/src/components/message/blocks/TextBlock.tsx +0 -15
- package/src/components/message/blocks/blocks.css +0 -141
- package/src/components/message/blocks/index.ts +0 -6
- package/src/components/message/parts/ToolResultPart.tsx +0 -96
- package/src/components/message/tool-results/DefaultToolResult.tsx +0 -26
- package/src/components/message/tool-results/SearchResults.tsx +0 -69
- package/src/components/message/tool-results/WeatherCard.tsx +0 -63
- package/src/components/message/tool-results/index.ts +0 -7
- package/src/components/message/tool-results/tool-results.css +0 -181
package/README.md
CHANGED
|
@@ -39,6 +39,7 @@ function App() {
|
|
|
39
39
|
models={modelList}
|
|
40
40
|
hideHeader={false}
|
|
41
41
|
welcomeConfig={welcomeConfig}
|
|
42
|
+
partRenderers={partRenderers}
|
|
42
43
|
onClose={handleClose}
|
|
43
44
|
/>
|
|
44
45
|
```
|
|
@@ -55,8 +56,7 @@ function App() {
|
|
|
55
56
|
| `hideHeader` | `boolean` | `false` | 是否隐藏标题栏 |
|
|
56
57
|
| `welcomeConfig` | `Partial<WelcomeConfig>` | - | 欢迎页配置 |
|
|
57
58
|
| `stepsExpandedType` | `'open' \| 'close' \| 'auto'` | `'auto'` | 执行步骤展开模式 |
|
|
58
|
-
| `
|
|
59
|
-
| `blockRenderers` | `BlockRenderers` | `{}` | 自定义内容块渲染器 |
|
|
59
|
+
| `partRenderers` | `PartRenderers` | `{}` | 自定义 Part 类型渲染器 |
|
|
60
60
|
| `autoRunConfig` | `AutoRunConfig` | - | 自动运行配置 |
|
|
61
61
|
| `onClose` | `() => void` | - | 关闭回调 |
|
|
62
62
|
| `onToolComplete` | `(event: ToolCompleteEvent) => void` | - | 工具执行完成回调 |
|
|
@@ -197,26 +197,45 @@ const welcomeConfig = {
|
|
|
197
197
|
}
|
|
198
198
|
```
|
|
199
199
|
|
|
200
|
-
##
|
|
200
|
+
## 自定义 Part 渲染器(新架构)
|
|
201
201
|
|
|
202
|
-
|
|
202
|
+
新架构使用 `partRenderers` 为特定的 Part 类型注入自定义渲染组件。工具执行结果会直接生成对应类型的 Part(如 `weather`),前端根据 `part.type` 选择渲染组件。
|
|
203
|
+
|
|
204
|
+
### 工作原理
|
|
205
|
+
|
|
206
|
+
```
|
|
207
|
+
工具执行完成
|
|
208
|
+
↓
|
|
209
|
+
后端发送 tool_call_result { id, name, result, resultType: 'weather' }
|
|
210
|
+
↓
|
|
211
|
+
前端 useChat 处理:
|
|
212
|
+
1. 更新 tool_call 状态为 done
|
|
213
|
+
2. 根据 resultType 创建 { type: 'weather', ...result } Part
|
|
214
|
+
↓
|
|
215
|
+
PartsRenderer 渲染:
|
|
216
|
+
- 检查 partRenderers['weather']
|
|
217
|
+
- 找到 → 使用自定义 WeatherCard 渲染
|
|
218
|
+
- 没找到 → 显示 JSON fallback
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### 使用示例
|
|
203
222
|
|
|
204
223
|
```tsx
|
|
205
224
|
import { useMemo } from 'react'
|
|
206
|
-
import { ChatPanel,
|
|
225
|
+
import { ChatPanel, PartRenderers } from '@huyooo/ai-chat-frontend-react'
|
|
207
226
|
import { CustomWeatherCard } from './components/CustomWeatherCard'
|
|
208
227
|
|
|
209
228
|
function App() {
|
|
210
|
-
//
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
-
//
|
|
229
|
+
// Part 类型 -> 渲染组件映射
|
|
230
|
+
const partRenderers = useMemo<PartRenderers>(() => ({
|
|
231
|
+
weather: CustomWeatherCard, // weather 类型使用自定义卡片
|
|
232
|
+
// stock: CustomStockCard,
|
|
214
233
|
}), [])
|
|
215
234
|
|
|
216
235
|
return (
|
|
217
236
|
<ChatPanel
|
|
218
237
|
adapter={adapter}
|
|
219
|
-
|
|
238
|
+
partRenderers={partRenderers}
|
|
220
239
|
/>
|
|
221
240
|
)
|
|
222
241
|
}
|
|
@@ -224,85 +243,73 @@ function App() {
|
|
|
224
243
|
|
|
225
244
|
### 创建自定义渲染组件
|
|
226
245
|
|
|
246
|
+
自定义组件直接接收 Part 的所有字段作为 props:
|
|
247
|
+
|
|
227
248
|
```tsx
|
|
228
249
|
// CustomWeatherCard.tsx
|
|
229
|
-
import { FC
|
|
230
|
-
import type { ToolRendererProps, WeatherData } from '@huyooo/ai-chat-shared'
|
|
250
|
+
import { FC } from 'react'
|
|
231
251
|
import './CustomWeatherCard.css'
|
|
232
252
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
if (typeof toolResult === 'object' && toolResult !== null) {
|
|
236
|
-
return toolResult as WeatherData
|
|
237
|
-
}
|
|
238
|
-
return { city: '未知', temperature: 0, condition: '未知' }
|
|
239
|
-
}, [toolResult])
|
|
240
|
-
|
|
241
|
-
return (
|
|
242
|
-
<div className="weather-card">
|
|
243
|
-
<div className="city">{weather.city}</div>
|
|
244
|
-
<div className="temp">{weather.temperature}°C</div>
|
|
245
|
-
<div className="condition">{weather.condition}</div>
|
|
246
|
-
<div className="details">
|
|
247
|
-
{weather.humidity && <span>湿度 {weather.humidity}%</span>}
|
|
248
|
-
{weather.wind && <span>{weather.wind}</span>}
|
|
249
|
-
</div>
|
|
250
|
-
</div>
|
|
251
|
-
)
|
|
252
|
-
}
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
### ToolRendererProps 接口
|
|
256
|
-
|
|
257
|
-
```typescript
|
|
258
|
-
interface ToolRendererProps {
|
|
259
|
-
toolName: string // 工具名称
|
|
260
|
-
toolArgs: object // 工具调用参数
|
|
261
|
-
toolResult: unknown // 工具返回结果
|
|
262
|
-
status: 'running' | 'done' | 'error' // 执行状态
|
|
263
|
-
}
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
### 内置数据类型
|
|
267
|
-
|
|
268
|
-
```typescript
|
|
269
|
-
// 天气数据
|
|
270
|
-
interface WeatherData {
|
|
253
|
+
interface WeatherPartProps {
|
|
254
|
+
type: 'weather' // Part 类型
|
|
271
255
|
city: string
|
|
272
256
|
temperature: number
|
|
273
257
|
condition: string
|
|
274
258
|
humidity?: number
|
|
275
259
|
wind?: string
|
|
260
|
+
reportTime?: string
|
|
261
|
+
province?: string
|
|
276
262
|
}
|
|
277
263
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
264
|
+
export const CustomWeatherCard: FC<WeatherPartProps> = ({
|
|
265
|
+
city,
|
|
266
|
+
temperature,
|
|
267
|
+
condition,
|
|
268
|
+
humidity,
|
|
269
|
+
wind,
|
|
270
|
+
}) => {
|
|
271
|
+
return (
|
|
272
|
+
<div className="weather-card">
|
|
273
|
+
<div className="city">{city}</div>
|
|
274
|
+
<div className="temp">{temperature}°C</div>
|
|
275
|
+
<div className="condition">{condition}</div>
|
|
276
|
+
<div className="details">
|
|
277
|
+
{humidity && <span>湿度 {humidity}%</span>}
|
|
278
|
+
{wind && <span>{wind}</span>}
|
|
279
|
+
</div>
|
|
280
|
+
</div>
|
|
281
|
+
)
|
|
283
282
|
}
|
|
284
283
|
```
|
|
285
284
|
|
|
286
|
-
|
|
285
|
+
### 内置 Part 类型
|
|
287
286
|
|
|
288
|
-
|
|
287
|
+
| Part 类型 | 说明 | 内置渲染器 |
|
|
288
|
+
|-----------|------|-----------|
|
|
289
|
+
| `text` | 文本内容 | TextPart(支持 Markdown) |
|
|
290
|
+
| `thinking` | 思考过程 | ThinkingPart(可折叠卡片) |
|
|
291
|
+
| `search` | 搜索结果 | SearchPart |
|
|
292
|
+
| `tool_call` | 工具执行状态 | ToolCallPart(仅显示状态) |
|
|
293
|
+
| `image` | 图片 | ImagePart |
|
|
294
|
+
| `error` | 错误信息 | ErrorPart |
|
|
289
295
|
|
|
290
|
-
|
|
291
|
-
import { useMemo } from 'react'
|
|
292
|
-
import { ChatPanel, BlockRenderers } from '@huyooo/ai-chat-frontend-react'
|
|
293
|
-
import { CustomMathBlock } from './components/CustomMathBlock'
|
|
296
|
+
### 扩展 Part 类型
|
|
294
297
|
|
|
295
|
-
|
|
296
|
-
const blockRenderers = useMemo<BlockRenderers>(() => ({
|
|
297
|
-
math: CustomMathBlock,
|
|
298
|
-
}), [])
|
|
298
|
+
可以通过工具的 `resultType` 定义新的 Part 类型:
|
|
299
299
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
300
|
+
```typescript
|
|
301
|
+
// 后端工具定义
|
|
302
|
+
export function getWeatherTool(): ToolPlugin {
|
|
303
|
+
return tool({
|
|
304
|
+
name: 'get_weather',
|
|
305
|
+
description: '获取城市天气',
|
|
306
|
+
parameters: { city: { type: 'string' } },
|
|
307
|
+
resultType: 'weather', // ← 指定结果 Part 类型
|
|
308
|
+
execute: async (args, context) => {
|
|
309
|
+
// 返回值会自动转换为 { type: 'weather', ...result }
|
|
310
|
+
return { city: args.city, temperature: 25, condition: '晴' }
|
|
311
|
+
}
|
|
312
|
+
})
|
|
306
313
|
}
|
|
307
314
|
```
|
|
308
315
|
|
|
@@ -329,31 +336,39 @@ const {
|
|
|
329
336
|
// 主组件
|
|
330
337
|
export { ChatPanel, WelcomeMessage, ChatInput, ChatHeader, MessageBubble }
|
|
331
338
|
|
|
332
|
-
//
|
|
333
|
-
export {
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
339
|
+
// Part 渲染组件
|
|
340
|
+
export { PartsRenderer }
|
|
341
|
+
export {
|
|
342
|
+
TextPartComponent,
|
|
343
|
+
ThinkingPartComponent,
|
|
344
|
+
SearchPartComponent,
|
|
345
|
+
ToolCallPartComponent,
|
|
346
|
+
ImagePartComponent,
|
|
347
|
+
ErrorPartComponent,
|
|
348
|
+
}
|
|
337
349
|
|
|
338
350
|
// Context Provider
|
|
339
|
-
export {
|
|
351
|
+
export { PartRenderersProvider, PartRenderersContext }
|
|
340
352
|
|
|
341
353
|
// Hook
|
|
342
354
|
export { useChat }
|
|
343
355
|
|
|
344
|
-
// 类型
|
|
356
|
+
// 类型
|
|
345
357
|
export type {
|
|
346
358
|
WelcomeConfig,
|
|
347
359
|
WelcomeFeature,
|
|
348
360
|
WelcomeTask,
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
361
|
+
PartRenderers,
|
|
362
|
+
PartRendererProps,
|
|
363
|
+
ContentPart,
|
|
364
|
+
TextPart,
|
|
365
|
+
ThinkingPart,
|
|
366
|
+
SearchPart,
|
|
367
|
+
ToolCallPart,
|
|
368
|
+
ImagePart,
|
|
369
|
+
ErrorPart,
|
|
352
370
|
WeatherData,
|
|
353
371
|
SearchResultItem,
|
|
354
|
-
ContentBlock,
|
|
355
|
-
TextBlock,
|
|
356
|
-
CodeBlock
|
|
357
372
|
}
|
|
358
373
|
|
|
359
374
|
// 工具函数 (来自 @huyooo/ai-chat-shared)
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|