Node接入ChatGPT 的最强对手Claude

lxf2023-05-18 00:56:59

由于个人的chatGPT免费版本即将到期, Claude 很火,在网上被说成是 ChatGPT 的最强对手,是 ChatGPT 的替代品。本文我将介绍下 Claude 是什么,以及如何免费使用 Claude.

什么是Claude?

看一下它是如何自我介绍的

Node接入ChatGPT 的最强对手Claude

Slack

Slack 是一款流行的团队协作和通讯软件

Claude 官方给我定义了很方便的 Slack 应用 Claude-in-Slack,我们直接把它添加到 Slack 中即可使用。添加的操作也很简单:

  1. 先注册 Slack
  2. 到 Claude 官网,点击 Add to Slack
  3. 在跳转的页面点击 添加到 Slack
  4. 在 Slack 中选择 Claude 应用,进入聊天窗口开始使用

接下来使用Slack的api来实现调用Claude, 虽然Claude也有接口申请, 但是一直没有通过, 不知道什么原因, 但是既然在Slack中可以使用Claude, 那就取巧, 通过Slack的api来实现调用Claude吧

Slack的api地址:

api.slack.com/methods

Slack 为我们提供了各个语言的 SDK,我们以 node-slack-sdk 来作为演示示例。

获取Slack Token

为了使用 Slack 的 SDK,我们需要新建一个 Slack APP。

Node接入ChatGPT 的最强对手Claude

选择Form scratch, 这里说一下, 我这里带翻译是使用了谷歌插件, 最近这个插件挺火的, 也很好用, 可以安利给大家, 插件的名字是沉浸式翻译, 大家直接去谷歌商店搜索就能找到了.

Node接入ChatGPT 的最强对手Claude

输入 app 名称并选择自己的 workspace。

Node接入ChatGPT 的最强对手Claude

创建后点击我们的 APP,然后点击左侧栏的 OAuth & Permissions。下拉找到 Scopes,为我们的 User Token 添加 Scope。

Node接入ChatGPT 的最强对手Claude

添加需要通过接口访问的权限

Node接入ChatGPT 的最强对手Claude

Node接入ChatGPT 的最强对手Claude

只有授权了才能够通过sdk调用这些接口哦

这些接口分别代表着不同的权限

Node接入ChatGPT 的最强对手Claude

然后我们把 APP 安装到我们的 workspace 中:

这个按钮在auth页面的上面

Node接入ChatGPT 的最强对手Claude

安装后,这里会生成我们需要的 User OAuth Token,我们复制这个 Token,后面需要用。

如果更改了权限, 就要重新下载到工作区才会出现效果哈

Node接入ChatGPT 的最强对手Claude

获取Claude Bot ID

进入Slack应用页面, 找到对应的Claude应用, 右击选择查看应用详情

Node接入ChatGPT 的最强对手Claude

复制Claude的成员ID和频道ID

Node接入ChatGPT 的最强对手Claude

Slack Claude Server

在服务端开始来获取应用里面的数据

我们需要安装的依赖有:

github.com/slackapi/no…

$ npm install @slack/web-api @slack/socket-mode

# Or, if you prefer yarn
$ yarn add @slack/web-api @slack/socket-mode

通过readme,我们可以看到如何像应用中发送一条数据

const { WebClient } = require('@slack/web-api');

// An access token (from your Slack app or custom integration - xoxp, xoxb)
const token = process.env.SLACK_TOKEN;

const web = new WebClient(token);

// This argument can be a channel ID, a DM ID, a MPDM ID, or a group ID
const conversationId = 'C1232456';

(async () => {
  // See: https://api.slack.com/methods/chat.postMessage
  const res = await web.chat.postMessage({ channel: conversationId, text: 'Hello there' });

  // `res` contains information about the posted message
  console.log('Message sent: ', res.ts);
})();

但是我们需要把这样的数据,做成一个接口的形式, 然后方便客户端调用, 我这里选择了express来创造路由接口, 很方便和快速

拿到客户端输入的数据之后, 我们需要将Claude返回的数据返回给客户端, readme里面就没有提供例子了.

其实方法就是读取Claude这个应用窗口的历史数据, 拿到最新的这条回复, 通过conversations.history接口来拿取数据

CALUDE_BOT_ID: 是频道ID

CALUDE_CHANNEL_ID: 是成员ID

CALUDE_TOKEN: 是上面拿到的User OAuth Token

import { WebClient } from '@slack/web-api'
import { Router } from "express";

const routes = Router();
// An access token (from your Slack app or custom integration - xoxp, xoxb)
const token = process.env.CALUDE_TOKEN;

const web = new WebClient(token);

// This argument can be a channel ID, a DM ID, a MPDM ID, or a group ID
const conversationId = process.env.CALUDE_CHANNEL_ID;

const channelId = process.env.CALUDE_BOT_ID;

routes.all("*", function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
  res.header("Access-Control-Allow-Headers", "X-Requested-With");
  res.header('Access-Control-Allow-Headers', 'Content-Type');
  next();
})

function sleep(ms: number) {
  return new Promise(resolve=>setTimeout(resolve, ms))
}

routes.post('/chat-process', async (req, res) => {
  
  res.setHeader('Content-type', 'application/octet-stream')
  try {
    const { prompt } = req.body
    const ans = await web.chat.postMessage({ channel: conversationId || '', text: prompt});
    let firstChunk = true
    for(let i = 0; i < 500; i++) {
      try {
        // Call the conversations.history method using WebClient
        const result = await web.conversations.history({
          channel: channelId || '',
          oldest: ans.ts,
          limit: 2
        });
    
        const conversationHistory = result.messages;
        if (!conversationHistory) {
          sleep(1000)
          continue
        }
        else if(conversationHistory != undefined && Array.isArray(conversationHistory) && conversationHistory[0]?.text?.indexOf('_Typing…_') != -1) {

          res.write(firstChunk ? `${conversationHistory[0].text}` : `⭐${conversationHistory[0].text}`)
          firstChunk = false
          sleep(1000)
          continue
        }
        res.write(`⭐${conversationHistory[0].text}`)
        res.end()
        break;
      }
      catch (error) {
        console.error(error);
      }
    }
  }
  catch (error) {
    res.json({
      err: JSON.stringify(error)
    })
  }
  finally {
    res.end()
  }
})


export default routes;

将接口的content-Type设置成application/octet-stream, 是为了不用等到Claude完全解答完再返回给客户端, 可以先返回一些内容, 然后慢慢加载, 这样会增强用户体验感, 同时也能防止接口响应时间太长, 用户一直未得到答案

这里设置一个循环500次, 其实就是为了保证500次之后, 能够返回完整的数据, 当然如果提前结束了,就会break退出循环.

Claude Client

我这里是一个vue+vite项目, 核心请求接口代码如下:

async function onConversation() {
  let message = prompt.value

  if (loading.value)
    return

  if (!message || message.trim() === '')
    return

  controller = new AbortController()


  scrollToBottom()
  addMessage('', false)
  loading.value = true
  prompt.value = ''
  
  try {
    const fetchChatAPIOnce = async () => {
      await fetchCaludeAPIProcess({
        prompt: message,
        onDownloadProgress: ({ event }) => {
          const xhr = event.target
          const { responseText } = xhr
          // Always process the final line
          const lastIndex = responseText.lastIndexOf('⭐', responseText.length - 2)
          let chunk = responseText
          if (lastIndex !== -1) {
            chunk = responseText.substring(lastIndex)
          }
          list.value[list.value.length - 1].message = chunk
          scrollToBottom()
        },
      })
    }
    await fetchChatAPIOnce()
  }
  catch (error: any) {
    const errorMessage = error?.message ?? 'common.wrong'

    if (error.message === 'canceled') {

      scrollToBottomIfAtBottom()
      return
    }
    list.value[list.value.length - 1].message = errorMessage
    console.error(errorMessage)
    scrollToBottomIfAtBottom()
  }
  finally {
    loading.value = false
  }
}

每次都是以⭐开头, 所以我这边就是去最后一个⭐开头的数据, 然后渲染到页面就可以了

Node接入ChatGPT 的最强对手Claude

最终的效果如下:

Node接入ChatGPT 的最强对手Claude

最后提供我的线上链接供大家体验一下:

vite-chatgpt-production.up.railway.app/#/claude

本网站是一个以CSS、JavaScript、Vue、HTML为核心的前端开发技术网站。我们致力于为广大前端开发者提供专业、全面、实用的前端开发知识和技术支持。 在本网站中,您可以学习到最新的前端开发技术,了解前端开发的最新趋势和最佳实践。我们提供丰富的教程和案例,让您可以快速掌握前端开发的核心技术和流程。 本网站还提供一系列实用的工具和插件,帮助您更加高效地进行前端开发工作。我们提供的工具和插件都经过精心设计和优化,可以帮助您节省时间和精力,提升开发效率。 除此之外,本网站还拥有一个活跃的社区,您可以在社区中与其他前端开发者交流技术、分享经验、解决问题。我们相信,社区的力量可以帮助您更好地成长和进步。 在本网站中,您可以找到您需要的一切前端开发资源,让您成为一名更加优秀的前端开发者。欢迎您加入我们的大家庭,一起探索前端开发的无限可能!