当前位置: 代码网 > it编程>编程语言>Java > LLM(大语言模型)——Springboot集成文心一言、讯飞星火、通义千问、智谱清言

LLM(大语言模型)——Springboot集成文心一言、讯飞星火、通义千问、智谱清言

2024年07月28日 Java 我要评论
目录引言代码完整地址入参出参ControllerServiceService实现类模型Service入参转换类文心一言实现类讯飞星火实现类通义千问实现类智谱清言实现类引言本文将介绍如何使用Java语言,结合Spring Boot框架,集成国内热门大模型API,包括文心一言、讯飞星火、通义千问、智谱清言。在开始前,请确保您已经按照各模型官网的指引,完成了相应的资源申请和配置。这些资源是调用大模型API的必要凭证,务必妥善保管。接下来,我

目录

引言

代码完整地址

入参

 出参

controller

service

service实现类

 模型service

 入参转换类

文心一言实现类

讯飞星火实现类

 通义千问实现类

智谱清言实现类


引言

代码完整地址

https://github.com/wangsilingwsl/model-integrate.git

入参

package com.wsl.model.llm.api.dto;

import com.alibaba.fastjson.jsonobject;
import io.swagger.annotations.apimodelproperty;
import lombok.data;

import javax.validation.constraints.notnull;
import java.io.serializable;
import java.util.list;

/**
 * 聊天请求 dto
 *
 * @author wsl
 * @date 2024/2/20
 */
@data
public class chatrequestdto implements serializable {

    private static final long serialversionuid = 1l;

    @apimodelproperty(value = "聊天上下文信息", notes = "(1)最后一个message为当前请求的信息,前面的message为历史对话信息\n" +
            "(2)成员数目必须为奇数\n" +
            "(3)示例中message中的role值分别为user、assistant;奇数位message中的role值为user;偶数位值为assistant",
            example = "[{\"role\":\"user\",\"content\":\"你好\"},{\"role\":\"assistant\",\"content\":\"需要什么帮助\"},{\"role\":\"user\",\"content\":\"自我介绍下\"}]")
    @notnull(message = "聊天上下文信息不能为空")
    private list<messagedto> messages;

    @apimodelproperty(value = "模型人设", notes = "主要用于人设设定,例如,你是xxx公司制作的ai助手,最大20000字符", example = "你是一名天气助手,需要提供天气查询服务")
    private string system;

    @apimodelproperty(value = "请求参数", notes = "请求参数", example = "{\"key\":\"value\"}")
    private jsonobject params;
}

package com.wsl.model.llm.api.dto;

import io.swagger.annotations.apimodelproperty;
import lombok.allargsconstructor;
import lombok.data;

import java.io.serializable;

/**
 * 消息 dto
 *
 * @author wsl
 * @date 2024/2/20
 */
@data
@allargsconstructor
public class messagedto implements serializable {

    private static final long serialversionuid = 1l;

    @apimodelproperty(value = "角色", notes = "说明: user-用户, assistant-助手", example = "user")
    private string role;

    @apimodelproperty(value = "消息内容", notes = "说明: 消息内容", example = "你好")
    private string content;

}

 出参

package com.wsl.model.llm.api.vo;

import io.swagger.annotations.apimodelproperty;
import lombok.data;

import java.io.serializable;

/**
 * 聊天响应 vo
 *
 * @author wsl
 * @date 2024/2/20
 */
@data
public class chatresponsevo implements serializable {

    private static final long serialversionuid = 1l;

    @apimodelproperty(value = "结果", notes = "结果")
    private string result;

}

controller

package com.wsl.model.llm.api.controller;

import com.wsl.model.llm.api.dto.chatrequestdto;
import com.wsl.model.llm.api.service.iaiappservice;
import com.wsl.model.llm.api.vo.chatresponsevo;
import io.swagger.annotations.api;
import io.swagger.annotations.apioperation;
import io.swagger.annotations.apiparam;
import lombok.extern.slf4j.slf4j;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.web.bind.annotation.*;

/**
 * ai应用controller
 *
 * @author wsl
 * @date 2024/02/19
 */
@slf4j
@restcontroller
@api(tags = "ai应用")
@requestmapping("/llm/middle")
public class aiappcontroller {

    @autowired
    private iaiappservice service;

    @postmapping("/chat-message")
    @apioperation("向大模型发起对话请求")
    public chatresponsevo chatmessage(
            @apiparam(value = "模型类型(erniebot/sparkdesk/chatglm/qianwen)", required = true) @requestparam string modeltype,
            @apiparam(value = "消息参数", required = true) @requestbody chatrequestdto dto) {
        try {
            return service.chatmessage(modeltype, dto);
        } catch (exception e) {
            throw new runtimeexception(e);
        }
    }

}

service

package com.wsl.model.llm.api.service;

import com.wsl.model.llm.api.dto.chatrequestdto;
import com.wsl.model.llm.api.vo.chatresponsevo;

/**
 * ai应用service
 *
 * @author wsl
 * @date 2024/02/19
 */
public interface iaiappservice {

    /**
     * 向大模型发起对话请求-根据模型编码、用户id
     *
     * @param modeltype 模型类型
     * @param dto       消息参数
     * @return chatresponsevo
     * @throws exception 异常
     */
    chatresponsevo chatmessage(string modeltype, chatrequestdto dto) throws exception;

}

service实现类

package com.wsl.model.llm.api.service.impl;

import cn.hutool.core.collection.collutil;
import cn.hutool.core.util.strutil;
import cn.hutool.extra.spring.springutil;
import com.wsl.model.llm.api.constant.enums.modeltypeenum;
import com.wsl.model.llm.api.dto.chatrequestdto;
import com.wsl.model.llm.api.dto.messagedto;
import com.wsl.model.llm.api.service.iaiappservice;
import com.wsl.model.llm.api.service.modelservice;
import com.wsl.model.llm.api.vo.chatresponsevo;
import org.springframework.stereotype.service;

import java.util.list;

/**
 * ai应用serviceimpl
 *
 * @author wsl
 * @date 2024/02/19
 */
@service("aiappservice")
public class aiappserviceimpl implements iaiappservice {

    @override
    public chatresponsevo chatmessage(string modeltype, chatrequestdto dto) throws exception {
        this.checkmessages(dto.getmessages());
        // 根据枚举类modeltypeenum中的枚举值判断模型类型,并调用对应的模型实现类的方法
        modelservice modelservice = getmodelservice(modeltype);
        return modelservice.chatmessage(dto);
    }

    /**
     * 检查消息参数是否符合规范
     *
     * @param messages 消息参数
     */
    private void checkmessages(list<messagedto> messages) {
        if (collutil.isnotempty(messages)) {
            // messages参数个数必须为奇数并且奇数个数的消息role必须为user,偶数个数的消息role必须为assistant
            if (messages.size() % 2 == 0) {
                throw new runtimeexception("messages参数个数必须为奇数");
            }
            for (int i = 0; i < messages.size(); i++) {
                if (i % 2 == 0) {
                    if (!"user".equals(messages.get(i).getrole())) {
                        throw new runtimeexception("messages奇数参数的role必须为user");
                    }
                } else {
                    if (!"assistant".equals(messages.get(i).getrole())) {
                        throw new runtimeexception("messages偶数参数的role必须为assistant");
                    }
                }
            }
        }
    }


    /**
     * 根据模型类型获取对应的模型服务
     *
     * @param modeltype 模型类型
     * @return 模型服务
     */
    private modelservice getmodelservice(string modeltype) {
        try {
            // 将模型类型字符串转换为枚举值
            modeltypeenum modeltypeenum = modeltypeenum.valueof(modeltype);
            // 根据枚举值获取对应的实现类bean的名称
            string beanname = modeltypeenum.name();
            beanname = strutil.tocamelcase(beanname) + "service";
            return springutil.getbean(beanname);
        } catch (illegalargumentexception e) {
            throw new runtimeexception("模型类型错误");
        }
    }

}

 模型service

package com.wsl.model.llm.api.service;

import com.wsl.model.llm.api.dto.chatrequestdto;
import com.wsl.model.llm.api.vo.chatresponsevo;

/**
 * 模型服务
 *
 * @author wsl
 * @date 2024/2/19
 */
public interface modelservice {

    /**
     * 发起请求
     *
     * @param dto 请求参数
     * @return 返回值
     * @throws exception 异常
     */
    chatresponsevo chatmessage(chatrequestdto dto) throws exception;

}

 入参转换类

package com.wsl.model.llm.api.convert;

import cn.hutool.core.bean.beanutil;
import cn.hutool.core.collection.collutil;
import cn.hutool.core.util.strutil;
import com.alibaba.fastjson.jsonobject;
import com.wsl.model.llm.api.dto.*;
import org.mapstruct.mapper;
import org.mapstruct.factory.mappers;

import java.util.arraylist;
import java.util.list;

/**
 * 聊天请求转换器
 *
 * @author wsl
 * @date 2024/2/22
 */
@mapper
public interface chatrequestconvert {

    chatrequestconvert instance = mappers.getmapper(chatrequestconvert.class);

    /**
     * 通用请求转换为文心一言请求
     *
     * @param dto 通用请求
     * @return 文心一言请求
     */
    default jsonobject converterniebot(chatrequestdto dto) {
        erniebotdto erniebotdto = new erniebotdto();
        erniebotdto.setmessages(dto.getmessages());
        erniebotdto.setsystem(dto.getsystem());

        jsonobject jsonobject = new jsonobject();
        beanutil.copyproperties(erniebotdto, jsonobject);
        beanutil.copyproperties(dto.getparams(), jsonobject);
        return jsonobject;
    }

    /**
     * 通用请求转换为通义千问请求
     *
     * @param dto 通用请求
     * @return 通义千问请求
     */
    default qianwendto convertqianwen(chatrequestdto dto) {
        qianwendto qianwendto = new qianwendto();
        qianwendto.setmodel("qwen-turbo");
        qianweninputdto input = new qianweninputdto();
        string system = dto.getsystem();
        if (strutil.isnotblank(system)) {
            messagedto messagedto = new messagedto("system", system);
            dto.getmessages().add(0, messagedto);
        }
        input.setmessages(dto.getmessages());

        jsonobject parametersjsonobject = new jsonobject();
        beanutil.copyproperties(dto.getparams(), parametersjsonobject);

        qianwendto.setinput(input);
        qianwendto.setparameters(parametersjsonobject);

        return qianwendto;
    }

    /**
     * 通用请求转换为智谱清言请求
     *
     * @param dto 通用请求
     * @return 智谱清言请求
     */
    default jsonobject convertchatglm(chatrequestdto dto) {
        chatglmdto chatglmdto = new chatglmdto();

        string system = dto.getsystem();
        if (strutil.isnotblank(system)) {
            messagedto messagedto = new messagedto("system", system);
            dto.getmessages().add(0, messagedto);
        }

        chatglmdto.setmessages(dto.getmessages());
        chatglmdto.setmodel("glm-4");
        jsonobject jsonobject = new jsonobject();
        beanutil.copyproperties(chatglmdto, jsonobject);
        beanutil.copyproperties(dto.getparams(), jsonobject);
        return jsonobject;
    }

    /**
     * 通用请求转换为讯飞星火请求
     *
     * @param dto 通用请求
     * @return 讯飞星火请求
     */
    default sparkdeskdto convertsparkdesk(chatrequestdto dto) {
        sparkdeskdto sparkdeskdto = new sparkdeskdto();
        sparkdeskpayloaddto payload = new sparkdeskpayloaddto();
        sparkdeskpayloadmessagedto payloadmessage = new sparkdeskpayloadmessagedto();

        string system = dto.getsystem();
        if (strutil.isnotblank(system)) {
            messagedto messagedto = new messagedto("system", system);
            dto.getmessages().add(0, messagedto);
        }

        payloadmessage.settext(dto.getmessages());
        payload.setmessage(payloadmessage);

        sparkdeskparameterchatdto parameterchat = new sparkdeskparameterchatdto();
        parameterchat.setdomain("generalv3.5");
        jsonobject parameterchatjsonobject = new jsonobject();

        beanutil.copyproperties(parameterchat, parameterchatjsonobject);
        beanutil.copyproperties(dto.getparams(), parameterchatjsonobject);

        sparkdeskparameterdto parameter = new sparkdeskparameterdto();
        parameter.setchat(parameterchatjsonobject);

        sparkdeskdto.setpayload(payload);
        sparkdeskdto.setparameter(parameter);

        return sparkdeskdto;
    }

    /**
     * 通用请求转换为通义千问请求
     *
     * @param dto 通用请求
     * @return 通义千问请求
     */
    default faruidto convertfarui(chatrequestdto dto) {
        faruidto faruidto = new faruidto();

        list<messagedto> messages = dto.getmessages();
        string prompt = messages.get(messages.size() - 1).getcontent();

        faruiinputdto input = new faruiinputdto();
        if (messages.size() == 1) {
            messages = new arraylist<>();
        }
        if (collutil.isnotempty(messages)) {
            messages.remove(messages.size() - 1);
            list<faruihistorydto> history = convertfaruihistory(messages);
            input.sethistory(history);
        }
        input.setprompt(prompt);
        faruidto.setparameters(dto.getparams());
        faruidto.setinput(input);

        return faruidto;
    }

    /**
     * 通用消息转换为通义法睿历史消息
     *
     * @param messages 通用消息
     * @return 通义法睿历史消息
     */
    default list<faruihistorydto> convertfaruihistory(list<messagedto> messages) {
        list<faruihistorydto> history = new arraylist<>();
        int size = messages.size();
        for (int i = 0; i < size; i += 2) {
            faruihistorydto messagepair = new faruihistorydto();
            messagepair.setuser(messages.get(i).getcontent());
            if (i + 1 < size) {
                messagepair.setbot(messages.get(i + 1).getcontent());
            }
            history.add(messagepair);
        }
        return history;
    }

}

文心一言实现类

package com.wsl.model.llm.api.service.impl;

import cn.hutool.http.httprequest;
import cn.hutool.http.httpresponse;
import cn.hutool.http.httputil;
import cn.hutool.json.jsonutil;
import com.alibaba.fastjson.json;
import com.alibaba.fastjson.jsonobject;
import com.wsl.model.llm.api.convert.chatrequestconvert;
import com.wsl.model.llm.api.dto.chatrequestdto;
import com.wsl.model.llm.api.service.modelservice;
import com.wsl.model.llm.api.vo.chatresponsevo;
import lombok.extern.slf4j.slf4j;
import org.springframework.stereotype.service;

/**
 * 文心一言 大模型服务
 *
 * @author wsl
 * @link https://console.bce.baidu.com/tools/?_=1708497709522&u=qfdc#/api?product=ai&project=%e5%8d%83%e5%b8%86%e5%a4%a7%e6%a8%a1%e5%9e%8b%e5%b9%b3%e5%8f%b0&parent=ernie-bot&api=rpc%2f2.0%2fai_custom%2fv1%2fwenxinworkshop%2fchat%2fcompletions&method=post
 * @date 2024/2/19
 */
@service("erniebotservice")
@slf4j
public class erniebotserviceimpl implements modelservice {

    private string appsecret = "?";

    private string apikey = "?";

    private static final string token_url_template = "https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=%s&client_secret=%s";

    private static final string chat_url = "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions?access_token=%s";


    @override
    public chatresponsevo chatmessage(chatrequestdto dto) {
        jsonobject erniebot = chatrequestconvert.instance.converterniebot(dto);
        string requestbody = jsonutil.tojsonstr(erniebot);
        log.info("文心一言请求参数 erniebot request:{}", requestbody);

        httpresponse response = httputil.createpost(string.format(chat_url, getaccesstoken(apikey, appsecret)))
                .body(requestbody)
                .header("content-type", "application/json")
                .execute();

        if (response == null) {
            throw new runtimeexception("http response is null");
        }

        log.info("文心一言返回结果 erniebot response:{}", response.body());
        if (response.body() == null || response.body().trim().isempty()) {
            throw new runtimeexception("http response body is null or empty");
        }
        jsonobject jsonobject = json.parseobject(response.body());
        if (!jsonobject.containskey("result")) {
            throw new runtimeexception(jsonobject.tojsonstring(jsonobject));
        }
        chatresponsevo vo = new chatresponsevo();
        vo.setresult(jsonobject.getstring("result"));
        return vo;
    }

    /**
     * 从用户的ak,sk生成鉴权签名(access token)
     *
     * @param appid     应用id
     * @param appsecret 应用密钥
     * @return token
     */
    public string getaccesstoken(string appid, string appsecret) {
        string url = string.format(token_url_template, apikey, appsecret);

        try (httpresponse response = httprequest.post(url)
                .header("content-type", "application/json")
                .header("accept", "application/json")
                .execute()) {
            jsonobject jsonobject = json.parseobject(response.body());
            string accesstoken = jsonobject.getstring("access_token");
            return accesstoken;
        }
    }

}
package com.wsl.model.llm.api.dto;

import io.swagger.annotations.apimodelproperty;
import lombok.data;

import javax.validation.constraints.notnull;
import java.io.serializable;
import java.util.list;

/**
 * 文心一言 请求 dto
 *
 * @author wsl
 * @date 2024/2/20
 */
@data
public class erniebotdto implements serializable {

    private static final long serialversionuid = 1l;

    @apimodelproperty(value = "聊天上下文信息", notes = "说明:\n" +
            "(1)messages成员不能为空,1个成员表示单轮对话,多个成员表示多轮对话;例如:\n" +
            "· 1个成员示例,\"messages\": [ {\"role\": \"user\",\"content\": \"你好\"}]\n" +
            "· 3个成员示例,\"messages\": [ {\"role\": \"user\",\"content\": \"你好\"},{\"role\":\"assistant\",\"content\":\"需要什么帮助\"},{\"role\":\"user\",\"content\":\"自我介绍下\"}]\n" +
            "(2)最后一个message为当前请求的信息,前面的message为历史对话信息\n" +
            "(3)成员数目必须为奇数,成员中message的role值说明如下:奇数位messsage的role值必须为user或function,偶数位message的role值为assistant,第一个message的role不能是function。例如:\n" +
            "示例中message中的role值分别为user、assistant、user、assistant、user;奇数位(红框)message中的role值为user,即第1、3、5个message中的role值为user;偶数位(蓝框)值为assistant,即第2、4个message中的role值为assistant",
            example = "[{\"role\":\"system\",\"content\":\"您好,我是智谱清言,我可以帮您查询天气,您可以输入:查询{{destination}}的天气,查询{{destination}}未来{{num_day}}天的天气\"},{\"role\":\"user\",\"content\":\"查询三亚未来5天的天气\"},{\"role\":\"assistant\",\"content\":\"正在查询三亚未来5天的天气\"},{\"role\":\"assistant\",\"content\":\"三亚未来5天的天气是晴天\"}]")
    @notnull(message = "聊天上下文信息不能为空")
    private list<messagedto> messages;

    @apimodelproperty(value = "模型人设", notes = "主要用于人设设定,例如,你是xxx公司制作的ai助手,最大20000字符", example = "qwen-turbo")
    private string system;

    @apimodelproperty(value = "温度", notes = "较高的数值会使输出更加随机,而较低的数值会使其更加集中和确定。默认0.8,范围 [0, 1.0],不能为0", example = "0.8")
    private float temperature;

}

讯飞星火实现类

package com.wsl.model.llm.api.service.impl;

import com.alibaba.fastjson.json;
import com.alibaba.fastjson.jsonexception;
import com.alibaba.fastjson.jsonobject;
import com.wsl.model.llm.api.convert.chatrequestconvert;
import com.wsl.model.llm.api.dto.chatrequestdto;
import com.wsl.model.llm.api.dto.sparkdeskdto;
import com.wsl.model.llm.api.dto.sparkdeskheaderdto;
import com.wsl.model.llm.api.service.modelservice;
import com.wsl.model.llm.api.vo.chatresponsevo;
import lombok.extern.slf4j.slf4j;
import okhttp3.*;
import org.springframework.stereotype.service;

import javax.crypto.mac;
import javax.crypto.spec.secretkeyspec;
import java.net.url;
import java.nio.charset.standardcharsets;
import java.text.simpledateformat;
import java.util.*;
import java.util.concurrent.completablefuture;
import java.util.concurrent.timeunit;

/**
 * 讯飞星火 大模型服务
 *
 * @author wsl
 * @link https://www.xfyun.cn/doc/spark/web.html
 * @date 2024/2/19
 */
@service("sparkdeskservice")
@slf4j
public class sparkdeskserviceimpl implements modelservice {

    private string appid = "?";

    private string appsecret = "?";

    private string appkey = "?";

    public static final string host_url = "https://spark-api.xf-yun.com/v3.5/chat";

    @override
    public chatresponsevo chatmessage(chatrequestdto dto) throws exception {
        chatresponsevo vo = new chatresponsevo();
        sparkdeskdto sparkdeskdto = chatrequestconvert.instance.convertsparkdesk(dto);
        sparkdeskdto.setheader(new sparkdeskheaderdto(appid));

        string authurl = getauthurl(host_url, appkey, appsecret).replace("http://", "ws://").replace("https://", "wss://");
        request request = new request.builder().url(authurl).build();
        okhttpclient client = new okhttpclient.builder().build();
        stringbuilder sb = new stringbuilder();
        completablefuture<string> messagereceived = new completablefuture<>();
        string body = json.tojsonstring(sparkdeskdto);
        websocket websocket = client.newwebsocket(request, new websocketlistener() {
            @override
            public void onopen(websocket websocket, response response) {
                //发送消息
                log.info("讯飞星火请求参数 sparkdesk request:{}", body);
                websocket.send(body);
            }

            @override
            public void onmessage(websocket websocket, string text) {
                try {
                    jsonobject obj = json.parseobject(text);

                    // 使用optional来避免空指针异常,并在内容不存在时抛出异常
                    optional<string> contentoptional = optional.ofnullable(obj)
                            .map(jsonobject -> jsonobject.getjsonobject("payload"))
                            .map(payload -> payload.getjsonobject("choices"))
                            .map(choices -> choices.getjsonarray("text"))
                            .map(jsonarray -> jsonarray.getjsonobject(0))
                            .map(jsonobject -> jsonobject.getstring("content"));
                    string str = contentoptional.orelsethrow(() -> new runtimeexception(jsonobject.tojsonstring(obj)));

                    sb.append(str);

                    // 检查header和status字段
                    optional<long> statusoptional = optional.ofnullable(obj)
                            .map(jsonobject -> jsonobject.getjsonobject("header"))
                            .map(header -> header.getlong("status"));

                    // 如果status为2,则关闭websocket并完成completablefuture
                    if (statusoptional.ispresent() && statusoptional.get() == 2) {
                        websocket.close(1000, "closing websocket connection");
                        messagereceived.complete(text);
                    }
                } catch (jsonexception e) {
                    throw new runtimeexception(e);
                }
            }
        });
        messagereceived.get(60, timeunit.seconds);
        websocket.close(1000, "closing websocket connection");
        log.info("讯飞星火返回结果 sparkdesk response:{}", sb);
        vo.setresult(sb.tostring());
        return vo;
    }

    /**
     * 鉴权方法
     *
     * @param hosturl   服务地址
     * @param apikey    apikey
     * @param apisecret apisecret
     * @return 返回鉴权url
     * @throws exception 异常
     */

    public static string getauthurl(string hosturl, string apikey, string apisecret) throws exception {
        url url = new url(hosturl);
        // 时间
        simpledateformat format = new simpledateformat("eee, dd mmm yyyy hh:mm:ss z", locale.us);
        format.settimezone(timezone.gettimezone("gmt"));
        string date = format.format(new date());
        // 拼接
        string prestr = "host: " + url.gethost() + "\n" +
                "date: " + date + "\n" +
                "get " + url.getpath() + " http/1.1";
        // sha256加密
        mac mac = mac.getinstance("hmacsha256");
        secretkeyspec spec = new secretkeyspec(apisecret.getbytes(standardcharsets.utf_8), "hmacsha256");
        mac.init(spec);

        byte[] hexdigits = mac.dofinal(prestr.getbytes(standardcharsets.utf_8));
        // base64加密
        string sha = base64.getencoder().encodetostring(hexdigits);
        string authorization = string.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", apikey, "hmac-sha256", "host date request-line", sha);
        // 拼接地址
        httpurl httpurl = objects.requirenonnull(httpurl.parse("https://" + url.gethost() + url.getpath())).newbuilder().
                addqueryparameter("authorization", base64.getencoder().encodetostring(authorization.getbytes(standardcharsets.utf_8))).
                addqueryparameter("date", date).
                addqueryparameter("host", url.gethost()).
                build();
        return httpurl.tostring();
    }
}

package com.wsl.model.llm.api.dto;

import io.swagger.annotations.apimodelproperty;
import lombok.data;

import java.io.serializable;

/**
 * 讯飞星火 请求 dto
 *
 * @author wsl
 * @date 2024/2/20
 */
@data
public class sparkdeskdto implements serializable {

    private static final long serialversionuid = 1l;

    @apimodelproperty(value = "头部", notes = "头部")
    private sparkdeskheaderdto header;

    @apimodelproperty(value = "参数", notes = "参数")
    private sparkdeskparameterdto parameter;

    @apimodelproperty(value = "有效载荷", notes = "有效载荷")
    private sparkdeskpayloaddto payload;

}
package com.wsl.model.llm.api.dto;

import io.swagger.annotations.apimodelproperty;
import lombok.allargsconstructor;
import lombok.data;
import lombok.noargsconstructor;

import java.io.serializable;

/**
 * 讯飞星火 header dto
 *
 * @author wsl
 * @date 2024/2/20
 */
@data
@noargsconstructor
@allargsconstructor
public class sparkdeskheaderdto implements serializable {

    private static final long serialversionuid = 1l;

    @apimodelproperty(value = "应用appid", notes = "从开放平台控制台创建的应用中获取")
    private string app_id;

}

package com.wsl.model.llm.api.dto;

import io.swagger.annotations.apimodelproperty;
import lombok.data;

import java.io.serializable;

/**
 * 讯飞星火 聊天 参数 dto
 *
 * @author wsl
 * @date 2024/2/20
 */
@data
public class sparkdeskparameterchatdto implements serializable {

    private static final long serialversionuid = 1l;

    @apimodelproperty(value = "指定访问的领域", notes = "generalv3指向v3版本;generalv3.5指向v3.5版本")
    private string domain;

    @apimodelproperty(value = "温度", notes = "较高的数值会使输出更加随机,而较低的数值会使其更加集中和确定。默认0.8,范围 [0, 2.0],不能为0", example = "0.8")
    private float temperature;

    @apimodelproperty(value = "最大标记", notes = "模型回答的tokens的最大长度;取值范围[1,8192],默认为2048", example = "2048")
    private integer max_tokens;

}
package com.wsl.model.llm.api.dto;

import com.alibaba.fastjson.jsonobject;
import io.swagger.annotations.apimodelproperty;
import lombok.data;

import java.io.serializable;

/**
 * 讯飞星火 参数 dto
 *
 * @author wsl
 * @date 2024/2/20
 */
@data
public class sparkdeskparameterdto implements serializable {

    private static final long serialversionuid = 1l;

    @apimodelproperty(value = "聊天参数", notes = "聊天参数")
    private jsonobject chat;

}
package com.wsl.model.llm.api.dto;

import io.swagger.annotations.apimodelproperty;
import lombok.data;

import java.io.serializable;

/**
 * 讯飞星火 有效载荷 dto
 *
 * @author wsl
 * @date 2024/2/20
 */
@data
public class sparkdeskpayloaddto implements serializable {

    private static final long serialversionuid = 1l;

    @apimodelproperty(value = "消息", notes = "消息")
    private sparkdeskpayloadmessagedto message;

}

package com.wsl.model.llm.api.dto;

import lombok.data;

import javax.validation.constraints.notnull;
import java.io.serializable;
import java.util.list;

/**
 * 讯飞星火 有效载荷 消息 dto
 *
 * @author wsl
 * @date 2024/2/20
 */
@data
public class sparkdeskpayloadmessagedto implements serializable {

    private static final long serialversionuid = 1l;

    @notnull(message = "聊天上下文信息不能为空")
    private list<messagedto> text;

}

 通义千问实现类

package com.wsl.model.llm.api.service.impl;

import cn.hutool.http.httprequest;
import com.alibaba.fastjson.json;
import com.alibaba.fastjson.jsonobject;
import com.wsl.model.llm.api.convert.chatrequestconvert;
import com.wsl.model.llm.api.dto.chatrequestdto;
import com.wsl.model.llm.api.dto.qianwendto;
import com.wsl.model.llm.api.service.modelservice;
import com.wsl.model.llm.api.vo.chatresponsevo;
import lombok.extern.slf4j.slf4j;
import org.springframework.stereotype.service;

import java.util.optional;

/**
 * 通义千问 大模型服务
 *
 * @author wsl
 * @link https://help.aliyun.com/zh/dashscope/developer-reference/api-details?spm=a2c4g.11186623.0.0.6922140btyj6qj#602895ef3dtl1
 * @date 2024/2/19
 */
@slf4j
@service("qianwenservice")
public class qianwenserviceimpl implements modelservice {

    private string apikey = "?";

    @override
    public chatresponsevo chatmessage(chatrequestdto dto) {
        qianwendto qianwen = chatrequestconvert.instance.convertqianwen(dto);
        string url = "https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation";
        string json = json.tojsonstring(qianwen);
        log.info("通义千问请求参数 qianwen request:{}", json);

        string result = httprequest.post(url)
                .header("authorization", "bearer " + apikey)
                .header("content-type", "application/json")
                .body(json)
                .execute().body();

        log.info("通义千问返回结果 qianwen response:{}", result);
        chatresponsevo vo = new chatresponsevo();
        jsonobject jsonobject = json.parseobject(result);
        optional<string> textoptional = optional.ofnullable(jsonobject.getjsonobject("output"))
                .map(output -> output.getstring("text"));

        if (!textoptional.ispresent()) {
            throw new runtimeexception(jsonobject.tojsonstring(jsonobject));
        }

        vo.setresult(textoptional.get());
        return vo;

    }

}
package com.wsl.model.llm.api.dto;

import io.swagger.annotations.apimodelproperty;
import lombok.data;

import javax.validation.constraints.notnull;
import java.io.serializable;
import java.util.list;

/**
 * 通义千问 输入 dto
 *
 * @author wsl
 * @date 2024/2/20
 */
@data
public class qianweninputdto implements serializable {

    private static final long serialversionuid = 1l;

    @apimodelproperty(value = "聊天上下文信息", notes = "说明:\n" +
            "(1)messages成员不能为空,1个成员表示单轮对话,多个成员表示多轮对话;例如:\n" +
            "· 1个成员示例,\"messages\": [ {\"role\": \"user\",\"content\": \"你好\"}]\n" +
            "· 3个成员示例,\"messages\": [ {\"role\": \"user\",\"content\": \"你好\"},{\"role\":\"assistant\",\"content\":\"需要什么帮助\"},{\"role\":\"user\",\"content\":\"自我介绍下\"}]\n" +
            "(2)最后一个message为当前请求的信息,前面的message为历史对话信息\n" +
            "(3)成员数目必须为奇数,成员中message的role值说明如下:奇数位messsage的role值必须为user或function,偶数位message的role值为assistant,第一个message的role不能是function。例如:\n" +
            "示例中message中的role值分别为user、assistant、user、assistant、user;奇数位(红框)message中的role值为user,即第1、3、5个message中的role值为user;偶数位(蓝框)值为assistant,即第2、4个message中的role值为assistant",
            example = "[{\"role\":\"system\",\"content\":\"您好,我是智谱清言,我可以帮您查询天气,您可以输入:查询{{destination}}的天气,查询{{destination}}未来{{num_day}}天的天气\"},{\"role\":\"user\",\"content\":\"查询三亚未来5天的天气\"},{\"role\":\"assistant\",\"content\":\"正在查询三亚未来5天的天气\"},{\"role\":\"assistant\",\"content\":\"三亚未来5天的天气是晴天\"}]")
    @notnull(message = "聊天上下文信息不能为空")
    private list<messagedto> messages;

}

智谱清言实现类

package com.wsl.model.llm.api.service.impl;

import cn.hutool.http.httpresponse;
import cn.hutool.http.httputil;
import cn.hutool.json.jsonutil;
import com.alibaba.fastjson.json;
import com.alibaba.fastjson.jsonarray;
import com.alibaba.fastjson.jsonobject;
import com.auth0.jwt.jwt;
import com.auth0.jwt.algorithms.algorithm;
import com.wsl.model.llm.api.convert.chatrequestconvert;
import com.wsl.model.llm.api.dto.chatrequestdto;
import com.wsl.model.llm.api.service.modelservice;
import com.wsl.model.llm.api.vo.chatresponsevo;
import lombok.extern.slf4j.slf4j;
import org.springframework.stereotype.service;

import java.util.date;
import java.util.hashmap;
import java.util.map;
import java.util.optional;

/**
 * 智谱清言 大模型服务
 *
 * @author wsl
 * @link https://open.bigmodel.cn/dev/api#glm-4
 * @date 2024/2/19
 */
@slf4j
@service("chatglmservice")
public class chatglmserviceimpl implements modelservice {

    private string apikey = "?";

    @override
    public chatresponsevo chatmessage(chatrequestdto dto) throws exception {
        jsonobject chatglm = chatrequestconvert.instance.convertchatglm(dto);
        string url = "https://open.bigmodel.cn/api/paas/v4/chat/completions";
        string requestbody = jsonutil.tojsonstr(chatglm);
        log.info("智谱清言请求参数 chatglm request:{}", requestbody);

        httpresponse response = httputil.createpost(url).body(requestbody).header("content-type", "application/json").header("authorization", "bearer " + generatetoken(apikey, 3600)).execute();

        log.info("智谱清言返回结果 chatglm response:{}", optional.ofnullable(response).map(httpresponse::body).orelse(""));

        chatresponsevo vo = new chatresponsevo();
        optional<jsonobject> jsonobject = optional.ofnullable(json.parseobject(response.body()));
        jsonobject.ifpresent(json -> {
            optional<jsonarray> choices = optional.ofnullable(json.getjsonarray("choices"));
            choices.ifpresent(choicearray -> {
                if (!choicearray.isempty()) {
                    optional<jsonobject> firstchoicemessage = optional.ofnullable(choicearray.getjsonobject(0).getjsonobject("message"));
                    firstchoicemessage.ifpresent(message -> {
                        string content = message.getstring("content");
                        if (content != null) {
                            vo.setresult(content);
                        } else {
                            throw new runtimeexception(response.body());
                        }
                    });
                }
            });
            throw new runtimeexception(response.body());
        });
        return vo;
    }

    /**
     * 生成token
     *
     * @param apikey     apikey
     * @param expseconds 过期时间
     * @return token
     * @throws exception 异常
     */
    public static string generatetoken(string apikey, int expseconds) throws exception {
        string[] parts = apikey.split("\\.");
        if (parts.length != 2) {
            throw new exception("invalid apikey");
        }

        string id = parts[0];
        string secret = parts[1];

        map<string, object> payload = new hashmap<>(16);
        payload.put("api_key", id);
        payload.put("exp", new date(system.currenttimemillis() + expseconds * 1000));
        payload.put("timestamp", new date(system.currenttimemillis()));

        algorithm algorithm = algorithm.hmac256(secret);
        return jwt.create().withheader(new hashmap<string, object>(16) {{
            put("alg", "hs256");
            put("sign_type", "sign");
        }}).withpayload(payload).sign(algorithm);
    }

}

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com