2025年2月28日-周报

本次周报也是对于鸿蒙原生大模型对话应用开发项目的一个总结

往期内容:
使用鸿蒙原生进行开发的大模型对话应用

鸿蒙原生大模型对话应用开发过程记录

新的项目地址:
release版本
dev版

项目开发记录

一、OpenAI 库调用与多轮对话实现

1.1 OpenAI 库调用

  • 使用鸿蒙的 openai 库实现与 OpenAI API 的交互。openai-arkts
  • 初始化配置:
    const { Configuration, OpenAIApi } = require("openai");
    const configuration = new Configuration({
      apiKey: process.env.OPENAI_API_KEY,
    });
    const openai = new OpenAIApi(configuration);
    

1.2 多轮对话实现

  • 多轮对话通过将本地对话记录塞进 messages 实现,但可能会消耗大量 token。
  • 示例代码:(下面并非项目实际代码)
    let conversationHistory = [];
    
    async function getResponse(userInput) {
      conversationHistory.push({ role: "user", content: userInput });
      const response = await openai.createChatCompletion({
        model: "gpt-4",
        messages: conversationHistory,
      });
      const assistantMessage = response.data.choices[0].message;
      conversationHistory.push(assistantMessage);
      return assistantMessage.content;
    }
    

二、页面设计与组件

2.1 页面设计参考

2.2 简单实现目标

  • 基本功能
    • 对话界面和对话列表。
    • 支持复制对话内容。
    • 提供终止按钮。
    • 实现多轮对话记录存储。
    • 编辑对话记录(加入删除按钮)。
  • 次要功能
    • 编辑上一次对话内容。
    • 模型管理与切换。

2.3 页面组件划分

  • 对话界面(Chat Interface)
    • 对话气泡(Chat Bubble)。
    • 输入框(Input Box)。
    • 发送按钮(Send Button)。
    • 终止对话按钮(End Conversation Button)。
  • 对话列表(Conversation List)
    • 新建对话按钮(New Conversation Button)。
    • 历史对话项(Conversation Item)。

2.4 状态管理

  • 当前对话状态
    • 当前对话的所有消息内容。
    • 当前对话的唯一标识符(ID)。
    • 当前对话的状态(进行中或已终止)。
  • 对话列表状态
    • 所有对话的列表,每个对话包含其唯一标识符(ID)、标题、创建时间等信息。
    • 当前选中的对话 ID。

2.5 组件间交互

  • 对话列表:
    • 新建对话时,更新对话列表状态。
    • 点击历史对话项时,更新当前对话状态。
    • 删除对话时,从对话列表中移除该对话。
  • 对话界面:
    • 用户发送新消息时,更新当前对话状态。
    • 用户终止对话时,更新当前对话状态。

三、实体设计

3.1 实体类型

  • Model:模型相关的信息,包括调用 API 的相关信息。
  • Message:单次对话,按照 OpenAI API 提供的结构实现。
    { role: "user", content: userInput }
    
  • Conversation:创建一个 Conversation 时自动生成一个 UUID。
    interface Conversation {
      id: string;
      messages: Message[];
      createdAt: Date;
      updatedAt: Date;
    }
    
  • ConversationList:由 Conversation 构成的列表。

四、存储与读取对话记录

4.1 存储设计

  • 以 Conversation 为单位存储,key 为 UUID,value 为 Conversation 构成的 JSON。
  • 每轮对话完毕后,将 Conversation 插入 KV 存储,更新同理。

4.2 读取设计

  • 读取所有记录,按照默认顺序构成 ConversationList 对应的 JSON 结构体。

4.3 删除记录

  • 按照 UUID 删除记录。

五、状态管理与组件间通信

5.1 状态管理

  • 使用状态管理(如 V2)实现组件间通信。
  • 使用 @Local@Param@Event 实现双向绑定。

5.2 组件间通信

  • 使用 @Event 处理回调,实现子组件向父组件通信。
  • 示例:
    • 点击删除按钮时,通知父组件删除对应对话。

六、页面组件构建

6.1 组件结构

  • Sidebar 子组件
    • ConversationList。
    • 添加 Conversation 的按钮。
  • ConversationList
    • 滚动列表,由不定数量的子组件组成。
  • 子组件
    • ConversationTabBar:按钮 + 文本,支持删除操作。
    • ConversationInfo。
    • DeleteConversationButton。
  • Chat 子组件
    • ChatWindow:滚动列表,由不定数量的子组件组成。
    • Brick:包含 UserAvatar 和 TextBubble。
    • MessageInputBox:包含 MessageInput、SendButton 和 StopButton。

6.2 页面渲染逻辑

  • 使用条件渲染实现页面切换。
  • 渲染逻辑:
    • 本地值 !== 全局值时,更新并触发重新渲染。

七、数据流动与展示

7.1 数据流动

  • 父组件将数据传递给子组件。
  • 子组件通过事件冒泡通知父组件数据变更。

7.2 数据存储与读取

  • 使用 KV 存储对话列表和对话内容。
  • 使用全局常量共享 key,所有组件通过 key 共享数据。

八、问题与解决方案

8.1 AppStorageV2 问题

  • AppStorageV2 不支持异步操作,无法同步深层结构。
  • 解决方案:使用 KV 存储,不依赖 AppStorageV2。

8.2 子组件通信问题

  • 子组件无法直接通知父组件删除操作。
  • 解决方案:使用事件冒泡,子组件触发事件,父组件监听并处理。

8.3 页面渲染问题

  • 初始化时,静态数据优先级高于异步数据,导致渲染异常。
  • 解决方案:在 onPageShow() 中先赋值触发渲染,再建立数据连接。

九、下一步计划

9.1 功能实现

  • 实现列表刷新和对话记录的本地存储与读取。
  • 测试对话记录的存储与读取是否正常工作。

9.2 优化与重构

  • 重构 Chat 数据部分,使其与 ChatContent 兼容。
  • 实现对话列表与真实对话记录的一一对应。

9.3 页面切换

  • 实现点击侧边栏时,Chat 界面重新读取数据并渲染。
  • 实现删除侧边栏时,对应的 ChatContent 被删除。

9.4 数据对接

  • 确保数据成功对接,实现全局状态共享。
posted @ 2025-02-28 16:14  EmptyEmeraldTablet  阅读(65)  评论(0)    收藏  举报