chatgpt api + function calling + 高德天气API + google custom search【联谷歌,联高德】

news2024/11/17 13:32:59

 

OpenAI 发布几个重磅更新

1、 开放 16k 上下文的 GPT-3.5-Turbo 模型(gpt-3.5-turbo-16k),是目前的4倍
2、 新的 GPT-4 和 3.5 Turbo 模型
3、Chat Completions API 中的新增加函数调用功能 (实时获取网络数据成为可能)
4、embeddings模型的成本降低75%
5、gpt-3.5-turbo的输入token成本降低了25% (开发者的福音)

其中最令人兴奋的功能应该当属函数调用功能,我们都知道ChatGPT训练的数据是基于2021年之前的,你要问一些实时性相关的问题就没法回答你了,而函数调用让实时获取网络数据成为可能,比如查询天气预报、查股票、推荐个近期的电影之类的。

哪些模型支持函数调用?

gpt-3.5-turbo-0613gpt-4-0613 这两个模型都支持函数调用。

函数调用的流程是什么?

1、用户发起提问时,调用一次带有函数描述的completions接口,gpt会判断是否支持调用函数,如果可以就从用户的提问信息中提取出函数所需要的参数。
2、开发者拿到gpt提取出来的参数后自行调用函数并返回结果
3、将函数的返回结果再次发给GPT做总结归纳为自然语言

需要注意的地方:

  1. 整个过程gpt会执行两次,第一次调用从问题中提取函数参数,第二次对函数返回结果做归纳总结
  2. 函数调用并不是由gpt调用,而是开发者来调用

举个真实例子

这里我以实时获取天气预报为例子演示函数调用的流程,天气预报接口我用的第三方高德API,免费,每天几千次的调用额度。申请注册流程这里省略,自行研究。

这个函数就是用来查询天气情况的,参数 city_name 是城市的名字,因为高德API只支持通过城市代码查天气,所以我这里做了一次根据城市名找到对应编码的查询

接口返回的结果中包含有温度(temperature)、风度(windpower)、风向(winddirection)、湿度(humidity)、天气(weather)等字段信息。

天气函数准备好后,用户开始提问:“深圳天气如何?“, 第一次调用`ChatCompletion`接口。

这里我们指定了一个functions 参数,该参数描述了函数的名字以及参数类型,比如我们这里定义了city_name的参数,gpt 就会从用户问题中提取出city_name。 

gpt 给我们返回的message中有function_call 字段,而且 arguments 里面提取了city_name这个字段的值。

第二步:从返回结果中提取参数后调用函数, 这个过程不是交给gpt处理,而是由开发者自己调用该函数,gpt做的事情是把函数需要的参数提取出来。

注意,这里要将函数调用返回的结果做一些json转换

第三交步:把返回结果给gpt做总结归纳

注意messages列表中最后一条消息中role角色是 function, 最后得到的结果second_response中的content内容为:

 

 

 

 

 

 

const functionCalling = async ({
  isUseGoogleSearch,
  params,
  messages,
  historyMessage,
  model,
}) => {

  const searchGoogleGptFunction = {
    name: 'search_google_when_gpt_cannot_answer',
    description:
      '当 gpt 遇到无法回答的或者需要搜索引擎协助回答时从 google 搜索',
    parameters: {
      type: 'object',
      properties: {
        query: {
          type: 'string',
          description: '搜索句,支持中文或者英文',
        },
      },
    },
  }

  const getCurrentWeather = {
    name: 'get_current_weather',
    description: '获取指定地区的当前天气情况',
    parameters: {
      type: 'object',
      properties: {
        city: {
          type: 'string',
          description: '城市,例如:深圳',
        },
      },
      required: ['city'],
    },
  }

  params = {
    ...params,
    functions: [searchGoogleGptFunction, getCurrentWeather],
    function_call: isUseGoogleSearch ? 'auto' : 'none', //fun?.function_call, none
  }

  let completionRes = await axios.post(`${baseURL}/api/light/chat/openAi`, {
    model,
    messages,
    apiKey,
    params,
  })

  const { completion } = completionRes.data.data

  if (
    completion &&
    Array.isArray(completion.choices) &&
    completion.choices.length > 0
  ) {
    if (
      completion.choices[0].finish_reason === 'function_call' &&
      completion.choices[0]?.message?.function_call?.name ===
        'search_google_when_gpt_cannot_answer'
    ) {
      try {
        let myArguments = completion.choices[0]?.message?.function_call?.arguments
        console.log('myArguments', myArguments)
        myArguments = myArguments ? JSON.parse(myArguments) : {}
        let pageNum = 1
        searchCount = searchCount + 1
        let message = myArguments.query
        console.log('google搜索次数', searchCount)
        console.log('google搜索关键词', message, Date())

        let timer = setTimeout(() => {
          customSendEmail({
            subject: 'google搜索超时',
            html: `google搜索超时,${message},${pageNum}`,
          })
        }, 1000 * 60)

        try {
          let result = await axios.post(
            `${baseURL}/api/light/chat/googleSearchOnAzure`,
            {
              message,
              pageNum: 1,
              apiKey,
            }
          )
          clearTimeout(timer)

          const { searchResult } = result.data.data

          delete searchResult.queries

          if (searchResult && Array.isArray(searchResult.items)) {
            let googleResultList = searchResult.items.map((item) => {
              return {
                title: item.title,
                snippet: item.snippet,
              }
            })
            const googleResultForGPT = `这是我的提问:${historyMessage}\n这是我在google搜索“${message}”的结果:\n${JSON.stringify(
              googleResultList
            )}\n请结合搜索结果回答`
            console.log(googleResultForGPT)
            let messagesTemp = [
              ...messages,
              {
                role: 'function',
                name: completion.choices[0]?.message?.function_call?.name,
                content: googleResultForGPT,
              },
            ]

            completionRes = await axios.post(
              `${baseURL}/api/light/chat/openAi`,
              {
                model,
                messages: messagesTemp,
                apiKey,
                params,
              }
            )
            return completionRes
          }
        } catch (err) {
          console.log('错误1', err)

          if (global.isLocal === false) {
            customSendEmail({
              subject: 'chatgpt错误【2】',
              html: `chatgpt错误【2】<br/>${err.stack}`,
            })
          }
        }
      } catch (err) {
        console.log('chatgpt错误【1】', err)

        if (global.isLocal === false) {
          customSendEmail({
            subject: 'chatgpt错误【1】',
            html: `chatgpt错误【1】<br/>${err.stack}`,
          })
        }
      }
    } else if (
      completion.choices[0].finish_reason === 'function_call' &&
      completion.choices[0]?.message?.function_call?.name ===
        'get_current_weather'
    ) {
      try {
        let myArguments = completion.choices[0]?.message?.function_call?.arguments
        console.log('myArguments,get_current_weather', myArguments)
        myArguments = myArguments ? JSON.parse(myArguments) : {}
        let city = myArguments.city

        let resultCity = cityList.find(item => item.name.includes(city))
        let cityCode = '110000'
        if (resultCity && resultCity.adcode) {
          cityCode = resultCity.adcode
        }
        console.log('城市', city, cityCode)


        let result = await axios.get(
          `https://restapi.amap.com/v3/weather/weatherInfo?key=${weatherApiKey}&city=${cityCode}`
        )
        const searchResult = result.data

        if (searchResult && Array.isArray(searchResult.lives)) {
          const searchResultForGPT = `这是我的提问:${historyMessage}\n这是我查询到的结果:\n${JSON.stringify(
            searchResult.lives
          )}\n请结合搜索结果回答`
          console.log(searchResultForGPT)
          let messagesTemp = [
            ...messages,
            {
              role: 'function',
              name: completion.choices[0]?.message?.function_call?.name,
              content: searchResultForGPT,
            },
          ]

          completionRes = await axios.post(`${baseURL}/api/light/chat/openAi`, {
            model,
            messages: messagesTemp,
            apiKey,
            params,
          })
          return completionRes
        }
      } catch (err) {
        console.log('chatgpt错误【3】', err)

        if (global.isLocal === false) {
          customSendEmail({
            subject: 'chatgpt错误【3】',
            html: `chatgpt错误【3】<br/>${err.stack}`,
          })
        }
      }
    }
  }
}
const { google } = require('googleapis')


const chatGoogleSearchOnAzure = async (req, res) => {
  let { message = '', pageNum = 1, apiKey = 'sk-xxx' } = req.body

  if (apiKey === 'xxx') {
    let start = (pageNum - 1) * 10

    const customSearch = google.customsearch('v1')
    const customSearchRes = await customSearch.cse.list({
      cx: googleCx,
      key: googleKey,
      q: message,
      start,
      num: 10,
      hl: 'zh-CN',
      safe: 'off',
      imgColorType: 'color',
    })

    const searchResult = customSearchRes.data

    res.send({
      code: 200,
      data: {
        searchResult: searchResult,
      },
      message: '成功',
    })
  } else {
    res.send({
      code: 400,
      message: '失败:参数apiKey',
    })
  }
}

参考链接:

https://wejson.cn/excel2json/

https://lbs.amap.com/api/webservice/guide/api/weatherinfo/ 

 https://m.moji.com/weather/china/beijing/beijing

https://zhuanlan.zhihu.com/p/637425118 

http://chat.xutongbao.top/ 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/730320.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot2+Vue2实战(十二)springboot一对一,一对多查询

新建数据库表 Course Data TableName("t_course") public class Course implements Serializable {private static final long serialVersionUID 1L;/*** id*/TableId(value "id", type IdType.AUTO)private Integer id;/*** 课程名称*/private String…

如何成为微软MVP?

对一个普通的开发人员来说&#xff0c;最大的认可就是得到微软官方的MVP 认证了&#xff0c;是一份对技术人的荣誉证书。 微软的MVP是相对公平公正的&#xff0c;只要你热爱技术&#xff0c;热爱分享&#xff0c;在一定的领域里有足够的深度&#xff0c;就会得到微软官方的认证…

【沐风老师】3dMax使用Dreamscape插件创建漂亮的日落场景教程

在本教程中,您将学习如何利用3dMax和DreamScape在平静的海面上创造一个美丽的日落效果。DreamScape是3dMax的一套复杂的插件,可以让你创造和呈现现实的景观、海景、天空、云层、户外照明等等。 【最后效果预览】 步骤1&#xff1a;首先,要用DreamScape来呈现一个场景,你需要创…

【Linux学习】日积月累——进程(1)

一、背景 1.1 冯诺依曼体系结构 我们常见的计算机、服务器等设备大部分遵循冯诺依曼体系。 图1 冯诺依曼体系结构 当前&#xff0c;我们所认识的计算机&#xff0c;主要由各类硬件组成&#xff1a; 输入单元&#xff1a;包含键盘、鼠标、扫描仪、写板等&#xff1b;中央处理器…

Unity游戏开发之游戏动画(Unity动画系统)

文章目录 Unity动画系统动画片段 Animation Clip在Unity中制作动画动画复用 替身系统 AvatarAnimator 组件 Animator Component动画状态机 Animator Controller动画状态动画状态的类型动画状态的属性 动画状态机----动画转换转换属性的配置面板 、、、、 Unity动画系统 Unity动…

selenium 02

✏️作者&#xff1a;银河罐头 &#x1f4cb;系列专栏&#xff1a;JavaEE &#x1f332;“种一棵树最好的时间是十年前&#xff0c;其次是现在” 目录 等待浏览器的操作键盘事件鼠标事件定位一组元素多层框架定位下拉框处理弹窗处理上传文件操作关闭浏览器切换窗口截图 等待 s…

SOLIDWORKS小问题解答 硕迪科技

众所周知&#xff0c;SOLIDWORKS的使用者非常多&#xff0c;在使用过程中呢也会有一些小问题&#xff0c;前几天就有朋友来咨询了两个问题&#xff0c;可能其他使用者也有这样的问题&#xff0c;所以今天硕迪科技统一为大家解答 问题一&#xff1a;SOLIDWORKS装配图中的颜色怎么…

csv文件如何在单元格内保留换行 \r\n

csv文件如何在单元格内保留换行 \r\n 一、问题描述 我们都知道 csv 文件内是通过 , 来切分单元格的。 但如果某个单元格内的内容有换行&#xff1a; 34, KyleBing, 你好 # 这里换行了 我的名字是 kyebing 35, Tina, hello 36, Lucy, nice to meet you当用 Excel 打开的时候…

如何使Revit导出带有标准材质的FBX模型?

如何使Revit导出带有标准材质的FBX模型&#xff1f; 初次使用Revit导出fbx格式模型&#xff0c;在导出模型后发现模型材质丢失了&#xff0c;上网查询之后也没到具体原因是什么&#xff0c;不过倒是找到了解决方式&#xff1a;在Revit中安装naviswork插件&#xff0c;然后从re…

Vue之router和vuex

Vue之router和vuex 在学习之前&#xff0c;我们可以先安装一个插件&#xff0c;是一个浏览器插件&#xff0c;这个插件的作用是可以让我们更好的观察到数据的变化和状态的变更 他是一个github的链接&#xff0c;如果你没办法科学上网的话&#xff0c;也可以在 插件下载 上面这…

CodeQL在代码审计中的应用

一、CodeQL简介 CodeQL是一种基于静态分析的程序分析工具&#xff0c;由GitHub开发和维护。截止到此刻&#xff0c;CodeQL在Github上已经有超过6100个Star。它可以用于发现代码中的漏洞、代码质量问题和安全问题。CodeQL使用了一种特殊的编程语言QL&#xff08;查询语言&#…

【Unity项目】Unity实现 双屏显示效果

需求&#xff1a;两个屏显示项目&#xff0c;一个屏显示列表&#xff0c;一个屏显示列表按钮点击后的效果。 最近在修改一个项目&#xff0c;是要求分屏显示项目&#xff0c;一个一体机&#xff0c;一个大屏&#xff0c;一体机当作目录界面&#xff0c;大屏当作模型显示界面&am…

NC140 排序

冒泡排序 public int[] BubbleSort(int[] arr) {// write code herefor (int i 0; i < arr.length - 1; i) {for (int j 0; j < arr.length - 1 - i; j) {if (arr[j] > arr[j 1]) {int temp arr[j];arr[j] arr[j 1];arr[j 1] temp;}}}return arr;}插入排序 p…

HTTP1.0、HTTP1.1、HTTP2.0、HTTP3.0的关系和区别

文章目录 一、对比二、HTTP1.0三、HTTP1.1四、HTTP2.0四、HTTP/3.0五、总结 一、对比 二、HTTP1.0 浏览器的每次请求都需要与服务器建立一个TCP连接&#xff0c;服务器处理完成后立即断开TCP连接&#xff08;无连接&#xff09;&#xff0c;服务器不跟踪每个客户端也不记录过去…

如何使用js对图像进行压缩

JavaScript 可以使用类似于 canvas 和 web workers 来实现图像压缩。 使用 canvas&#xff0c;可以将图像绘制到 canvas 上&#xff0c;然后使用 canvas 提供的 toBlob() 或 toDataURL() 方法将其转换为不同格式的图像。在这些方法中指定图像质量参数即可实现压缩。 使用 web…

python接口自动化(二十)--token登录(详解)

简介 为了验证用户登录情况以及减轻服务器的压力&#xff0c;减少频繁的查询数据库&#xff0c;使服务器更加健壮。有些登录不是用 cookie 来验证的&#xff0c;是用 token 参数来判断是否登录。token 传参有两种一种是放在请求头里&#xff0c;本质上是跟 cookie 是一样的&…

【JS】自调用函数(自执行函数)

文章目录 自调用函数&#xff1a;只能自己在定义的同时调用自己一次&#xff0c;对外界不可见。 语法 // 函数名加与不加都可以 (function 函数名(形参){console.log(11); })(实参)使用&#xff1a; // 用法一 const str 流星; (function (params){console.log(params); // …

33.RocketMQ之Broker启动源码

highlight: arduino-light Broker启动流程:BrokerStartup#main java public static void main(String[] args) { //手动指定了 nameServer start(createBrokerController(args)); } java public static BrokerController start(BrokerController controller)…

Docker开启远程端口访问2375

开启方法&#xff1a; 1、修改/etc/default/docker下的配置 cat >> /etc/default/docker <<EOF DOCKER_OPTS"-H tcp://0.0.0.0:2375" EOF systemctl restart docker 2、修改/usr/lib/systemd/system/docker.service配置 cat >> /usr/lib/systemd/s…

第四章 网络层【计算机网络】

第四章 网络层【计算机网络】 前言推荐第四章 网络层4.1 网络层的几个重要概念4.1.1 网络层提供的两种服务4.1.2 网络层的两个层面 4.2网际协议IP4.2.1 虚拟互连网络4.2.2 IP地址4.2.3IP地址与硬件地址4.2.4地址解析协议ARP4.2.5IP数据报的格式 4.3 IP层转发分组的过程4.3.1 基…