Vue3 + TypeScript 本地 AI 助手 - 集成大模型 API、文档总结、翻译完整实现

欢迎加入开源鸿蒙PC社区:
https://harmonypc.csdn.net/

项目 Git 仓库:
https://atomgit.com/liboqian/harmonyOs_ai

基于 Vue3 Composition API + TypeScript 构建的本地 AI 助手桌面端应用,支持 OpenAI、Claude、DeepSeek、通义千问、Ollama 等多种 AI 服务,提供文档总结、智能翻译、文本改写、概念解释等核心功能,支持流式输出和历史对话管理。
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

一、项目背景

随着大语言模型(LLM)技术的快速发展,AI 助手已经成为提升工作效率的重要工具。然而,大多数 AI 服务需要通过网页访问,缺乏统一的本地管理界面。

1.1 业务痛点

  • 多个 AI 服务需要频繁切换网页,效率低下
  • 对话历史分散在各个平台,无法统一管理
  • 常用任务(总结、翻译等)需要反复编写提示词
  • API 调用缺乏统计和管理,难以控制成本
  • 离线场景下无法使用 AI 能力

1.2 解决方案

构建一个统一的本地 AI 助手桌面端应用,具备以下特点:

  • 多服务支持:OpenAI、Claude、DeepSeek、通义千问、Ollama 本地部署
  • 任务模板:文档总结、智能翻译、文本改写、概念解释、问答助手
  • 流式输出:实时显示 AI 回复内容,无需等待完整响应
  • 历史管理:多轮对话管理,随时回溯历史对话
  • 数据统计:对话数量、消息统计、使用趋势
  • 隐私安全:本地存储,API Key 安全保存

1.3 效果预览

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传


二、技术栈

2.1 核心技术

技术版本说明
Vue3^3.4.0前端框架,使用 Composition API
TypeScript^5.3.0类型安全的 JavaScript 超集
Vue Router^4.6.4Vue 官方路由管理
Vite^5.0.0极速构建工具
HarmonyOSAPI 11+鸿蒙操作系统
Fetch API原生调用 AI 服务 API

2.2 支持的 AI 服务

服务默认模型默认地址说明
OpenAIgpt-4o-miniapi.openai.com/v1全球最流行的 AI 服务
Claudeclaude-3-5-sonnetapi.anthropic.comAnthropic 的 Claude 系列
DeepSeekdeepseek-chatapi.deepseek.com/v1国产开源大模型
通义千问qwen-turbodashscope.aliyuncs.com阿里云通义系列
Ollamallama3localhost:11434/v1本地部署,无需网络

2.3 项目配置

{
  "name": "local-ai-assistant",
  "version": "1.0.0",
  "description": "本地AI助手 - 集成大模型API,文档总结、翻译",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  }
}

三、项目架构

3.1 目录结构

vue-app/
├── src/
│   ├── types/
│   │   └── ai.ts                    # 类型定义
│   ├── services/
│   │   └── AIService.ts             # 业务逻辑层
│   ├── components/
│   │   └── AIPanel.vue              # 主组件
│   ├── views/
│   │   └── AIView.vue               # 视图组件
│   ├── router/
│   │   └── index.ts                 # 路由配置
│   ├── styles/
│   │   └── global.css               # 全局样式
│   ├── App.vue                      # 根组件
│   └── main.ts                      # 入口文件
├── index.html                       # HTML 模板
├── package.json                     # 项目配置
├── vite.config.ts                   # Vite 配置
└── tsconfig.json                    # TypeScript 配置

3.2 架构分层

┌─────────────────────────────────────────────┐
│                  View 层                     │
│                AIView.vue                    │
├─────────────────────────────────────────────┤
│                Component 层                  │
│               AIPanel.vue                   │
│  ┌──────────┬──────────┬────────┬────────┐  │
│  │ 对话管理 │ 任务模板 │ 消息展示│ 设置面板│  │
│  └──────────┴──────────┴────────┴────────┘  │
├─────────────────────────────────────────────┤
│                Service 层                    │
│              AIService.ts                   │
│  ┌──────────┬──────────┬────────┬────────┐  │
│  │ 配置管理 │ 对话管理 │ API调用 │ 统计管理│  │
│  └──────────┴──────────┴────────┴────────┘  │
├─────────────────────────────────────────────┤
│                Type 层                       │
│                 ai.ts                       │
│  AIConfig | Conversation | ChatMessage      │
├─────────────────────────────────────────────┤
│              数据存储层                       │
│              localStorage                   │
└─────────────────────────────────────────────┘

四、TypeScript 类型定义

4.1 枚举类型

// AI 服务类型
export type AIServiceType = 
  | 'openai'     // OpenAI GPT
  | 'claude'     // Anthropic Claude
  | 'deepseek'   // DeepSeek
  | 'qwen'       // 通义千问
  | 'ollama'     // 本地部署

// 任务类型
export type TaskType = 
  | 'summary'    // 文档总结
  | 'translate'  // 智能翻译
  | 'rewrite'    // 文本改写
  | 'explain'    // 概念解释
  | 'qa'         // 问答助手
  | 'custom'     // 自由对话

// 消息角色
export type MessageRole = 'user' | 'assistant' | 'system'

4.2 核心接口

// AI 配置接口
export interface AIConfig {
  serviceType: AIServiceType  // 服务类型
  apiKey: string              // API Key
  baseUrl: string             // API 地址
  model: string               // 模型名称
  maxTokens: number           // 最大 Token 数
  temperature: number         // 温度参数 (0-1)
}

// 聊天消息接口
export interface ChatMessage {
  id: string            // 唯一标识
  role: MessageRole     // 消息角色
  content: string       // 消息内容
  timestamp: number     // 发送时间
  model?: string        // 使用的模型
}

// 对话接口
export interface Conversation {
  id: string                    // 唯一标识
  title: string                 // 对话标题
  messages: ChatMessage[]       // 消息列表
  createdAt: number             // 创建时间
  updatedAt: number             // 更新时间
  messageCount: number          // 消息数量
}

// 任务模板接口
export interface TaskTemplate {
  id: string                // 唯一标识
  name: string              // 任务名称
  type: TaskType            // 任务类型
  icon: string              // 图标
  description: string       // 描述
  systemPrompt: string      // 系统提示词
  userPromptTemplate: string // 用户提示词模板
  color: string             // 颜色
}

// 使用统计接口
export interface UsageStats {
  totalConversations: number    // 对话总数
  totalMessages: number         // 消息总数
  totalTokens: number           // Token 总数
  todayConversations: number    // 今日对话
  todayMessages: number         // 今日消息
  popularTask: string           // 常用任务
}

4.3 任务模板配置

export const TASK_TEMPLATES: TaskTemplate[] = [
  {
    id: 'summary',
    name: '文档总结',
    type: 'summary',
    icon: '📝',
    description: '快速提炼文档核心要点',
    systemPrompt: '你是一个专业的文档总结助手。请仔细阅读用户提供的文档内容,提炼出核心要点...',
    userPromptTemplate: '请对以下内容进行总结:\n\n{{content}}',
    color: '#3b82f6',
  },
  {
    id: 'translate',
    name: '智能翻译',
    type: 'translate',
    icon: '🌐',
    description: '支持多语言智能翻译',
    systemPrompt: '你是一个专业的翻译助手。请将用户提供的内容翻译为目标语言...',
    userPromptTemplate: '请将以下内容翻译为{{targetLang}}:\n\n{{content}}',
    color: '#10b981',
  },
  {
    id: 'rewrite',
    name: '文本改写',
    type: 'rewrite',
    icon: '✍️',
    description: '改写文本,使其更通顺专业',
    // ...
  },
  {
    id: 'explain',
    name: '概念解释',
    type: 'explain',
    icon: '💡',
    description: '用通俗易懂的方式解释概念',
    // ...
  },
  {
    id: 'qa',
    name: '问答助手',
    type: 'qa',
    icon: '❓',
    description: '解答各种问题',
    // ...
  },
  {
    id: 'custom',
    name: '自由对话',
    type: 'custom',
    icon: '💬',
    description: '自由发挥,无限制对话',
    // ...
  },
]

任务模板说明

任务图标适用场景提示词特点
文档总结📝长文总结、报告提炼要求提炼3-5个要点
智能翻译🌐中英互译、多语言翻译保持原意,自然流畅
文本改写✍️润色文章、改写风格保留核心意思,优化表达
概念解释💡技术解释、知识科普通俗易懂,避免术语
问答助手问题解答、知识查询准确详细,有条理
自由对话💬创意写作、头脑风暴无限制,自由发挥

五、服务层实现

5.1 服务类初始化

import { AIConfig, Conversation, ChatMessage, UsageStats } from '../types/ai'

const STORAGE_KEYS = {
  config: 'ai_config',
  conversations: 'ai_conversations',
  currentConversationId: 'ai_current_conversation',
  usage: 'ai_usage_stats',
}

class _AIService {
  private config: AIConfig | null = null
  private conversations: Conversation[] = []
  private currentConversationId: string | null = null

  constructor() {
    this.loadFromStorage()
    if (!this.config) {
      this.initDefaultConfig()
    }
  }

  private loadFromStorage(): void {
    try {
      const config = localStorage.getItem(STORAGE_KEYS.config)
      const conversations = localStorage.getItem(STORAGE_KEYS.conversations)
      const currentId = localStorage.getItem(STORAGE_KEYS.currentConversationId)
      if (config) this.config = JSON.parse(config)
      if (conversations) this.conversations = JSON.parse(conversations)
      if (currentId) this.currentConversationId = currentId
    } catch {
      this.config = null
      this.conversations = []
      this.currentConversationId = null
    }
  }

  private saveToStorage(): void {
    localStorage.setItem(STORAGE_KEYS.config, JSON.stringify(this.config))
    localStorage.setItem(STORAGE_KEYS.conversations, JSON.stringify(this.conversations))
    if (this.currentConversationId) {
      localStorage.setItem(STORAGE_KEYS.currentConversationId, this.currentConversationId)
    }
  }

  private initDefaultConfig(): void {
    this.config = {
      serviceType: 'ollama',        // 默认使用本地 Ollama
      apiKey: '',                   // 本地无需 API Key
      baseUrl: 'http://localhost:11434/v1',
      model: 'llama3',
      maxTokens: 2048,
      temperature: 0.7,
    }
    this.saveToStorage()
  }
}

5.2 API 调用(支持流式输出)

这是核心功能,支持流式响应和模拟降级:

async sendMessage(conversationId: string, content: string, onChunk?: (chunk: string) => void): Promise<string> {
  // 添加用户消息
  this.addMessage(conversationId, 'user', content)

  const conversation = this.conversations.find(c => c.id === conversationId)
  if (!conversation) throw new Error('Conversation not found')

  // 构建消息历史(最近10条)
  const messages = conversation.messages.slice(-10).map(m => ({
    role: m.role,
    content: m.content,
  }))

  if (!this.config) throw new Error('AI config not initialized')

  try {
    // 调用 AI API
    const response = await fetch(`${this.config.baseUrl}/chat/completions`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${this.config.apiKey}`,
      },
      body: JSON.stringify({
        model: this.config.model,
        messages,
        max_tokens: this.config.maxTokens,
        temperature: this.config.temperature,
        stream: !!onChunk,  // 是否启用流式输出
      }),
    })

    if (!response.ok) {
      throw new Error(`API Error: ${response.status}`)
    }

    if (onChunk) {
      // 流式输出处理
      return await this.handleStreamResponse(response, onChunk, conversationId)
    } else {
      // 非流式输出
      const data = await response.json()
      const reply = data.choices?.[0]?.message?.content || '抱歉,未能生成回复。'
      this.addMessage(conversationId, 'assistant', reply)
      return reply
    }
  } catch (error) {
    // API 调用失败时,使用模拟回复
    console.warn('AI API call failed, using simulated response')
    const simulated = this.simulateResponse(content)
    this.addMessage(conversationId, 'assistant', simulated)
    return simulated
  }
}

5.3 流式响应处理

private async handleStreamResponse(response: Response, onChunk: (chunk: string) => void, conversationId: string): Promise<string> {
  const reader = response.body?.getReader()
  if (!reader) throw new Error('Failed to read stream')

  const decoder = new TextDecoder()
  let fullContent = ''

  try {
    while (true) {
      const { done, value } = await reader.read()
      if (done) break

      const chunk = decoder.decode(value, { stream: true })
      const lines = chunk.split('\n')

      for (const line of lines) {
        if (line.startsWith('data: ') && line !== 'data: [DONE]') {
          try {
            const json = JSON.parse(line.slice(6))
            const content = json.choices?.[0]?.delta?.content
            if (content) {
              fullContent += content
              onChunk(fullContent)  // 实时更新 UI
            }
          } catch { /* skip malformed JSON */ }
        }
      }
    }
  } finally {
    reader.releaseLock()
  }

  if (fullContent) {
    this.addMessage(conversationId, 'assistant', fullContent)
  }

  return fullContent
}

流式输出原理

服务器 → data: {"choices":[{"delta":{"content":"你"}}]}
服务器 → data: {"choices":[{"delta":{"content":"好"}}]}
服务器 → data: {"choices":[{"delta":{"content":","}}]}
服务器 → data: {"choices":[{"delta":{"content":"我"}}]}
...
服务器 → data: [DONE]

5.4 模拟响应(降级方案)

private simulateResponse(userInput: string): string {
  const lowerInput = userInput.toLowerCase()
  if (lowerInput.includes('总结')) {
    return '这是一份文档的总结要点:\n\n1. **核心主题**:文章主要讨论了技术发展趋势及其对行业的影响。\n\n2. **关键发现**:研究表明,AI 技术在各个领域的应用正在加速...\n\n3. **建议行动**:建议企业尽早布局 AI 战略...\n\n4. **未来展望**:随着技术的不断成熟...'
  }
  if (lowerInput.includes('翻译')) {
    return 'Translation completed successfully.\n\nThe content has been translated while preserving the original meaning and tone.'
  }
  if (lowerInput.includes('解释')) {
    return '让我用通俗的方式来解释这个概念:\n\n你可以把它想象成是一个"智能助手"。就像你有一个非常聪明的朋友...\n\n**关键点**:\n- 它能够理解自然语言\n- 可以学习和适应不同的任务...'
  }
  return `感谢您的提问!\n\n关于您提到的内容,我的分析如下:\n\n这是一个非常有意义的话题...`
}

六、核心功能实现

6.1 对话管理

<template>
  <aside class="sidebar">
    <button class="btn btn-primary btn-block" @click="createNewChat">
      ➕ 新建对话
    </button>

    <div class="task-templates">
      <div class="section-title">快捷任务</div>
      <div v-for="task in taskTemplates" :key="task.id" class="task-item" @click="selectTask(task)">
        <span class="task-icon">{{ task.icon }}</span>
        <span class="task-name">{{ task.name }}</span>
      </div>
    </div>

    <div class="conversations">
      <div class="section-title">历史对话</div>
      <div v-for="conv in conversations" :key="conv.id"
           :class="['conv-item', { active: conv.id === currentConversation?.id }]"
           @click="selectConversation(conv)">
        <span class="conv-title">{{ conv.title }}</span>
        <button class="conv-delete" @click.stop="deleteConversation(conv.id)">✕</button>
      </div>
    </div>
  </aside>
</template>

对话管理功能

功能说明
新建对话创建新的对话会话
切换对话点击历史对话切换到对应会话
删除对话鼠标悬停显示删除按钮
自动标题第一条消息自动作为对话标题

6.2 消息展示

<div class="chat-messages">
  <div v-for="msg in currentConversation.messages" :key="msg.id"
       :class="['message', `message-${msg.role}`]">
    <div class="message-avatar">
      {{ msg.role === 'user' ? '👤' : '🤖' }}
    </div>
    <div class="message-content">
      <div class="message-text" v-html="formatMessage(msg.content)"></div>
      <div class="message-time">
        {{ formatTime(msg.timestamp) }}
        <span v-if="msg.model" class="message-model">{{ msg.model }}</span>
      </div>
    </div>
  </div>
</div>

消息格式化

function formatMessage(content: string): string {
  return content
    .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')  // **粗体**
    .replace(/\*(.*?)\*/g, '<em>$1</em>')              // *斜体*
    .replace(/`(.*?)`/g, '<code>$1</code>')            // `代码`
    .replace(/\n/g, '<br>')                            // 换行
}

6.3 任务模板

选择任务模板后,用户输入会自动套用模板:

function selectTask(task: TaskTemplate): void {
  selectedTask.value = task
  if (!currentConversation.value) {
    createNewChat()
  }
}

async function sendMessage(): Promise<void> {
  let finalContent = inputMessage.value

  // 如果选择了任务模板,套用提示词模板
  if (selectedTask.value) {
    finalContent = selectedTask.value.userPromptTemplate
      .replace('{{content}}', inputMessage.value)
      .replace('{{targetLang}}', '英文')
  }

  await AIService.sendMessage(conversationId, finalContent, (chunk: string) => {
    streamingContent.value = chunk
  })
}

任务模板使用示例

用户选择「文档总结」任务
用户输入:这是一篇关于AI发展的长文章...

实际发送给AI的提示词:
请对以下内容进行总结:

这是一篇关于AI发展的长文章...

6.4 快捷操作

export const QUICK_ACTIONS: QuickAction[] = [
  { id: 'q1', label: '总结文章', icon: '📄', prompt: '请帮我总结以下文章的核心要点:' },
  { id: 'q2', label: '翻译为英文', icon: '🇬🇧', prompt: '请将以下内容翻译为英文:' },
  { id: 'q3', label: '翻译为中文', icon: '🇨🇳', prompt: '请将以下内容翻译为中文:' },
  { id: 'q4', label: '润色文本', icon: '✨', prompt: '请帮我润色以下文本,使其更加专业:' },
  { id: 'q5', label: '代码解释', icon: '💻', prompt: '请帮我解释以下代码的作用:' },
  { id: 'q6', label: '写邮件', icon: '📧', prompt: '请帮我写一封邮件,主题是:' },
]

七、响应式数据管理

7.1 组合式 API

import { ref, computed, onMounted, nextTick } from 'vue'

const inputMessage = ref('')
const isStreaming = ref(false)
const streamingContent = ref('')
const showSettings = ref(false)
const selectedTask = ref<TaskTemplate | null>(null)
const toastMessage = ref('')
const toastType = ref('success')
const chatContainer = ref<HTMLElement | null>(null)

const config = ref<AIConfig | null>(null)
const conversations = ref<Conversation[]>([])
const currentConversation = ref<Conversation | null>(null)
const stats = ref({ totalConversations: 0, totalMessages: 0, todayConversations: 0, todayMessages: 0 })

7.2 自动滚动

function scrollToBottom(): void {
  nextTick(() => {
    if (chatContainer.value) {
      chatContainer.value.scrollTop = chatContainer.value.scrollHeight
    }
  })
}

// 发送消息后自动滚动
await AIService.sendMessage(conversationId, content, (chunk: string) => {
  streamingContent.value = chunk
  scrollToBottom()  // 流式输出时实时滚动到底部
})
scrollToBottom()

八、样式设计

8.1 消息气泡样式

.message { display: flex; gap: 12px; margin-bottom: 20px; }
.message-avatar { 
  width: 36px; height: 36px; border-radius: 50%; 
  background: #f1f5f9; display: flex; align-items: center; 
  justify-content: center; font-size: 18px; 
}
.message-text { 
  background: white; border-radius: 12px; padding: 12px 15px; 
  line-height: 1.6; font-size: 14px; 
  box-shadow: 0 1px 3px rgba(0,0,0,0.05); 
}
.message-user .message-text { background: #e0e7ff; }
.message-user { flex-direction: row-reverse; }

8.2 打字指示器动画

.typing-indicator { display: flex; gap: 4px; padding: 5px 0; }
.typing-indicator span { 
  width: 6px; height: 6px; border-radius: 50%; 
  background: #94a3b8; animation: typing 1.4s infinite; 
}
.typing-indicator span:nth-child(2) { animation-delay: 0.2s; }
.typing-indicator span:nth-child(3) { animation-delay: 0.4s; }

@keyframes typing { 
  0%, 60%, 100% { transform: translateY(0); } 
  30% { transform: translateY(-6px); } 
}

8.3 流式输出样式

.streaming { 
  border-left: 3px solid #3b82f6;  /* 左侧蓝色竖线表示正在生成 */
}

九、AI 服务配置

9.1 配置参数说明

参数说明默认值建议范围
serviceTypeAI 服务类型ollama见上表
apiKeyAPI 密钥从服务商获取
baseUrlAPI 地址localhost:11434根据服务商调整
model模型名称llama3根据服务选择
maxTokens最大 Token 数2048256-8192
temperature温度参数0.70-1,越低越保守

9.2 Ollama 本地部署

Ollama 是最简单的本地 AI 部署方案:

# 1. 安装 Ollama
# 访问 https://ollama.ai 下载安装

# 2. 拉取模型
ollama pull llama3

# 3. 启动服务(默认端口 11434)
ollama serve

# 4. 测试
curl http://localhost:11434/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model":"llama3","messages":[{"role":"user","content":"你好"}]}'

💡 使用 Ollama 时,无需配置 API Key,默认地址为 http://localhost:11434/v1

9.3 其他服务商配置

OpenAI 配置示例

{
  "serviceType": "openai",
  "apiKey": "sk-...",
  "baseUrl": "https://api.openai.com/v1",
  "model": "gpt-4o-mini",
  "maxTokens": 2048,
  "temperature": 0.7
}

通义千问配置

{
  "serviceType": "qwen",
  "apiKey": "sk-...",
  "baseUrl": "https://dashscope.aliyuncs.com/compatible-mode/v1",
  "model": "qwen-turbo",
  "maxTokens": 2048,
  "temperature": 0.7
}

十、构建与部署

10.1 构建命令

# 清理缓存
Remove-Item -Recurse -Force "dist" -ErrorAction SilentlyContinue
Remove-Item -Recurse -Force ".hvigor" -ErrorAction SilentlyContinue

# 构建
npm run build

10.2 构建输出

✓ 37 modules transformed.
../dist/index.html                   0.62 kB │ gzip:  0.45 kB
../dist/assets/index-CBgsX6DZ.css    0.21 kB │ gzip:  0.19 kB
../dist/assets/AIView-CLjK2IUT.css   7.88 kB │ gzip:  1.96 kB
../dist/assets/AIView-C3X5lQXk.js   17.87 kB │ gzip:  8.26 kB
../dist/assets/index-BbYfLuou.js    91.73 kB │ gzip: 35.96 kB
✓ built in 615ms

10.3 产物分析

文件大小Gzip 后说明
index.html0.62 KB0.45 KBHTML 入口
index.css0.21 KB0.19 KB全局样式
AIView.css7.88 KB1.96 KB组件样式
AIView.js17.87 KB8.26 KB业务逻辑
index.js91.73 KB35.96 KBVue + Router
总计118.31 KB46.82 KB-

十一、核心亮点

11.1 流式输出实现

流式输出是提升用户体验的关键技术:

// 使用 Fetch API 的 ReadableStream
const reader = response.body?.getReader()
const decoder = new TextDecoder()
let fullContent = ''

while (true) {
  const { done, value } = await reader.read()
  if (done) break

  const chunk = decoder.decode(value, { stream: true })
  // 解析 SSE (Server-Sent Events) 格式
  const lines = chunk.split('\n')
  for (const line of lines) {
    if (line.startsWith('data: ') && line !== 'data: [DONE]') {
      const json = JSON.parse(line.slice(6))
      const content = json.choices?.[0]?.delta?.content
      if (content) {
        fullContent += content
        onChunk(fullContent)  // 回调更新 UI
      }
    }
  }
}

11.2 提示词模板系统

通过模板系统,用户无需记忆复杂的提示词:

// 模板定义
{
  userPromptTemplate: '请对以下内容进行总结:\n\n{{content}}',
}

// 运行时替换
const finalPrompt = template.replace('{{content}}', userInput)

设计优势

  • 降低使用门槛:普通用户无需编写提示词
  • 保证输出质量:精心设计的提示词获得更好的结果
  • 灵活可扩展:支持自定义变量替换

11.3 自动降级机制

当 API 调用失败时,自动使用模拟回复:

try {
  // 尝试调用真实 API
  const response = await fetch(apiUrl, { ... })
  return await handleResponse(response)
} catch (error) {
  // 降级到模拟回复
  return simulateResponse(userInput)
}

十二、常见问题解答

12.1 如何添加新的 AI 服务?

  1. ai.ts 中添加服务类型:
export type AIServiceType = 'openai' | '...' | 'new_service'
  1. SERVICE_CONFIG 中添加配置:
new_service: { label: '新服务', defaultModel: 'model-name', defaultBaseUrl: 'https://api.example.com' }

12.2 如何实现多轮对话?

系统会自动维护对话历史(最近10条消息):

const messages = conversation.messages.slice(-10).map(m => ({
  role: m.role,
  content: m.content,
}))

💡 AI 会基于上下文进行连贯对话,无需额外配置。

12.3 如何导出对话历史?

function exportHistory(): string {
  return JSON.stringify({
    conversations: this.conversations,
    config: this.config,
    exportedAt: new Date().toISOString(),
  }, null, 2)
}

导出后可用于:

  • 数据备份
  • 分析使用习惯
  • 迁移到其他设备

十三、总结

本项目基于 Vue3 + TypeScript 实现了一个功能完整的本地 AI 助手桌面端应用,主要特点包括:

  1. 多服务支持:OpenAI、Claude、DeepSeek、通义千问、Ollama
  2. 任务模板系统:文档总结、智能翻译、文本改写、概念解释等6种预设任务
  3. 流式输出:实时显示 AI 回复,无需等待完整响应
  4. 对话管理:多轮对话、历史记录、随时回溯
  5. 快捷操作:6种常用快捷动作一键触发
  6. 自动降级:API 不可用时自动使用模拟回复
  7. 数据统计:对话数、消息数、今日统计
  8. 本地部署支持:Ollama 本地部署,无需网络

项目代码结构清晰,遵循分层架构设计,可直接打包为 HarmonyOS 应用部署到鸿蒙设备。


十四、参考资料


更多推荐