chatgpt-web icon indicating copy to clipboard operation
chatgpt-web copied to clipboard

通过更新apiBaseUrl避免国内API被墙

Open pengmaochang opened this issue 3 years ago • 15 comments

从昨晚8点开始,GPT3.5的API被墙,导致国内各种项目都使用不了。但是更改service/src/chatgpt/index.ts文件的API参数,可以避免被墙。具体如下:

const options: ChatGPTAPIOptions = {
      apiKey: process.env.OPENAI_API_KEY,
      apiBaseUrl: 'https://openapi.ssiic.com',
      debug: false,
    }

请问作者可以把这段写入源码吗?或者把这个参数作为docker 镜像可配置的参数,方便我们docker compose部署党。 感谢感谢~

pengmaochang avatar Mar 03 '23 12:03 pengmaochang

我觉得不妥,这个url什么时候停了就全都受影响。

JeazW avatar Mar 03 '23 12:03 JeazW

所以做成可配置参数呀。总比现在这么多国内的朋友都被强的好吧

pengmaochang avatar Mar 03 '23 12:03 pengmaochang

我觉得还是用原生的API接口地址比较好,对于如何解决API地址无法访问并不是本项目的重点要关注的点,可以自行设置代理来解决该问题

LuckyZY avatar Mar 03 '23 13:03 LuckyZY

比如做成可选参数,如果不配置,就是默认的原生API地址。如果配置,就自己写进去。这样既不影响已有的部署,也能有效解决被墙的问题

pengmaochang avatar Mar 03 '23 13:03 pengmaochang

对的,有同样的需求

goodwisdom avatar Mar 03 '23 14:03 goodwisdom

接口timeout的原因是被墙了?

font-size avatar Mar 03 '23 15:03 font-size

TS整体换成:

import * as dotenv from 'dotenv'
import 'isomorphic-fetch'
import type { ChatMessage, SendMessageOptions } from 'chatgpt'
import { ChatGPTAPI, ChatGPTUnofficialProxyAPI } from 'chatgpt'
import { SocksProxyAgent } from 'socks-proxy-agent'
import fetch from 'node-fetch'
import { sendResponse } from '../utils'
import type { ApiModel, ChatContext, ChatGPTAPIOptions, ChatGPTUnofficialProxyAPIOptions, ModelConfig } from '../types'

dotenv.config()

const timeoutMs: number = !isNaN(+process.env.TIMEOUT_MS) ? +process.env.TIMEOUT_MS : 30 * 1000

let apiModel: ApiModel

if (!process.env.OPENAI_API_KEY && !process.env.OPENAI_ACCESS_TOKEN)
  throw new Error('Missing OPENAI_API_KEY or OPENAI_ACCESS_TOKEN environment variable')

let api: ChatGPTAPI | ChatGPTUnofficialProxyAPI

// To use ESM in CommonJS, you can use a dynamic import
(async () => {
  // More Info: https://github.com/transitive-bullshit/chatgpt-api

  if (process.env.OPENAI_API_KEY) {
    const options: ChatGPTAPIOptions = {
      apiKey: process.env.OPENAI_API_KEY,
      apiBaseUrl: 'https://openapi.ssiic.com',
      debug: false,
    }

    api = new ChatGPTAPI({ ...options })
    apiModel = 'ChatGPTAPI'
  }
  else {
    const options: ChatGPTUnofficialProxyAPIOptions = {
      accessToken: process.env.OPENAI_ACCESS_TOKEN,
      debug: false,
    }

    if (process.env.SOCKS_PROXY_HOST && process.env.SOCKS_PROXY_PORT) {
      const agent = new SocksProxyAgent({
        hostname: process.env.SOCKS_PROXY_HOST,
        port: process.env.SOCKS_PROXY_PORT,
      })
      options.fetch = (url, options) => {
        return fetch(url, { agent, ...options })
      }
    }

    if (process.env.API_REVERSE_PROXY)
      options.apiReverseProxyUrl = process.env.API_REVERSE_PROXY

    api = new ChatGPTUnofficialProxyAPI({
      accessToken: process.env.OPENAI_ACCESS_TOKEN,
      ...options,
    })
    apiModel = 'ChatGPTUnofficialProxyAPI'
  }
})()

async function chatReply(
  message: string,
  lastContext?: { conversationId?: string; parentMessageId?: string },
) {
  if (!message)
    return sendResponse({ type: 'Fail', message: 'Message is empty' })

  try {
    let options: SendMessageOptions = { timeoutMs }

    if (lastContext)
      options = { ...lastContext }

    const response = await api.sendMessage(message, { ...options })

    return sendResponse({ type: 'Success', data: response })
  }
  catch (error: any) {
    return sendResponse({ type: 'Fail', message: error.message })
  }
}

async function chatReplyProcess(
  message: string,
  lastContext?: { conversationId?: string; parentMessageId?: string },
  process?: (chat: ChatMessage) => void,
) {
  if (!message)
    return sendResponse({ type: 'Fail', message: 'Message is empty' })

  try {
    let options: SendMessageOptions = { timeoutMs }

    if (lastContext)
      options = { ...lastContext }

    const response = await api.sendMessage(message, {
      ...options,
      onProgress: (partialResponse) => {
        process?.(partialResponse)
      },
    })

    return sendResponse({ type: 'Success', data: response })
  }
  catch (error: any) {
    return sendResponse({ type: 'Fail', message: error.message })
  }
}

async function chatConfig() {
  return sendResponse({
    type: 'Success',
    data: {
      apiModel,
      reverseProxy: process.env.API_REVERSE_PROXY,
      timeoutMs,
      socksProxy: (process.env.SOCKS_PROXY_HOST && process.env.SOCKS_PROXY_PORT) ? (`${process.env.SOCKS_PROXY_HOST}:${process.env.SOCKS_PROXY_PORT}`) : '-',
    } as ModelConfig,
  })
}

export type { ChatContext, ChatMessage }

export { chatReply, chatReplyProcess, chatConfig }

pengmaochang avatar Mar 03 '23 15:03 pengmaochang

ChatGPTAPIOptions和ChatGPTUnofficialProxyAPI、chatConfig都有所更改

pengmaochang avatar Mar 03 '23 15:03 pengmaochang

TS整体换成:

import * as dotenv from 'dotenv'
import 'isomorphic-fetch'
import type { ChatMessage, SendMessageOptions } from 'chatgpt'
import { ChatGPTAPI, ChatGPTUnofficialProxyAPI } from 'chatgpt'
import { SocksProxyAgent } from 'socks-proxy-agent'
import fetch from 'node-fetch'
import { sendResponse } from '../utils'
import type { ApiModel, ChatContext, ChatGPTAPIOptions, ChatGPTUnofficialProxyAPIOptions, ModelConfig } from '../types'

dotenv.config()

const timeoutMs: number = !isNaN(+process.env.TIMEOUT_MS) ? +process.env.TIMEOUT_MS : 30 * 1000

let apiModel: ApiModel

if (!process.env.OPENAI_API_KEY && !process.env.OPENAI_ACCESS_TOKEN)
  throw new Error('Missing OPENAI_API_KEY or OPENAI_ACCESS_TOKEN environment variable')

let api: ChatGPTAPI | ChatGPTUnofficialProxyAPI

// To use ESM in CommonJS, you can use a dynamic import
(async () => {
  // More Info: https://github.com/transitive-bullshit/chatgpt-api

  if (process.env.OPENAI_API_KEY) {
    const options: ChatGPTAPIOptions = {
      apiKey: process.env.OPENAI_API_KEY,
      apiBaseUrl: 'https://openapi.ssiic.com',
      debug: false,
    }

    api = new ChatGPTAPI({ ...options })
    apiModel = 'ChatGPTAPI'
  }
  else {
    const options: ChatGPTUnofficialProxyAPIOptions = {
      accessToken: process.env.OPENAI_ACCESS_TOKEN,
      debug: false,
    }

    if (process.env.SOCKS_PROXY_HOST && process.env.SOCKS_PROXY_PORT) {
      const agent = new SocksProxyAgent({
        hostname: process.env.SOCKS_PROXY_HOST,
        port: process.env.SOCKS_PROXY_PORT,
      })
      options.fetch = (url, options) => {
        return fetch(url, { agent, ...options })
      }
    }

    if (process.env.API_REVERSE_PROXY)
      options.apiReverseProxyUrl = process.env.API_REVERSE_PROXY

    api = new ChatGPTUnofficialProxyAPI({
      accessToken: process.env.OPENAI_ACCESS_TOKEN,
      ...options,
    })
    apiModel = 'ChatGPTUnofficialProxyAPI'
  }
})()

async function chatReply(
  message: string,
  lastContext?: { conversationId?: string; parentMessageId?: string },
) {
  if (!message)
    return sendResponse({ type: 'Fail', message: 'Message is empty' })

  try {
    let options: SendMessageOptions = { timeoutMs }

    if (lastContext)
      options = { ...lastContext }

    const response = await api.sendMessage(message, { ...options })

    return sendResponse({ type: 'Success', data: response })
  }
  catch (error: any) {
    return sendResponse({ type: 'Fail', message: error.message })
  }
}

async function chatReplyProcess(
  message: string,
  lastContext?: { conversationId?: string; parentMessageId?: string },
  process?: (chat: ChatMessage) => void,
) {
  if (!message)
    return sendResponse({ type: 'Fail', message: 'Message is empty' })

  try {
    let options: SendMessageOptions = { timeoutMs }

    if (lastContext)
      options = { ...lastContext }

    const response = await api.sendMessage(message, {
      ...options,
      onProgress: (partialResponse) => {
        process?.(partialResponse)
      },
    })

    return sendResponse({ type: 'Success', data: response })
  }
  catch (error: any) {
    return sendResponse({ type: 'Fail', message: error.message })
  }
}

async function chatConfig() {
  return sendResponse({
    type: 'Success',
    data: {
      apiModel,
      reverseProxy: process.env.API_REVERSE_PROXY,
      timeoutMs,
      socksProxy: (process.env.SOCKS_PROXY_HOST && process.env.SOCKS_PROXY_PORT) ? (`${process.env.SOCKS_PROXY_HOST}:${process.env.SOCKS_PROXY_PORT}`) : '-',
    } as ModelConfig,
  })
}

export type { ChatContext, ChatMessage }

export { chatReply, chatReplyProcess, chatConfig }

替换后还是经常出现“fetch failed”,如何处理?

DevinLin01 avatar Mar 03 '23 18:03 DevinLin01

已添加

Chanzhaoyu avatar Mar 04 '23 01:03 Chanzhaoyu

localhost: 一直报错,我改成了上面的代码,在环境中也改了网址,有什么解决办法嘛,错误提示ChatGPTUnofficialProxyAPI.sendMessage: conversationId and parentMessageId must both be set or both be undefinedmmexport1677942501020.png

kuxingdu avatar Mar 04 '23 15:03 kuxingdu

@Chanzhaoyu @pengmaochang 两位大大有解决办法不

kuxingdu avatar Mar 04 '23 15:03 kuxingdu

我也出现这样的情况了,同求解决办法

Smeleo avatar Mar 04 '23 15:03 Smeleo

@kuxingdu @Smeleo new chat就可以了。这个问题应该是因为更换代理后不支持以前对话导致的。所以请删除旧的对话,新搞一个对话窗口

pengmaochang avatar Mar 06 '23 02:03 pengmaochang

感谢

---- 回复的原邮件 ---- | 发件人 | @.> | | 日期 | 2023年03月06日 10:34 | | 收件人 | @.> | | 抄送至 | @.>@.> | | 主题 | Re: [Chanzhaoyu/chatgpt-web] 通过更新apiBaseUrl避免国内API被墙 (Issue #249) |

@@.*** new chat就可以了。这个问题应该是因为更换代理后不支持以前对话导致的。所以请删除旧的对话,新搞一个对话窗口

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you were mentioned.Message ID: @.***>

kuxingdu avatar Mar 06 '23 03:03 kuxingdu

@pengmaochang 兄弟,接口调不通啦

RenDaniu avatar Mar 27 '23 01:03 RenDaniu