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 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)}