随笔- 当ChatGPT遇见SpreadJS (代码篇)

上一篇博文当ChatGPT遇见SpreadJS中,我们介绍了当ChatGPT遇上SpreadJS之后,我们都有哪些应用场景,同时给大家展示了这些场景的实际使用效果。着急的小伙伴可能早已按捺不住内心的激动,想看一看为了达到这种结合,我们需要什么样的代码来实现。本文将逐一揭晓。

发布于 2023/06/12 14:53

SpreadJS

上一篇博文当ChatGPT遇见SpreadJS中,我们介绍了当ChatGPT遇上SpreadJS之后,我们都有哪些应用场景,同时给大家展示了这些场景的实际使用效果。着急的小伙伴可能早已按捺不住内心的激动,想看一看为了达到这种结合,我们需要什么样的代码来实现。本文将逐一揭晓。

OpenAI接口调用

为了跟ChatGPT进行代码级别的交互,首先你需要注册OpenAI,并获取apiKey,关于这部分的说明,网上有很多现成的文章,我们这里不再重复说明。

调用OpenAI接口,OpenAI给提供了现成的NodeJS的库,可以通过npm直接安装

$ npm install openai

为了快速验证Demo,我们直接在Vue项目的前端页面中使用这个OpenAI的库,经测试功能正常。不过话说回来,在正常的项目中的使用场景,这部分的代码调用应当在服务端实现。(不然你的apiKey就公之于众了)

对于单一提问,创建一个Completion即可,Completion.data.choices会返回对应的信息,以下是官方提供的调用示例,需要设置apiKey

const { Configuration, OpenAIApi } = require("openai");

const configuration = new Configuration({
  apiKey: process.env.OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);

const completion = await openai.createCompletion({
  model: "text-davinci-003",
  prompt: "Hello world",
});
console.log(completion.data.choices[0].text);

对于对话聊天,需要使用createChatCompletion

openai.createChatCompletion({
  model:"gpt-3.5-turbo",
  messages:[
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": "Who won the world series in 2020?"},
    {"role": "assistant", "content": "The Los Angeles Dodgers won the World Series in 2020."},
    {"role": "user", "content": "Where was it played?"}
  ]})

需要注意,OpenAI不负责记录数据,也就是说每次请求是无状态的。因此如果需要GPT知道聊天的的上下文,在执行每一次的请求时需要将之前的聊天记录全部放到messages中。
在messages中有三个角色system、user和assistant。简单来说
user: 代表用户发的消息,即用户的提问或者指令
assistant: 就是GPT,需要将GPT上一次的回复或者反馈加入到messages中
system: 代表系统或者客户端通过代码发出的消息。系统消息的目的是给 assistant 提供进一步的指导或者指示,从而让 assistant 作出更好的响应。
一次对话可以从system开始,指导此次对话的主题,然后交替的追加 user 和 assistant 类型的消息。

可以看到createCompletion和createChatCompletion使用了text-davinci-003和gpt-3.5-turbo两个不同的model,那么两者有什么不一样呢?

text-davinci-003和gpt-3.5-turbo都是OpenAI的语言模型,它们都是基于GPT-3的。text-davinci-003是GPT-3的改进版,支持更长的上下文窗口(即4097个标记),并且使用了更新的数据集 。gpt-3.5-turbo是在text-davinci-003的基础上进行了改进,针对聊天应用进行了优化 。 从效果来看,gpt-3.5-turbo比text-davinci-003更优秀。而且,gpt-3.5-turbo的API价格只有text-davinci-003的1/10 。

从官方的表述来看gpt-3.5-turbo更强大(强大但是便宜?),但是在实际测试中,对于类似生成公式这样的明确指令,text-davinci-003表现的更好,问题回复简洁直接,便于程序分析使用,而针对聊天优化的gpt-3.5-turbo有时还会返回“请稍等”的反馈。

二.创建GPT公式

对于OpenAI的请求是异步的,因此这里需要用到SpreadJS的异步函数来创建自定义的GPT公式。对于返回一个值的公式可以直接设置结果,如果返回的是区域数据,可以使用动态数组
动态数组功能在SpreadJS中是默认关闭的,需要设置开启,开启的代码如下所示:

workbook.options.allowDynamicArray = true;

以GPT.FILTER公式为例,演示通过使用OpenAI对于选择区域的数据进行过滤,公式接收两个参数,选择区域和过滤条件的文字描述
设置acceptsReference配置公式参数是否是引用区域。

var GPT_Filter = function () {};
GPT_Filter.prototype = new GC.Spread.CalcEngine.Functions.AsyncFunction('GPT.FILTER', 2, 2, {
        description: "对选择的数据区域做描述行的过滤",
        parameters: [
            {
                name: "数据区域"
            },
            {
                name: "过滤条件描述"
            }]});
GPT_Filter.prototype.defaultValue = function () { return 'Loading...'; };
GPT_Filter.prototype.acceptsArray = function () {
    return true;
}
GPT_Filter.prototype.acceptsReference = function (argIndex) {
    return true;
}
GPT_Filter.prototype.evaluateAsync = function (context, range, desc) {
    if (!range || !desc) {
        return GC.Spread.CalcEngine.Errors.NotAvailable;
    }
    
    let tempArray = range.toArray && range.toArray();
    if (!Array.isArray(tempArray)) {
        return GC.Spread.CalcEngine.Errors.NotAvailable;
    }

    const response = openai.createCompletion({
        model: "text-davinci-003",
        prompt: "对最后的JSON数据,过滤" + desc + ",返回和原来结构一样的双层JSON数组。\n" + JSON.stringify(tempArray),
        max_tokens: 500,
        temperature: 0.5
    });
    response.then(function(completion){
        let array = JSON.parse(completion.data.choices[0].text.trim())
        context.setAsyncResult(new GC.Spread.CalcEngine.CalcArray(array));
    })
};

在调用OpenAI时,将公式引用区域的数据转换成二维数组的文本,同时通过文字描述,让api返回一个同样的二维数据json
在接受到json后parse成Arary,最后创建动态数组对象,设置到单元格中。

这里需要注意一点,不要在evaluateAsync中使用await,await会将promise对象直接return,而异步函数只有接收不到return值才会显示defaultValue。

三. 其他应用场景

对于数据分析建议,和Filter类似,将数据stringfly后提交OpenAI,除了用二维数组,也可以通过getCsv获取带有换行的表格数据。

代码也同步在GitHub上。

可以关注https://github.com/SpreadJSHero以获取最新SpreadJS案例资源

SpreadJS | 下载试用

纯前端表格控件SpreadJS,兼容 450 种以上的 Excel 公式,具备“高性能、跨平台、与 Excel 高度兼容”的产品特性,备受华为、苏宁易购、天弘基金等行业龙头企业的青睐,并被中国软件行业协会认定为“中国优秀软件产品”。SpreadJS 可为用户提供类 Excel 的功能,满足表格文档协同编辑、 数据填报、 类 Excel 报表设计等业务场景需求,极大的降低企业研发成本和项目交付风险。

如下资源列表,可以为您评估产品提供帮助:

相关产品
推荐相关案例
推荐相关资源
关注微信
葡萄城社区二维码

关注“葡萄城社区”

活字格低代码二维码

关注“活字格低代码”

想了解更多信息,请联系我们, 随时掌握技术资源和产品动态