前端JS接入阿里云通义千问/百炼大模型

852 阅读2分钟

原文地址:前端JS接入阿里云通义千问/百炼大模型

前端JS接入阿里云通义千问/百炼大模型

本文仅以阿里云百炼大模型为例,阿里其他大模型如通义千问接入方式类似。

百炼大模型文档地址:help.aliyun.com/document_de…

作者的TS写得比较菜(初学者),不足之处还望多多指正

安装依赖

mitt 不是必需的,可以自行删除相关代码

npm i @microsoft/fetch-event-source mitt

tyqw.ts


/**
 * 阿里云通义千问接入 bodyData目前对接的百炼平台,对接通义千问需要修改下bodyData
 * @auth chinjiaqing
 */
import {EventSourceMessage, fetchEventSource} from "@microsoft/fetch-event-source";
import mitt, {Emitter, EventType} from "mitt";

// Tyqw事件类型枚举
export enum TyqwEvent {
    MESSAGE = 'message',
    ERROR = 'error'
}

// 通用事件处理类型
type EmitterEvents = {
    [key in EventType]?: (data: any) => void;
}

// 消息类型
interface MessageMap {
    [TyqwEvent.MESSAGE]: Message;
    [TyqwEvent.ERROR]: Error;
}

// Tyqw事件监听类型
type TyqwEvents = {
    [key in TyqwEvent]: key extends keyof MessageMap ? MessageMap[key] : never;
} & EmitterEvents;

interface Message {
    output?: {
        session_id: string;
        text: string;
        thoughts?: Array<{
            action?: string;
            arguments?: string;
            [key: string]: any;
        }>;
        finish_reason: 'null' | 'stop';
    };

    [key: string]: any;
}

// 请求体数据接口
interface FetchBodyData {
    input: {
        prompt: string;
        session_id: string;
    };
    parameters?: {
        has_thoughts?: boolean;
    };
}

// 默认请求体数据
const defaultBodyData: FetchBodyData = {
    input: {
        prompt: '',
        session_id: ''
    },
    parameters: {
        has_thoughts: false
    }
};

class Tyqw {
    // 应用ID
    private readonly appId: string = 'your appid';
    // 会话ID键值
    private readonly sessionIdKey: string = 'tyqw_sessionId';
    // 请求体数据
    private bodyData: FetchBodyData = {...defaultBodyData};
    // 事件发射器
    private emitter: Emitter<TyqwEvents> = mitt<TyqwEvents>();

    // 请求的url
    private get api(): string {
        return `/tyqw/api/v1/apps/${this.appId}/completion`;
    }

    // 获取会话的sessionId
    get sessionId(): string | null {
        return localStorage.getItem(this.sessionIdKey);
    }

    /**
     * 获取token, 后续开发应该对接真正的获取token流程
     * @private
     * @returns {string} token
     */
    private getToken(): string {
        return 'your token';
    }

    /**
     * 转换请求体数据格式
     * @private
     * @param {string} text 要发送的文本
     * @returns {string} 转换后的请求体数据
     */
    private transferBodyData(text: string): string {
        this.bodyData.input.prompt = text;
        this.bodyData.input.session_id = this.sessionId;
        return JSON.stringify(this.bodyData);
    }

    /**
     * 发送消息
     * @param {string} text 要发送的文本 不能为空
     * @returns Promise
     * @example
     * tyqw.send('你叫什么名字')
     */
    public async send(text: string): Promise<void> {
        if (!text || !text.trim()) return;
        const {emitter} = this;
        const bodyData: string = this.transferBodyData(text);
        const controller: AbortController = new AbortController();

        return fetchEventSource(this.api, {
            method: "POST",
            headers: {
                "Authorization": `Bearer ${this.getToken()}`,
                "Content-Type": "application/json",
            },
            body: bodyData,
            signal: controller.signal,
            onmessage: (e: EventSourceMessage) => {
                try {
                    const data: Message = JSON.parse(e.data);
                    if (data?.output?.session_id) {
                        this.setSessionId(data.output.session_id);
                    }
                    emitter.emit(TyqwEvent.MESSAGE, data);
                    console.log("on message: ", data);
                } catch (err) {
                    console.error('通义千问 message 解析出错', err);
                    emitter.emit(TyqwEvent.ERROR, err as Error);
                }
            },
            onclose: () => {
                controller.abort();
            },
            onerror: (err: Error) => {
                console.error('通义千问 请求出错', err);
                controller.abort();
                emitter.emit(TyqwEvent.ERROR, err);
            },
        });
    }

    /**
     * 设置sessionId
     * @param {string} value sessionId
     */
    public setSessionId(value: string): void {
        localStorage.setItem(this.sessionIdKey, value);
    }

    /**
     * 清除sessionId 用于开启新的对话,清除上下文关系
     */
    public clearSessionId(): void {
        localStorage.removeItem(this.sessionIdKey);
    }

    /**
     * 事件监听
     * @param {T extends TyqwEvent} event 监听的事件类型
     * @param {(data: TyqwEvents[T]) => void} callback 回调函数
     */
    public on<T extends TyqwEvent>(event: T, callback: (data: TyqwEvents[T]) => void): void {
        this.emitter.on(event, callback);
    }

    /**
     * 取消事件监听
     * @param {T extends TyqwEvent} event 监听的事件类型
     * @param {(data: TyqwEvents[T]) => void} [callback] 回调函数
     */
    public off<T extends TyqwEvent>(event: T, callback?: (data: TyqwEvents[T]) => void): void {
        this.emitter.off(event, callback);
    }
}

export default Tyqw;

使用示例


import Tyqw, { TyqwEvent } from './tyqw.js';

const tyqw = new Tyqw();

tyqw.on(TyqwEvent.MESSAGE, (data) => {
    console.log(`on message: `,data)
})

tyqw.on(TyqwEvent.ERROR, (err) => {
    console.error('on error: ',err)
})

tyqw.send('你好')