Skip to content

快速开始 ​

概述 ​

AI Chat UI 是一个后端无关的 AI 聊天界面组件库。通过 ChatAdapter 接口适配任何 AI 后端(OpenAI、Claude、自建 API 等),组件库本身不依赖任何特定的 API 提供商。

前置条件 ​

  • Node.js >= 18
  • pnpm >= 9
  • Vue 3.5+

安装 ​

bash
# 安装核心包(必须)
pnpm add @toimc/core

# 安装 Vue 组件(必须)
pnpm add @toimc/vue

# 安装 Markdown 渲染(可选)
pnpm add @toimc/markdown

如需渲染 LaTeX 公式,额外手动引入 KaTeX 样式(可选,不影响其他功能):

ts
import '@toimc/markdown/katex.css'

最小示例 ​

vue
<script setup lang="ts">
import { provide } from 'vue'
import { useChat } from '@toimc/core'
import type { ChatAdapter } from '@toimc/core'
import {
  Conversation,
  ConversationContent,
  Message,
  MessageContent,
  PromptInput,
  PromptInputBody,
  PromptInputTextarea,
  PromptInputFooter,
  PromptInputSubmit,
  markdownRendererKey,
} from '@toimc/vue'
import { MarkdownRenderer } from '@toimc/markdown'

// AI 消息的 content prop 走 Markdown 渲染,需注入渲染器
provide(markdownRendererKey, MarkdownRenderer)

// 1. 实现 ChatAdapter 接口
const adapter: ChatAdapter = {
  async *sendMessage({ messages }) {
    // 对接你的 AI 后端
    const res = await fetch('/api/chat', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ messages }),
    })
    const reader = res.body!.getReader()
    const decoder = new TextDecoder()
    while (true) {
      const { done, value } = await reader.read()
      if (done) break
      yield { type: 'text', content: decoder.decode(value) }
    }
    yield { type: 'done', content: '' }
  },
}

// 2. 使用 useChat composable
const chat = useChat(adapter)
</script>

<template>
  <!-- 3. 组装组件 -->
  <Conversation>
    <ConversationContent>
      <Message v-for="msg in chat.messages" :key="msg.id" :from="msg.role">
        <MessageContent
          :content="msg.role === 'assistant' ? msg.content : undefined"
          :streaming="chat.isStreaming"
        >
          <template v-if="msg.role !== 'assistant'">{{ msg.content }}</template>
        </MessageContent>
      </Message>
    </ConversationContent>

    <PromptInput
      :disabled="chat.isStreaming"
      @send="(payload) => chat.send(payload.text)"
      @abort="chat.abort"
    >
      <PromptInputBody>
        <PromptInputTextarea />
      </PromptInputBody>
      <template #footer>
        <PromptInputFooter>
          <template #hint>
            <PromptInputSubmit />
          </template>
        </PromptInputFooter>
      </template>
    </PromptInput>
  </Conversation>
</template>

下一步 ​