聊天消息

GitHub
显示带有图标、头像和操作的聊天消息。

用法

ChatMessage 组件为 userassistant 聊天消息渲染一个 <article> 元素。

你好!告诉我更多关于使用 Nuxt UI 构建 AI 聊天机器人的信息。
使用 ChatMessages 组件来显示聊天消息列表。

部分

使用 parts 属性以 AI SDK v5 格式显示消息内容。

你好!告诉我更多关于使用 Nuxt UI 构建 AI 聊天机器人的信息。
<template>
  <UChatMessage
    :parts="[
      {
        type: 'text',
        id: '1',
        text: 'Hello! Tell me more about building AI chatbots with Nuxt UI.'
      }
    ]"
    role="user"
    id="1"
  />
</template>
parts 属性是 AI SDK v5 的推荐格式。每个部分都有一个 type(例如,“text”)和相应的内容。ChatMessage 组件也支持已弃用的 content 属性以实现向后兼容。

方向

使用 side 属性在左侧或右侧显示消息。

你好!告诉我更多关于使用 Nuxt UI 构建 AI 聊天机器人的信息。
<template>
  <UChatMessage
    side="right"
    :parts="[
      {
        type: 'text',
        id: '1',
        text: 'Hello! Tell me more about building AI chatbots with Nuxt UI.'
      }
    ]"
    role="user"
    id="1"
  />
</template>
当使用 ChatMessages 组件时,side 属性对于 assistant 消息设置为 left,对于 user 消息设置为 right

变体

使用 variant 属性更改消息样式。

你好!告诉我更多关于使用 Nuxt UI 构建 AI 聊天机器人的信息。
<template>
  <UChatMessage
    variant="soft"
    :parts="[
      {
        type: 'text',
        id: '1',
        text: 'Hello! Tell me more about building AI chatbots with Nuxt UI.'
      }
    ]"
    role="user"
    id="1"
  />
</template>
当使用 ChatMessages 组件时,variant 属性对于 assistant 消息设置为 naked,对于 user 消息设置为 soft

Icon

使用 icon 属性在消息旁边显示一个 Icon 组件。

你好!告诉我更多关于使用 Nuxt UI 构建 AI 聊天机器人的信息。
<template>
  <UChatMessage
    icon="i-lucide-user"
    variant="soft"
    side="right"
    :parts="[
      {
        type: 'text',
        id: '1',
        text: 'Hello! Tell me more about building AI chatbots with Nuxt UI.'
      }
    ]"
    role="user"
    id="1"
  />
</template>

Avatar

使用 avatar 属性在消息旁边显示一个 Avatar 组件。

你好!告诉我更多关于使用 Nuxt UI 构建 AI 聊天机器人的信息。
<template>
  <UChatMessage
    :avatar="{
      src: 'https://github.com/benjamincanac.png'
    }"
    variant="soft"
    side="right"
    :parts="[
      {
        type: 'text',
        id: '1',
        text: 'Hello! Tell me more about building AI chatbots with Nuxt UI.'
      }
    ]"
    role="user"
    id="1"
  />
</template>

您还可以使用 avatar.icon 属性将图标显示为头像。

Nuxt UI 提供了几个用于构建 AI 聊天机器人的功能,包括 ChatMessage、ChatMessages 和 ChatPrompt 组件。最佳实践包括使用 AI SDK v5 中的 Chat 类,通过变体实现适当的消息样式,以及利用内置的操作进行消息交互。这些组件完全可定制,支持主题和响应式设计。
<template>
  <UChatMessage
    :avatar="{
      icon: 'i-lucide-bot'
    }"
    :parts="[
      {
        type: 'text',
        id: '1',
        text: 'Nuxt UI offers several features for building AI chatbots including the ChatMessage, ChatMessages, and ChatPrompt components. Best practices include using the Chat class from AI SDK v5, implementing proper message styling with variants, and utilizing the built-in actions for message interactions. The components are fully customizable with theming support and responsive design.'
      }
    ]"
    role="assistant"
    id="1"
  />
</template>

操作

使用 actions 属性在消息下方显示操作,当鼠标悬停在消息上时将显示这些操作。

Nuxt UI 提供了几个用于构建 AI 聊天机器人的功能,包括 ChatMessage、ChatMessages 和 ChatPrompt 组件。最佳实践包括使用 AI SDK v5 中的 Chat 类,通过变体实现适当的消息样式,以及利用内置的操作进行消息交互。这些组件完全可定制,支持主题和响应式设计。
<script setup lang="ts">
const actions = ref([
  {
    label: 'Copy to clipboard',
    icon: 'i-lucide-copy'
  }
])
</script>

<template>
  <UChatMessage
    :actions="actions"
    :parts="[
      {
        type: 'text',
        id: '1',
        text: 'Nuxt UI offers several features for building AI chatbots including the ChatMessage, ChatMessages, and ChatPrompt components. Best practices include using the Chat class from AI SDK v5, implementing proper message styling with variants, and utilizing the built-in actions for message interactions. The components are fully customizable with theming support and responsive design.'
      }
    ]"
    role="user"
    id="1"
  />
</template>

API

属性

属性默认值类型
as

'article'

any

此组件应渲染为的元素或组件。

id

string

消息的唯一标识符。

角色

"system" | "user" | "assistant"

消息的角色。

部分

UIMessagePart<UIDataTypes, UITools>[]

消息的部分。用于在 UI 中渲染消息。

应避免系统消息(而应在服务器上设置系统提示)。它们可以包含文本部分。

用户消息可以包含文本部分和文件部分。

助手消息可以包含文本、推理、工具调用和文件部分。

图标

字符串 | 对象

avatar

AvatarProps & { [key: string]: any; }

variant

'naked'

"solid" | "outline" | "soft" | "subtle" | "naked"

side

'left'

"left" | "right"

actions

(Omit<ButtonProps, "onClick> & { onClick?: ((e: MouseEvent, message: UIMessage<unknown, UIDataTypes, UITools>) => void) | undefined; })[]

在消息下方显示操作列表。工具提示中将使用 label{ size: 'xs', color: 'neutral', variant: 'ghost' }

紧凑

false

boolean

以紧凑样式渲染消息。在 UChatPalette 中使用时会自动完成。

内容

string

元数据

未知

消息的元数据。

ui

{ root?: ClassNameValue; container?: ClassNameValue; leading?: ClassNameValue; leadingIcon?: ClassNameValue; leadingAvatar?: ClassNameValue; leadingAvatarSize?: ClassNameValue; content?: ClassNameValue; actions?: ClassNameValue; }

插槽

插槽类型
前置

{ avatar: (AvatarProps & { [key: string]: any; }) | undefined; ui: object; }

内容

ChatMessageProps

actions

{ actions: (Omit<ButtonProps, "onClick> & { onClick?: ((e: MouseEvent, message: UIMessage<unknown, UIDataTypes, UITools>) => void) | undefined; })[] | undefined; }

主题

app.config.ts
export default defineAppConfig({
  ui: {
    chatMessage: {
      slots: {
        root: 'group/message relative w-full',
        container: 'relative flex items-start',
        leading: 'inline-flex items-center justify-center min-h-6',
        leadingIcon: 'shrink-0',
        leadingAvatar: 'shrink-0',
        leadingAvatarSize: '',
        content: 'relative text-pretty min-w-0 *:first:mt-0 *:last:mb-0',
        actions: [
          'opacity-0 group-hover/message:opacity-100 absolute bottom-0 flex items-center',
          'transition-opacity'
        ]
      },
      variants: {
        variant: {
          solid: {
            content: 'bg-inverted text-inverted'
          },
          outline: {
            content: 'bg-default ring ring-default'
          },
          soft: {
            content: 'bg-elevated/50'
          },
          subtle: {
            content: 'bg-elevated/50 ring ring-default'
          },
          naked: {
            content: ''
          }
        },
        side: {
          left: {
            container: 'rtl:justify-end'
          },
          right: {
            container: 'ltr:justify-end ms-auto max-w-[75%]'
          }
        },
        leading: {
          true: ''
        },
        actions: {
          true: ''
        },
        compact: {
          true: {
            root: 'scroll-mt-3',
            container: 'gap-1.5 pb-3',
            leadingIcon: 'size-5',
            leadingAvatarSize: '2xs'
          },
          false: {
            root: 'scroll-mt-4 sm:scroll-mt-6',
            container: 'gap-3 pb-8',
            leadingIcon: 'size-8',
            leadingAvatarSize: 'md'
          }
        }
      },
      compoundVariants: [
        {
          compact: true,
          actions: true,
          class: {
            container: 'pb-8'
          }
        },
        {
          leading: true,
          compact: false,
          side: 'left',
          class: {
            actions: 'left-11'
          }
        },
        {
          leading: true,
          compact: true,
          side: 'left',
          class: {
            actions: 'left-6.5'
          }
        },
        {
          variant: [
            'solid',
            'outline',
            'soft',
            'subtle'
          ],
          compact: false,
          class: {
            content: 'px-4 py-3 rounded-lg min-h-12',
            leading: 'mt-2'
          }
        },
        {
          variant: [
            'solid',
            'outline',
            'soft',
            'subtle'
          ],
          compact: true,
          class: {
            content: 'px-2 py-1 rounded-lg min-h-8',
            leading: 'mt-1'
          }
        },
        {
          variant: 'naked',
          side: 'left',
          class: {
            content: 'w-full'
          }
        }
      ],
      defaultVariants: {
        variant: 'naked'
      }
    }
  }
})
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: {
        chatMessage: {
          slots: {
            root: 'group/message relative w-full',
            container: 'relative flex items-start',
            leading: 'inline-flex items-center justify-center min-h-6',
            leadingIcon: 'shrink-0',
            leadingAvatar: 'shrink-0',
            leadingAvatarSize: '',
            content: 'relative text-pretty min-w-0 *:first:mt-0 *:last:mb-0',
            actions: [
              'opacity-0 group-hover/message:opacity-100 absolute bottom-0 flex items-center',
              'transition-opacity'
            ]
          },
          variants: {
            variant: {
              solid: {
                content: 'bg-inverted text-inverted'
              },
              outline: {
                content: 'bg-default ring ring-default'
              },
              soft: {
                content: 'bg-elevated/50'
              },
              subtle: {
                content: 'bg-elevated/50 ring ring-default'
              },
              naked: {
                content: ''
              }
            },
            side: {
              left: {
                container: 'rtl:justify-end'
              },
              right: {
                container: 'ltr:justify-end ms-auto max-w-[75%]'
              }
            },
            leading: {
              true: ''
            },
            actions: {
              true: ''
            },
            compact: {
              true: {
                root: 'scroll-mt-3',
                container: 'gap-1.5 pb-3',
                leadingIcon: 'size-5',
                leadingAvatarSize: '2xs'
              },
              false: {
                root: 'scroll-mt-4 sm:scroll-mt-6',
                container: 'gap-3 pb-8',
                leadingIcon: 'size-8',
                leadingAvatarSize: 'md'
              }
            }
          },
          compoundVariants: [
            {
              compact: true,
              actions: true,
              class: {
                container: 'pb-8'
              }
            },
            {
              leading: true,
              compact: false,
              side: 'left',
              class: {
                actions: 'left-11'
              }
            },
            {
              leading: true,
              compact: true,
              side: 'left',
              class: {
                actions: 'left-6.5'
              }
            },
            {
              variant: [
                'solid',
                'outline',
                'soft',
                'subtle'
              ],
              compact: false,
              class: {
                content: 'px-4 py-3 rounded-lg min-h-12',
                leading: 'mt-2'
              }
            },
            {
              variant: [
                'solid',
                'outline',
                'soft',
                'subtle'
              ],
              compact: true,
              class: {
                content: 'px-2 py-1 rounded-lg min-h-8',
                leading: 'mt-1'
              }
            },
            {
              variant: 'naked',
              side: 'left',
              class: {
                content: 'w-full'
              }
            }
          ],
          defaultVariants: {
            variant: 'naked'
          }
        }
      }
    })
  ]
})

更新日志

63c0a— feat: 在使用的 slot prop 中暴露 ui (#5207)

61b60— 功能:允许传递组件而不是名称 (#4766)

de782— feat!: 升级 ai-sdk 到 v5 (#4698)

5cb65— 特性:导入 @nuxt/ui-pro 组件