Electron Forge【实战】百度智能云千帆大模型 —— AI聊天

1. 获取 Access Key 与 Secret Key

登录百度智能云
https://login.bce.baidu.com/



2. 安装node.js sdk

ts 复制代码
npm install @baiducloud/qianfan

3. src/main.ts

ts 复制代码
import { setupIPC } from "./ipc";

在 const mainWindow 之后

ts 复制代码
 setupIPC(mainWindow);

4. src/ipc.ts

ts 复制代码
import { ipcMain, BrowserWindow } from "electron";
import { createProvider } from "./providers/createProvider";

interface CreateChatProps {
  messages: {
    role: string;
    content: string;
    imagePath?: string;
  }[];
  providerName: string;
  selectedModel: string;
  messageId: number;
}

export function setupIPC(mainWindow: BrowserWindow) {
  ipcMain.on("start-chat", async (event, data: CreateChatProps) => {
    const { providerName, messages, messageId, selectedModel } = data;

    try {
      const provider = createProvider(providerName);
      const stream = await provider.chat(messages, selectedModel);
      for await (const chunk of stream) {
        const content = {
          messageId,
          data: chunk,
        };
        mainWindow.webContents.send("update-message", content);
      }
    } catch (error) {
      const errorContent = {
        messageId,
        data: {
          is_end: true,
          result:
            error instanceof Error ? error.message : "与AI服务通信时发生错误",
          is_error: true,
        },
      };
      mainWindow.webContents.send("update-message", errorContent);
    }
  });
}

5. src/providers/createProvider.ts

下方代码中,留意更改为第1步得到的 accessKey 和 secretKey

ts 复制代码
import { QianfanProvider } from "./QianfanProvider";

export function createProvider(providerName: string) {
  // 定义 QianfanConfig 接口
  interface QianfanConfig {
    accessKey: string;
    secretKey: string;
  }

  // 定义完整的配置接口
  interface Config {
    qianfan: QianfanConfig;
  }

  const providerConfigs: Config = {
    qianfan: {
      accessKey: "填第1步获取的accessKey",
      secretKey: "填第1步获取的secretKey",
    },
  };

  const providerConfig = providerConfigs[providerName as keyof Config] || {};
  switch (providerName) {
    case "qianfan":
      if (!providerConfig.accessKey || !providerConfig.secretKey) {
        throw new Error(
          "缺少千帆API配置:请在设置中配置 accessKey 和 secretKey"
        );
      }
      return new QianfanProvider(
        providerConfig.accessKey,
        providerConfig.secretKey
      );
    default:
      throw new Error(`不支持的AI服务提供商: ${providerName}`);
  }
}

6. src/providers/QianfanProvider.ts

ts 复制代码
import { ChatCompletion } from "@baiducloud/qianfan";

interface ChatMessageProps {
  role: string;
  content: string;
  imagePath?: string;
}

export class QianfanProvider {
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  private client: any;
  constructor(accessKey: string, secretKey: string) {
    this.client = new ChatCompletion({
      QIANFAN_ACCESS_KEY: accessKey,
      QIANFAN_SECRET_KEY: secretKey,
      ENABLE_OAUTH: true,
    });
  }
  async chat(messages: ChatMessageProps[], model: string) {
    const stream = await this.client.chat(
      {
        messages,
        stream: true,
      },
      model
    );
    return {
      async *[Symbol.asyncIterator]() {
        for await (const chunk of stream) {
          yield chunk;
        }
      },
    };
  }
}

7. src/preload.ts

ts 复制代码
import { ipcRenderer, contextBridge } from "electron";

contextBridge.exposeInMainWorld("electronAPI", {
  startChat: (data: CreateChatProps) => ipcRenderer.send("start-chat", data),
  onUpdateMessage: (callback: OnUpdatedCallback) =>
    ipcRenderer.on("update-message", (_event, value) => callback(value)),
});

interface CreateChatProps {
  messages: {
    role: string;
    content: string;
    imagePath?: string;
  }[];
  providerName: string;
  selectedModel: string;
  messageId: number;
}

interface UpdatgedStreamData {
  messageId: number;
  data: {
    is_end: boolean;
    result: string;
    is_error?: boolean;
  };
}

type OnUpdatedCallback = (data: UpdatgedStreamData) => void;

8. 页面中使用

ts 复制代码
// 访问 AI 模型,获取答案
const get_AI_answer = async (answerIndex: number) => {
  await (window as any).electronAPI.startChat({
    messageId: answerIndex,
    providerName: convsersation.value!.AI_providerName,
    selectedModel: convsersation.value!.AI_modelName,
    // 发给AI模型的消息需移除最后一条加载状态的消息,使最后一条消息为用户的提问
    messages: convsersation
      .value!.msgList.map((message) => ({
        role: message.type === "question" ? "user" : "assistant",
        content: message.content,
      }))
      .slice(0, -1),
  });
};

完整使用范例见
https://blog.csdn.net/weixin_41192489/article/details/146472170

相关推荐
EndingCoder15 小时前
Electron 安全性最佳实践:防范常见漏洞
前端·javascript·electron·前端框架·node.js·桌面端
EndingCoder1 天前
Electron 性能优化:内存管理和渲染效率
javascript·性能优化·electron·前端框架
至善迎风1 天前
使用国内镜像源解决 Electron 安装卡在 postinstall 的问题
前端·javascript·electron
mit6.8241 天前
[Upscayl图像增强] docs | 前端 | Electron工具(web->app)
前端·人工智能·electron·状态模式
小妖6662 天前
怎么用 tauri 创建一个桌面应用程序(Electron)
前端·javascript·electron
EndingCoder2 天前
单元测试:Jest 与 Electron 的结合
javascript·electron·单元测试·前端框架
小浣熊喜欢揍臭臭2 天前
react+umi项目如何添加electron的功能
javascript·electron·react
EndingCoder3 天前
调试技巧:Chrome DevTools 与 Node.js Inspector
javascript·网络·electron·node.js·vim·chrome devtools
EndingCoder3 天前
数据库集成:使用 SQLite 与 Electron
数据库·electron·sqlite·前端框架·node.js
妮妮喔妮4 天前
如何把HTML转化成桌面Electron
前端·javascript·electron