聊天消息

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

用法

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

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

组成部分

使用 parts prop 以 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 prop 是 AI SDK v5 的推荐格式。每个部分都有一个 type (例如,'text') 和相应的内容。ChatMessage 组件也支持已废弃的 content prop 以实现向后兼容性。

方向

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

你好!请告诉我更多关于使用 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 prop 对于 assistant 消息设置为 left,对于 user 消息设置为 right

变体

使用 variant prop 更改消息的样式。

你好!请告诉我更多关于使用 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 prop 对于 assistant 消息设置为 naked,对于 user 消息设置为 soft

Icon

使用 icon prop 在消息旁边显示 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 prop 在消息旁边显示 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 prop 显示作为头像的图标。

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 prop 在消息下方显示操作,这些操作将在鼠标悬停在消息上时显示。

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

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

idstring

消息的唯一标识符。

role"system" | "user" | "assistant"

消息的角色。

partsUIMessagePart<UIDataTypes, UITools>[]

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

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

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

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

图标any
avatarAvatarProps & { [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' }

紧凑falseboolean

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

内容string
metadataunknown

消息的元数据。

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

更新日志

dd81d— feat: 添加 data-slot 属性 (#5447)

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

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

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

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