zen-ai-chat-ui 0.1.0-beta.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/LICENSE +21 -0
- package/README.md +137 -0
- package/dist/ai-chat-ui.css +1 -0
- package/dist/ai-chat-ui.es.js +952 -0
- package/dist/ai-chat-ui.umd.js +1 -0
- package/dist/components/ChatContainer/ChatContainer.d.ts +100 -0
- package/dist/components/ChatInput/ChatInput.d.ts +30 -0
- package/dist/components/MarkdownRenderer/MarkdownRenderer.d.ts +8 -0
- package/dist/components/MessageBubble/MessageBubble.d.ts +19 -0
- package/dist/components/MessageList/MessageList.d.ts +24 -0
- package/dist/components/ThinkingBlock/ThinkingBlock.d.ts +14 -0
- package/dist/components/WelcomeScreen/WelcomeScreen.d.ts +16 -0
- package/dist/composables/useMarkdown.d.ts +11 -0
- package/dist/composables/useStreaming.d.ts +12 -0
- package/dist/env.d.ts +8 -0
- package/dist/index.d.ts +16 -0
- package/dist/types/index.d.ts +88 -0
- package/dist/utils/format.d.ts +6 -0
- package/package.json +69 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 xzisme
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# zen-ai-chat-ui
|
|
2
|
+
|
|
3
|
+
一个精美的大模型对话 UI 组件库,基于 Vue 3 + TypeScript。支持流式输出、思考过程折叠、Markdown 渲染(Shiki 代码高亮)、附件上传、浅色/深色双主题。可发布到 NPM,供其他项目安装复用。
|
|
4
|
+
|
|
5
|
+
## 特性
|
|
6
|
+
|
|
7
|
+
- **流式输出**:逐字渲染 + 光标,支持 `content` / `reasoning` 双通道分片
|
|
8
|
+
- **思考过程**:独立的可折叠「思考中」区块,流式时展开 + 动画,完成后折叠
|
|
9
|
+
- **Markdown 渲染**:基于 markdown-it + Shiki,双主题代码高亮、表格、引用、任务列表,代码块带语言标签与一键复制
|
|
10
|
+
- **附件上传**:点击 / 拖拽,图片缩略图预览,文件卡片,可移除
|
|
11
|
+
- **开场白 + 预设问题**:首屏欢迎语 + 可点击的话题卡片
|
|
12
|
+
- **双主题**:浅色 / 深色 / 跟随系统,通过 CSS 变量驱动,可深度定制
|
|
13
|
+
- **样式自洽**:所有组件带 `acu-` 前缀,CSS 变量作用域隔离,不污染宿主
|
|
14
|
+
|
|
15
|
+
## 安装
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install zen-ai-chat-ui
|
|
19
|
+
# 或
|
|
20
|
+
pnpm add zen-ai-chat-ui
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
`vue` 为 peerDependency,需 >= 3.3。`markdown-it` 与 `shiki` 为 dependency,会自动安装。
|
|
24
|
+
|
|
25
|
+
## 快速开始
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
import { createApp } from 'vue'
|
|
29
|
+
import App from './App.vue'
|
|
30
|
+
import 'zen-ai-chat-ui/style.css'
|
|
31
|
+
|
|
32
|
+
createApp(App).mount('#app')
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
```vue
|
|
36
|
+
<template>
|
|
37
|
+
<ChatContainer
|
|
38
|
+
:messages="messages"
|
|
39
|
+
:preset-questions="questions"
|
|
40
|
+
theme="light"
|
|
41
|
+
@send="onSend"
|
|
42
|
+
/>
|
|
43
|
+
</template>
|
|
44
|
+
|
|
45
|
+
<script setup lang="ts">
|
|
46
|
+
import { ref } from 'vue'
|
|
47
|
+
import { ChatContainer, useStreaming, uid, type ChatMessage, type StreamChunk } from 'zen-ai-chat-ui'
|
|
48
|
+
|
|
49
|
+
const messages = ref<ChatMessage[]>([])
|
|
50
|
+
const streaming = useStreaming()
|
|
51
|
+
|
|
52
|
+
const questions = [
|
|
53
|
+
{ id: 'q1', label: '介绍一下你自己', prompt: '介绍一下你自己' }
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
async function onSend({ text, files }: { text: string; files: any[] }) {
|
|
57
|
+
messages.value.push({
|
|
58
|
+
id: uid('u'), role: 'user', content: text, status: 'done',
|
|
59
|
+
attachments: files.map(f => ({ id: f.id, name: f.file.name, size: f.file.size, type: f.file.type, preview: f.preview }))
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
const assistant = streaming.createAssistant()
|
|
63
|
+
messages.value.push(assistant)
|
|
64
|
+
|
|
65
|
+
// 调用大模型接口,逐块 append
|
|
66
|
+
for await (const chunk of callLLM(text)) {
|
|
67
|
+
streaming.append(assistant, chunk as StreamChunk)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
</script>
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## 流式输出
|
|
74
|
+
|
|
75
|
+
`useStreaming().append(message, chunk)` 按 `chunk.type` 分发:
|
|
76
|
+
|
|
77
|
+
| type | delta | 说明 |
|
|
78
|
+
| ----------- | ------------- | ------------------------ |
|
|
79
|
+
| `reasoning` | 思考增量文本 | 写入 `message.reasoning` |
|
|
80
|
+
| `content` | 正文增量文本 | 写入 `message.content` |
|
|
81
|
+
| `done` | - | 标记完成 |
|
|
82
|
+
| `error` | - | 标记错误 |
|
|
83
|
+
|
|
84
|
+
首个 `content` 到达时,`reasoning` 自动标记为完成。
|
|
85
|
+
|
|
86
|
+
## 组件 API
|
|
87
|
+
|
|
88
|
+
### `<ChatContainer>`
|
|
89
|
+
|
|
90
|
+
主组件,组合消息列表、开场白、输入框。
|
|
91
|
+
|
|
92
|
+
| Prop | 类型 | 默认值 | 说明 |
|
|
93
|
+
| ------------------- | -------------------------- | ---------- | --------------------- |
|
|
94
|
+
| `messages` | `ChatMessage[]` | - | 消息列表(必填) |
|
|
95
|
+
| `presetQuestions` | `PresetQuestion[]` | `[]` | 预设问题 |
|
|
96
|
+
| `welcomeTitle` | `string` | 见默认 | 开场白标题 |
|
|
97
|
+
| `welcomeDescription`| `string` | 见默认 | 开场白描述 |
|
|
98
|
+
| `assistantName` | `string` | `'AI 助手'`| 模型名称 |
|
|
99
|
+
| `assistantAvatar` | `string` | - | 模型头像 URL |
|
|
100
|
+
| `userAvatar` | `string` | - | 用户头像 URL |
|
|
101
|
+
| `theme` | `'light' \| 'dark' \| 'auto'` | `'light'` | 主题 |
|
|
102
|
+
| `disabled` | `boolean` | `false` | 禁用输入(生成中) |
|
|
103
|
+
| `uploadConfig` | `Partial<UploadConfig>` | `{}` | 附件上传配置 |
|
|
104
|
+
|
|
105
|
+
| Event | Payload | 说明 |
|
|
106
|
+
| --------- | -------------------------------------------- | -------------- |
|
|
107
|
+
| `send` | `{ text: string; files: SelectedFile[] }` | 用户发送 |
|
|
108
|
+
| `select` | `PresetQuestion` | 点击预设问题 |
|
|
109
|
+
| `retry` | `ChatMessage` | 重试失败消息 |
|
|
110
|
+
|
|
111
|
+
### 其他可独立使用的组件
|
|
112
|
+
|
|
113
|
+
`MessageList`、`MessageBubble`、`ThinkingBlock`、`WelcomeScreen`、`ChatInput`、`MarkdownRenderer` 均已导出,可单独使用。
|
|
114
|
+
|
|
115
|
+
## 主题定制
|
|
116
|
+
|
|
117
|
+
覆盖任意 CSS 变量即可换肤,变量定义于 `:root`,切换深色用 `[data-theme="dark"]`:
|
|
118
|
+
|
|
119
|
+
```css
|
|
120
|
+
:root {
|
|
121
|
+
--acu-primary: #10b981; /* 主色 */
|
|
122
|
+
--acu-bubble-user-bg: #10b981;/* 用户气泡背景 */
|
|
123
|
+
--acu-radius: 14px; /* 圆角 */
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## 本地开发
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
npm install
|
|
131
|
+
npm run dev # 启动调试(端口 7788)
|
|
132
|
+
npm run build # 构建组件库产物(dist/)
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## License
|
|
136
|
+
|
|
137
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:root,[data-theme=light]{color-scheme:light;--acu-bg: #ffffff;--acu-surface: #f7f7f8;--acu-surface-2: #ededf0;--acu-surface-hover: #f0f0f3;--acu-text: #18181b;--acu-text-secondary: #52525b;--acu-text-muted: #a1a1aa;--acu-border: #e7e7ea;--acu-border-strong: #d4d4d8;--acu-primary: #6366f1;--acu-primary-hover: #5457e5;--acu-primary-active: #4f46e5;--acu-primary-contrast: #ffffff;--acu-primary-soft: rgba(99, 102, 241, .09);--acu-primary-soft-hover: rgba(99, 102, 241, .14);--acu-bubble-user-bg: #6366f1;--acu-bubble-user-text: #ffffff;--acu-bubble-assistant-bg: #f7f7f8;--acu-bubble-assistant-text: #18181b;--acu-thinking-bg: #fafafa;--acu-thinking-text: #71717a;--acu-thinking-border: #ececef;--acu-thinking-icon: #a1a1aa;--acu-code-bg: #f6f8fa;--acu-code-text: #24292f;--acu-code-border: #e4e4e7;--acu-code-inline-bg: rgba(175, 184, 193, .2);--acu-code-header-bg: #eceef1;--acu-error: #ef4444;--acu-error-soft: rgba(239, 68, 68, .1);--acu-success: #10b981;--acu-warning: #f59e0b;--acu-shadow-sm: 0 1px 2px rgba(24, 24, 27, .05);--acu-shadow: 0 4px 16px rgba(24, 24, 27, .08);--acu-shadow-lg: 0 12px 32px rgba(24, 24, 27, .12);--acu-radius-xs: 4px;--acu-radius-sm: 8px;--acu-radius: 12px;--acu-radius-lg: 16px;--acu-radius-xl: 20px;--acu-radius-full: 9999px;--acu-space-1: 4px;--acu-space-2: 8px;--acu-space-3: 12px;--acu-space-4: 16px;--acu-space-5: 20px;--acu-space-6: 24px;--acu-space-8: 32px;--acu-font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;--acu-font-mono: "SFMono-Regular", "JetBrains Mono", Menlo, Consolas, "Liberation Mono", monospace;--acu-font-size-xs: 12px;--acu-font-size-sm: 13px;--acu-font-size-base: 14px;--acu-font-size-md: 15px;--acu-font-size-lg: 16px;--acu-font-size-xl: 18px;--acu-line-height: 1.65;--acu-duration-fast: .12s;--acu-duration: .2s;--acu-easing: cubic-bezier(.4, 0, .2, 1);--acu-max-width: 768px;--acu-avatar-size: 32px}[data-theme=dark]{color-scheme:dark;--acu-bg: #18181b;--acu-surface: #27272a;--acu-surface-2: #34343a;--acu-surface-hover: #2f2f35;--acu-text: #f4f4f5;--acu-text-secondary: #a1a1aa;--acu-text-muted: #71717a;--acu-border: #323236;--acu-border-strong: #52525b;--acu-primary: #818cf8;--acu-primary-hover: #6366f1;--acu-primary-active: #5457e5;--acu-primary-contrast: #18181b;--acu-primary-soft: rgba(129, 140, 248, .14);--acu-primary-soft-hover: rgba(129, 140, 248, .22);--acu-bubble-user-bg: #6366f1;--acu-bubble-user-text: #ffffff;--acu-bubble-assistant-bg: #27272a;--acu-bubble-assistant-text: #f4f4f5;--acu-thinking-bg: #1f1f23;--acu-thinking-text: #a1a1aa;--acu-thinking-border: #2e2e33;--acu-thinking-icon: #71717a;--acu-code-bg: #0d1117;--acu-code-text: #e6edf3;--acu-code-border: #30363d;--acu-code-inline-bg: rgba(110, 118, 129, .4);--acu-code-header-bg: #161b22;--acu-error: #f87171;--acu-error-soft: rgba(248, 113, 113, .14);--acu-success: #34d399;--acu-warning: #fbbf24;--acu-shadow-sm: 0 1px 2px rgba(0, 0, 0, .3);--acu-shadow: 0 4px 16px rgba(0, 0, 0, .4);--acu-shadow-lg: 0 12px 32px rgba(0, 0, 0, .5)}.acu-root,.acu-root *,.acu-root *:before,.acu-root *:after{box-sizing:border-box}.acu-root{font-family:var(--acu-font-sans);font-size:var(--acu-font-size-base);line-height:var(--acu-line-height);color:var(--acu-text);background:var(--acu-bg);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-rendering:optimizeLegibility}.acu-root a{color:var(--acu-primary);text-decoration:none}.acu-root a:hover{text-decoration:underline}.acu-transition{transition:all var(--acu-duration) var(--acu-easing)}.acu-cursor{display:inline-block;width:7px;height:1.05em;margin-left:2px;vertical-align:text-bottom;background:var(--acu-primary);border-radius:1px;animation:acu-blink 1s steps(2,start) infinite}@keyframes acu-blink{to{opacity:0}}.acu-typing-dots{display:inline-flex;align-items:center;gap:4px}.acu-typing-dots span{width:6px;height:6px;border-radius:50%;background:var(--acu-thinking-icon);animation:acu-bounce 1.4s infinite ease-in-out both}.acu-typing-dots span:nth-child(1){animation-delay:-.32s}.acu-typing-dots span:nth-child(2){animation-delay:-.16s}@keyframes acu-bounce{0%,80%,to{transform:scale(.6);opacity:.5}40%{transform:scale(1);opacity:1}}@media (prefers-reduced-motion: reduce){.acu-root *{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}.acu-md{font-size:var(--acu-font-size-md);line-height:var(--acu-line-height);color:var(--acu-bubble-assistant-text);word-wrap:break-word;overflow-wrap:anywhere}.acu-md>*:first-child{margin-top:0}.acu-md>*:last-child{margin-bottom:0}.acu-md p{margin:0 0 var(--acu-space-3)}.acu-md h1,.acu-md h2,.acu-md h3,.acu-md h4,.acu-md h5,.acu-md h6{margin:var(--acu-space-6) 0 var(--acu-space-3);font-weight:650;line-height:1.3}.acu-md h1{font-size:1.5em}.acu-md h2{font-size:1.32em}.acu-md h3{font-size:1.18em}.acu-md h4{font-size:1.06em}.acu-md ul,.acu-md ol{margin:0 0 var(--acu-space-3);padding-left:1.5em}.acu-md li{margin:var(--acu-space-1) 0}.acu-md li::marker{color:var(--acu-text-muted)}.acu-md ul ul,.acu-md ol ol,.acu-md ul ol,.acu-md ol ul{margin:var(--acu-space-1) 0}.acu-md li.task-list-item{list-style:none;margin-left:-1.4em}.acu-md a{color:var(--acu-primary);text-decoration:none;border-bottom:1px solid var(--acu-primary-soft);transition:border-color var(--acu-duration) var(--acu-easing)}.acu-md a:hover{border-bottom-color:var(--acu-primary)}.acu-md strong{font-weight:650}.acu-md em{font-style:italic}.acu-md del{color:var(--acu-text-muted)}.acu-md hr{margin:var(--acu-space-5) 0;border:none;border-top:1px solid var(--acu-border)}.acu-md blockquote{margin:0 0 var(--acu-space-3);padding:var(--acu-space-1) var(--acu-space-4);border-left:3px solid var(--acu-primary);background:var(--acu-primary-soft);border-radius:0 var(--acu-radius-sm) var(--acu-radius-sm) 0;color:var(--acu-text-secondary)}.acu-md blockquote>*:last-child{margin-bottom:0}.acu-md code:not(pre code){padding:.15em .4em;margin:0 .1em;font-family:var(--acu-font-mono);font-size:.88em;background:var(--acu-code-inline-bg);color:var(--acu-text);border-radius:var(--acu-radius-xs)}.acu-md table{width:100%;margin:0 0 var(--acu-space-3);border-collapse:collapse;font-size:.95em;overflow:hidden;border-radius:var(--acu-radius-sm);display:block;overflow-x:auto;scrollbar-width:thin;scrollbar-color:var(--acu-border-strong) transparent}.acu-md table::-webkit-scrollbar{width:6px;height:6px}.acu-md table::-webkit-scrollbar-track{background:transparent}.acu-md table::-webkit-scrollbar-thumb{background-color:var(--acu-border-strong);border-radius:3px}.acu-md table::-webkit-scrollbar-thumb:hover{background-color:var(--acu-text-muted)}.acu-md th,.acu-md td{padding:var(--acu-space-2) var(--acu-space-3);border:1px solid var(--acu-border);text-align:left}.acu-md th{background:var(--acu-surface);font-weight:600}.acu-md tbody tr:nth-child(2n){background:var(--acu-surface)}.acu-md img.acu-md-img{max-width:100%;border-radius:var(--acu-radius-sm);vertical-align:middle}.acu-md .acu-code-block{margin:0 0 var(--acu-space-3);border:1px solid var(--acu-code-border);border-radius:var(--acu-radius);overflow:hidden;background:var(--acu-code-bg)}.acu-md .acu-code-header{display:flex;align-items:center;justify-content:space-between;padding:0 var(--acu-space-3);height:34px;background:var(--acu-code-header-bg);border-bottom:1px solid var(--acu-code-border)}.acu-md .acu-code-lang{font-family:var(--acu-font-mono);font-size:var(--acu-font-size-xs);color:var(--acu-text-muted);text-transform:lowercase;letter-spacing:.02em}.acu-md .acu-code-copy{display:inline-flex;align-items:center;gap:4px;padding:3px 8px;border:none;background:transparent;color:var(--acu-text-muted);font-size:var(--acu-font-size-xs);font-family:inherit;border-radius:var(--acu-radius-xs);cursor:pointer;transition:all var(--acu-duration-fast) var(--acu-easing)}.acu-md .acu-code-copy svg{display:block}.acu-md .acu-code-copy:hover{background:var(--acu-surface-2);color:var(--acu-text)}.acu-md .acu-code-copy.is-copied{color:var(--acu-success)}.acu-md .acu-code-copy.is-error{color:var(--acu-error)}.acu-md .shiki{margin:0;padding:var(--acu-space-4);background:var(--acu-code-bg)!important;font-family:var(--acu-font-mono);font-size:var(--acu-font-size-sm);line-height:1.6;overflow-x:auto;scrollbar-width:thin;scrollbar-color:var(--acu-border-strong) transparent}.acu-md .shiki::-webkit-scrollbar{width:8px;height:8px}.acu-md .shiki::-webkit-scrollbar-track{background:transparent}.acu-md .shiki::-webkit-scrollbar-thumb{background-color:var(--acu-border-strong);border-radius:4px}.acu-md .shiki::-webkit-scrollbar-thumb:hover{background-color:var(--acu-text-muted)}.acu-md .shiki code{font-family:inherit;background:none;padding:0}.acu-md .shiki,.acu-md .shiki span{color:var(--shiki-light, inherit);font-style:var(--shiki-light-font-style, normal);font-weight:var(--shiki-light-font-weight, normal);text-decoration:var(--shiki-light-text-decoration, none)}[data-theme=dark] .acu-md .shiki,[data-theme=dark] .acu-md .shiki span{color:var(--shiki-dark, inherit);font-style:var(--shiki-dark-font-style, normal);font-weight:var(--shiki-dark-font-weight, normal);text-decoration:var(--shiki-dark-text-decoration, none)}.acu-md .acu-code-fallback{color:var(--acu-code-text)}.acu-thinking[data-v-7249f847]{margin-bottom:var(--acu-space-3);border:1px solid var(--acu-thinking-border);border-radius:var(--acu-radius);background:var(--acu-thinking-bg);overflow:hidden}.acu-thinking.is-streaming[data-v-7249f847]{border-color:var(--acu-primary-soft)}.acu-thinking-header[data-v-7249f847]{display:flex;align-items:center;gap:var(--acu-space-2);width:100%;padding:var(--acu-space-2) var(--acu-space-3);border:none;background:transparent;color:var(--acu-thinking-text);font-size:var(--acu-font-size-sm);font-family:inherit;cursor:pointer;transition:background-color var(--acu-duration-fast) var(--acu-easing);outline:none}.acu-thinking-header[data-v-7249f847]:focus-visible{box-shadow:0 0 0 2px var(--acu-bg),0 0 0 4px var(--acu-primary)}.acu-thinking-header[data-v-7249f847]:hover{background:var(--acu-surface-hover)}.acu-thinking-icon[data-v-7249f847]{display:inline-flex;color:var(--acu-thinking-icon);flex-shrink:0}.is-streaming .acu-thinking-icon[data-v-7249f847]{color:var(--acu-primary);animation:acu-pulse-7249f847 2s var(--acu-easing) infinite}@keyframes acu-pulse-7249f847{0%,to{opacity:.55}50%{opacity:1}}.acu-thinking-title[data-v-7249f847]{font-weight:500;letter-spacing:.01em}.acu-thinking-chevron[data-v-7249f847]{margin-left:auto;color:var(--acu-text-muted);transition:transform var(--acu-duration) var(--acu-easing);flex-shrink:0}.acu-thinking-chevron.is-open[data-v-7249f847]{transform:rotate(180deg)}.acu-thinking-body[data-v-7249f847]{padding:0 var(--acu-space-3) var(--acu-space-3);border-top:1px dashed var(--acu-thinking-border);color:var(--acu-thinking-text);font-size:var(--acu-font-size-sm);line-height:1.7}.acu-thinking-body[data-v-7249f847] .acu-md{font-size:var(--acu-font-size-sm);color:var(--acu-thinking-text);opacity:.92}.acu-thinking-body[data-v-7249f847] .acu-md p{margin-bottom:var(--acu-space-2)}.acu-collapse-enter-active[data-v-7249f847],.acu-collapse-leave-active[data-v-7249f847]{transition:opacity var(--acu-duration) var(--acu-easing),transform var(--acu-duration) var(--acu-easing)}.acu-collapse-enter-from[data-v-7249f847],.acu-collapse-leave-to[data-v-7249f847]{opacity:0;transform:translateY(-4px)}.acu-bubble-row[data-v-49f051a5]{display:flex;gap:var(--acu-space-3);align-items:flex-start}.acu-bubble-row.is-user[data-v-49f051a5]{justify-content:flex-end}.acu-avatar[data-v-49f051a5]{flex-shrink:0;width:var(--acu-avatar-size);height:var(--acu-avatar-size);border-radius:var(--acu-radius-full);display:inline-flex;align-items:center;justify-content:center;overflow:hidden}.acu-avatar img[data-v-49f051a5]{width:100%;height:100%;object-fit:cover}.acu-avatar--left[data-v-49f051a5]{background:var(--acu-surface-2);color:var(--acu-text-secondary)}.acu-avatar--right[data-v-49f051a5]{background:var(--acu-primary-soft);color:var(--acu-primary)}.acu-bubble-main[data-v-49f051a5]{min-width:0;max-width:min(680px,78%);display:flex;flex-direction:column}.is-user .acu-bubble-main[data-v-49f051a5]{align-items:flex-end}.acu-bubble-name[data-v-49f051a5]{font-size:var(--acu-font-size-xs);color:var(--acu-text-muted);margin-bottom:var(--acu-space-1);padding-left:2px}.acu-bubble[data-v-49f051a5]{position:relative;padding:var(--acu-space-3) var(--acu-space-4);border-radius:var(--acu-radius-lg);font-size:var(--acu-font-size-md);line-height:var(--acu-line-height);max-width:100%;word-break:break-word}.acu-bubble.is-assistant[data-v-49f051a5]{background:var(--acu-bubble-assistant-bg);color:var(--acu-bubble-assistant-text);border-top-left-radius:var(--acu-radius-xs)}.acu-bubble.is-user[data-v-49f051a5]{background:var(--acu-bubble-user-bg);color:var(--acu-bubble-user-text);border-top-right-radius:var(--acu-radius-xs)}.acu-bubble-content[data-v-49f051a5] .acu-md{color:inherit;font-size:var(--acu-font-size-md)}.acu-attachments[data-v-49f051a5]{display:flex;flex-wrap:wrap;gap:var(--acu-space-2);margin-bottom:var(--acu-space-2)}.acu-attachments.is-user[data-v-49f051a5]{justify-content:flex-end}.acu-att-thumb[data-v-49f051a5]{width:88px;height:88px;border-radius:var(--acu-radius);overflow:hidden;border:1px solid var(--acu-border);background:var(--acu-surface)}.acu-att-thumb img[data-v-49f051a5]{width:100%;height:100%;object-fit:cover}.acu-att-file[data-v-49f051a5]{display:inline-flex;align-items:center;gap:var(--acu-space-2);padding:var(--acu-space-2) var(--acu-space-3);background:var(--acu-surface);border:1px solid var(--acu-border);border-radius:var(--acu-radius-sm);max-width:220px}.acu-att-file-icon[data-v-49f051a5]{color:var(--acu-text-muted);flex-shrink:0}.acu-att-file-info[data-v-49f051a5]{display:flex;flex-direction:column;min-width:0}.acu-att-file-name[data-v-49f051a5]{font-size:var(--acu-font-size-sm);color:var(--acu-text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.acu-att-file-size[data-v-49f051a5]{font-size:var(--acu-font-size-xs);color:var(--acu-text-muted)}.acu-pending[data-v-49f051a5]{padding:var(--acu-space-1) 0}.acu-bubble-error[data-v-49f051a5]{display:flex;align-items:center;gap:var(--acu-space-2);margin-top:var(--acu-space-2);padding:var(--acu-space-2) var(--acu-space-3);background:var(--acu-error-soft);color:var(--acu-error);border-radius:var(--acu-radius-sm);font-size:var(--acu-font-size-sm)}.acu-retry-btn[data-v-49f051a5]{margin-left:auto;border:1px solid currentColor;background:transparent;color:inherit;padding:2px 10px;border-radius:var(--acu-radius-xs);font-size:var(--acu-font-size-xs);font-family:inherit;cursor:pointer;transition:opacity var(--acu-duration-fast) var(--acu-easing)}.acu-retry-btn[data-v-49f051a5]:hover{opacity:.75}.acu-message-list[data-v-b7171398]{position:relative;flex:1;min-height:0;overflow-y:auto;overflow-x:hidden;scrollbar-width:thin;scrollbar-color:var(--acu-border-strong) transparent}.acu-message-list[data-v-b7171398]::-webkit-scrollbar{width:6px;height:6px}.acu-message-list[data-v-b7171398]::-webkit-scrollbar-track{background:transparent}.acu-message-list[data-v-b7171398]::-webkit-scrollbar-thumb{background-color:var(--acu-border-strong);border-radius:3px}.acu-message-list[data-v-b7171398]::-webkit-scrollbar-thumb:hover{background-color:var(--acu-text-muted)}.acu-message-list[data-v-b7171398]{scroll-behavior:auto}.acu-message-list-inner[data-v-b7171398]{display:flex;flex-direction:column;gap:var(--acu-space-5);max-width:var(--acu-max-width);width:100%;margin:0 auto;padding:var(--acu-space-5) var(--acu-space-4) var(--acu-space-6)}.acu-scroll-btn[data-v-b7171398]{position:sticky;bottom:var(--acu-space-3);left:50%;transform:translate(-50%);width:36px;height:36px;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--acu-border);background:var(--acu-bg);color:var(--acu-text-secondary);border-radius:var(--acu-radius-full);cursor:pointer;box-shadow:var(--acu-shadow);transition:all var(--acu-duration) var(--acu-easing);z-index:2;margin:0 auto}.acu-scroll-btn[data-v-b7171398]:hover{color:var(--acu-primary);border-color:var(--acu-primary)}.acu-fade-enter-active[data-v-b7171398],.acu-fade-leave-active[data-v-b7171398]{transition:opacity var(--acu-duration) var(--acu-easing),transform var(--acu-duration) var(--acu-easing)}.acu-fade-enter-from[data-v-b7171398],.acu-fade-leave-to[data-v-b7171398]{opacity:0;transform:translate(-50%,6px)}.acu-welcome[data-v-9931daa7]{flex:1;display:flex;align-items:center;justify-content:center;padding:var(--acu-space-8) var(--acu-space-4);min-height:0}.acu-welcome-inner[data-v-9931daa7]{width:100%;max-width:640px;text-align:center;display:flex;flex-direction:column;align-items:center}.acu-welcome-logo[data-v-9931daa7]{width:56px;height:56px;border-radius:var(--acu-radius-lg);background:linear-gradient(135deg,var(--acu-primary-soft),var(--acu-surface));color:var(--acu-primary);display:inline-flex;align-items:center;justify-content:center;margin-bottom:var(--acu-space-5);box-shadow:var(--acu-shadow-sm)}.acu-welcome-title[data-v-9931daa7]{font-size:22px;font-weight:650;color:var(--acu-text);margin:0 0 var(--acu-space-2);letter-spacing:-.01em}.acu-welcome-desc[data-v-9931daa7]{font-size:var(--acu-font-size-md);color:var(--acu-text-secondary);margin:0 0 var(--acu-space-6);max-width:440px}.acu-welcome-grid[data-v-9931daa7]{width:100%;display:grid;grid-template-columns:repeat(2,1fr);gap:var(--acu-space-3)}@media (max-width: 560px){.acu-welcome-grid[data-v-9931daa7]{grid-template-columns:1fr}}.acu-preset-q[data-v-9931daa7]{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--acu-space-3);padding:var(--acu-space-4);text-align:left;background:var(--acu-surface);border:1px solid var(--acu-border);border-radius:var(--acu-radius);cursor:pointer;font-family:inherit;transition:all var(--acu-duration) var(--acu-easing);outline:none}.acu-preset-q[data-v-9931daa7]:focus-visible{box-shadow:0 0 0 2px var(--acu-bg),0 0 0 4px var(--acu-primary)}.acu-preset-q[data-v-9931daa7]:hover{border-color:var(--acu-primary);background:var(--acu-primary-soft);transform:translateY(-1px);box-shadow:var(--acu-shadow-sm)}.acu-preset-q:hover .acu-preset-q-arrow[data-v-9931daa7]{color:var(--acu-primary);transform:translate(2px,-2px)}.acu-preset-q-body[data-v-9931daa7]{display:flex;flex-direction:column;gap:2px;min-width:0}.acu-preset-q-label[data-v-9931daa7]{font-size:var(--acu-font-size-md);font-weight:550;color:var(--acu-text)}.acu-preset-q-prompt[data-v-9931daa7]{font-size:var(--acu-font-size-xs);color:var(--acu-text-muted);display:-webkit-box;-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.acu-preset-q-arrow[data-v-9931daa7]{flex-shrink:0;color:var(--acu-text-muted);transition:transform var(--acu-duration) var(--acu-easing),color var(--acu-duration) var(--acu-easing);margin-top:2px}.acu-input-wrap[data-v-8f617582]{position:relative;max-width:var(--acu-max-width);width:100%;margin:0 auto;background:var(--acu-surface);border:1px solid var(--acu-border);border-radius:var(--acu-radius-lg);padding:var(--acu-space-2);transition:border-color var(--acu-duration) var(--acu-easing),box-shadow var(--acu-duration) var(--acu-easing),background-color var(--acu-duration) var(--acu-easing)}.acu-input-wrap[data-v-8f617582]:focus-within{border-color:var(--acu-primary);box-shadow:0 0 0 3px var(--acu-primary-soft)}.acu-input-wrap.is-dragging[data-v-8f617582]{border-color:var(--acu-primary);background:var(--acu-primary-soft);box-shadow:0 0 0 3px var(--acu-primary-soft)}.acu-input-wrap.is-disabled[data-v-8f617582]{opacity:.6;pointer-events:none}.acu-input-drop-hint[data-v-8f617582]{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--acu-space-2);color:var(--acu-primary);font-size:var(--acu-font-size-sm);font-weight:500;pointer-events:none;z-index:1}.acu-input-attachments[data-v-8f617582]{display:flex;flex-wrap:wrap;gap:var(--acu-space-2);padding:var(--acu-space-2) var(--acu-space-2) 0}.acu-input-att[data-v-8f617582]{position:relative;display:inline-flex}.acu-input-att-thumb[data-v-8f617582]{width:56px;height:56px;border-radius:var(--acu-radius-sm);overflow:hidden;border:1px solid var(--acu-border)}.acu-input-att-thumb img[data-v-8f617582]{width:100%;height:100%;object-fit:cover}.acu-input-att-file[data-v-8f617582]{display:inline-flex;align-items:center;gap:var(--acu-space-2);padding:var(--acu-space-2) var(--acu-space-3);background:var(--acu-bg);border:1px solid var(--acu-border);border-radius:var(--acu-radius-sm);color:var(--acu-text-secondary);max-width:180px}.acu-input-att-name[data-v-8f617582]{font-size:var(--acu-font-size-xs);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.acu-input-att-remove[data-v-8f617582]{position:absolute;top:-6px;right:-6px;width:18px;height:18px;display:inline-flex;align-items:center;justify-content:center;border:none;border-radius:var(--acu-radius-full);background:var(--acu-text);color:var(--acu-bg);cursor:pointer;box-shadow:var(--acu-shadow-sm);transition:transform var(--acu-duration-fast) var(--acu-easing)}.acu-input-att-remove[data-v-8f617582]:hover{transform:scale(1.12)}.acu-input-row[data-v-8f617582]{display:flex;align-items:flex-end;gap:var(--acu-space-2);padding:var(--acu-space-1) var(--acu-space-1) 0}.acu-input-icon-btn[data-v-8f617582]{flex-shrink:0;width:36px;height:36px;display:inline-flex;align-items:center;justify-content:center;border:none;background:transparent;color:var(--acu-text-muted);border-radius:var(--acu-radius-sm);cursor:pointer;transition:all var(--acu-duration-fast) var(--acu-easing);outline:none}.acu-input-icon-btn[data-v-8f617582]:focus-visible{box-shadow:0 0 0 2px var(--acu-bg),0 0 0 4px var(--acu-primary)}.acu-input-icon-btn[data-v-8f617582]:hover:not(:disabled){background:var(--acu-surface-2);color:var(--acu-text)}.acu-input-file[data-v-8f617582]{display:none}.acu-input-textarea[data-v-8f617582]{flex:1;min-height:36px;max-height:200px;padding:8px 4px;border:none;background:transparent;resize:none;font-family:inherit;font-size:var(--acu-font-size-md);line-height:1.5;color:var(--acu-text);outline:none;scrollbar-width:thin;scrollbar-color:var(--acu-border-strong) transparent}.acu-input-textarea[data-v-8f617582]::-webkit-scrollbar{width:4px;height:4px}.acu-input-textarea[data-v-8f617582]::-webkit-scrollbar-track{background:transparent}.acu-input-textarea[data-v-8f617582]::-webkit-scrollbar-thumb{background-color:var(--acu-border-strong);border-radius:2px}.acu-input-textarea[data-v-8f617582]::-webkit-scrollbar-thumb:hover{background-color:var(--acu-text-muted)}.acu-input-textarea[data-v-8f617582]::placeholder{color:var(--acu-text-muted)}.acu-input-textarea[data-v-8f617582]:disabled{cursor:not-allowed}.acu-input-send[data-v-8f617582]{flex-shrink:0;width:36px;height:36px;display:inline-flex;align-items:center;justify-content:center;border:none;background:var(--acu-primary);color:var(--acu-primary-contrast);border-radius:var(--acu-radius-sm);cursor:pointer;transition:all var(--acu-duration-fast) var(--acu-easing);outline:none}.acu-input-send[data-v-8f617582]:focus-visible{box-shadow:0 0 0 2px var(--acu-bg),0 0 0 4px var(--acu-primary)}.acu-input-send[data-v-8f617582]:hover:not(:disabled){background:var(--acu-primary-hover)}.acu-input-send[data-v-8f617582]:active:not(:disabled){background:var(--acu-primary-active)}.acu-input-send[data-v-8f617582]:disabled{background:var(--acu-surface-2);color:var(--acu-text-muted);cursor:not-allowed}.acu-chat[data-v-e862adeb]{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--acu-bg)}.acu-chat-body[data-v-e862adeb]{flex:1;min-height:0;display:flex;flex-direction:column}.acu-chat-footer[data-v-e862adeb]{flex-shrink:0;padding:var(--acu-space-3) var(--acu-space-4) var(--acu-space-4);background:linear-gradient(to top,var(--acu-bg) 70%,transparent)}
|