聊天推理 (ChatReasoning)
显示可折叠的 AI 推理或思考过程。
用法
ChatReasoning 组件渲染一个可折叠区块,用于显示 AI 的推理或思考过程。它在流式传输期间会自动展开,结束后自动收起。
<script setup lang="ts">
const streaming = ref(false)
const text = ref('')
async function simulateStreaming() {
streaming.value = true
text.value = ''
const content =
'The user is asking about Vue components. I should explain the Composition API pattern and how it relates to their question about reactive state management. Let me think about the best way to structure this response.\n\nFirst, I need to consider the key differences between the Options API and Composition API. The Composition API was introduced in Vue 3 to address limitations of the Options API when building large-scale applications.\n\nFor reactive state management specifically, the Composition API offers ref() for primitive values and reactive() for objects.'
for (const char of content) {
text.value += char
await new Promise((resolve) => setTimeout(resolve, 10))
}
streaming.value = false
}
onMounted(simulateStreaming)
</script>
<template>
<UChatReasoning :text="text" :streaming="streaming" class="w-60" />
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
const streaming = ref(false)
const text = ref('')
async function simulateStreaming() {
streaming.value = true
text.value = ''
const content =
'The user is asking about Vue components. I should explain the Composition API pattern and how it relates to their question about reactive state management. Let me think about the best way to structure this response.\n\nFirst, I need to consider the key differences between the Options API and Composition API. The Composition API was introduced in Vue 3 to address limitations of the Options API when building large-scale applications.\n\nFor reactive state management specifically, the Composition API offers ref() for primitive values and reactive() for objects.'
for (const char of content) {
text.value += char
await new Promise((resolve) => setTimeout(resolve, 10))
}
streaming.value = false
}
onMounted(simulateStreaming)
</script>
<template>
<UChatReasoning :text="text" :streaming="streaming" class="w-60" />
</template>
文本
使用 text prop 来设置推理内容。文本将显示在可折叠的主体中。
用户正在询问有关 Vue 组件的问题……
<template>
<UChatReasoning text="The user is asking about Vue components..." />
</template>
流式传输 (Streaming)
使用 streaming prop 来指示当前正在进行推理。组件会在流式传输开始时自动展开,并在结束时自动收起。
用户正在询问有关 Vue 组件的问题……
<template>
<UChatReasoning streaming text="The user is asking about Vue components..." />
</template>
使用来自
@nuxt/ui/utils/ai 的 isPartStreaming 工具来判断某个部分当前是否正在进行流式传输。Shimmer 效果
在流式传输时,触发器标签会使用 ChatShimmer 组件。使用 shimmer prop 来自定义其 duration 和 spread。
用户正在询问有关 Vue 组件的问题……
<template>
<UChatReasoning
streaming
text="The user is asking about Vue components..."
:shimmer="{
duration: 2,
spread: 2
}"
/>
</template>
Icon
使用 icon prop 在触发器旁边显示一个 Icon 组件。
用户正在询问有关 Vue 组件的问题……
<template>
<UChatReasoning icon="i-lucide-brain" text="The user is asking about Vue components..." />
</template>
折叠图标 (Chevron)
使用 chevron prop 来更改折叠图标的位置。
当
chevron 设置为 leading 且有 icon 时,图标会在悬停或打开状态时与折叠图标交换位置。用户正在询问有关 Vue 组件的问题……
<template>
<UChatReasoning
chevron="leading"
icon="i-lucide-brain"
text="The user is asking about Vue components..."
/>
</template>
折叠图标
使用 chevron-icon prop 自定义折叠 Icon。默认为 i-lucide-chevron-down。
用户正在询问有关 Vue 组件的问题……
<template>
<UChatReasoning
chevron-icon="i-lucide-arrow-down"
text="The user is asking about Vue components..."
/>
</template>
示例
API
属性
| 属性 | 默认值 | 类型 |
|---|---|---|
文本 | string要显示的推理文本内容。 | |
streaming | false | boolean推理内容当前是否正在进行流式传输。 |
duration | numberAI 进行推理所花费的时间(以秒为单位)。如果未提供,将根据流式传输时间自动计算。 | |
图标 | any显示在触发器旁边的图标。 | |
chevron | 'trailing' | "leading" | "trailing"折叠图标的位置。 |
chevronIcon | appConfig.ui.icons.chevronDown | any用作折叠箭头的图标。 |
autoCloseDelay | 500 | number流式传输结束后自动收起的延迟时间(以毫秒为单位)。设置为 |
shimmer | Partial<Omit<ChatShimmerProps, "text">>流式传输时自定义 | |
disabled | boolean当设置为 | |
open | undefined | boolean折叠块的受控展开状态。可以通过 |
defaultOpen | boolean折叠块在初始渲染时的展开状态。 | |
unmountOnHide | false | boolean当为 `true` 时,元素在关闭状态下将被卸载。 |
ui | { root?: SlotClass; trigger?: SlotClass; leading?: SlotClass; leadingIcon?: SlotClass; chevronIcon?: SlotClass; label?: SlotClass; trailingIcon?: SlotClass; content?: SlotClass; body?: SlotClass; } |
插槽
| 插槽 | 类型 |
|---|---|
default | { open: boolean; } |
事件
| 事件 | 类型 |
|---|---|
update:open | [value: boolean] |
主题
app.config.ts
export default defineAppConfig({
ui: {
chatReasoning: {
slots: {
root: '',
trigger: [
'group flex w-full items-center gap-1.5 text-muted text-sm disabled:cursor-default disabled:hover:text-muted hover:text-default rounded-sm outline-primary/25 focus-visible:outline-3 min-w-0',
'transition-colors'
],
leading: 'relative size-4 shrink-0',
leadingIcon: 'size-4 shrink-0',
chevronIcon: 'size-4 shrink-0 group-data-[state=open]:rotate-180 transition-transform duration-200',
label: 'truncate',
trailingIcon: 'size-4 shrink-0 group-data-[state=open]:rotate-180 transition-transform duration-200',
content: 'data-[state=open]:animate-[collapsible-down_200ms_ease-out] data-[state=closed]:animate-[collapsible-up_200ms_ease-out] data-[state=closed]:overflow-hidden rounded-sm outline-primary/25 has-focus-visible:outline-3',
body: 'max-h-[200px] pt-2 overflow-y-auto text-sm text-dimmed whitespace-pre-wrap focus:outline-none'
},
variants: {
chevron: {
leading: {
leadingIcon: 'group-hover:opacity-0'
},
trailing: ''
},
alone: {
false: {
leadingIcon: [
'absolute inset-0 group-data-[state=open]:opacity-0',
'transition-opacity duration-200'
],
chevronIcon: [
'absolute inset-0 opacity-0 group-hover:opacity-100 group-data-[state=open]:opacity-100',
'transition-[rotate,opacity] duration-200'
]
}
}
}
}
}
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'
export default defineConfig({
plugins: [
vue(),
ui({
ui: {
chatReasoning: {
slots: {
root: '',
trigger: [
'group flex w-full items-center gap-1.5 text-muted text-sm disabled:cursor-default disabled:hover:text-muted hover:text-default rounded-sm outline-primary/25 focus-visible:outline-3 min-w-0',
'transition-colors'
],
leading: 'relative size-4 shrink-0',
leadingIcon: 'size-4 shrink-0',
chevronIcon: 'size-4 shrink-0 group-data-[state=open]:rotate-180 transition-transform duration-200',
label: 'truncate',
trailingIcon: 'size-4 shrink-0 group-data-[state=open]:rotate-180 transition-transform duration-200',
content: 'data-[state=open]:animate-[collapsible-down_200ms_ease-out] data-[state=closed]:animate-[collapsible-up_200ms_ease-out] data-[state=closed]:overflow-hidden rounded-sm outline-primary/25 has-focus-visible:outline-3',
body: 'max-h-[200px] pt-2 overflow-y-auto text-sm text-dimmed whitespace-pre-wrap focus:outline-none'
},
variants: {
chevron: {
leading: {
leadingIcon: 'group-hover:opacity-0'
},
trailing: ''
},
alone: {
false: {
leadingIcon: [
'absolute inset-0 group-data-[state=open]:opacity-0',
'transition-opacity duration-200'
],
chevronIcon: [
'absolute inset-0 opacity-0 group-hover:opacity-100 group-data-[state=open]:opacity-100',
'transition-[rotate,opacity] duration-200'
]
}
}
}
}
}
})
]
})
更新日志
暂无近期更新