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

Add support for reverse proxy servers

Open st6091741 opened this issue 2 years ago • 1 comments

Clear and concise description of the problem

我使用hk博客搭建了一个api反代,可以免魔法访问api(不用设置https_proxy)

然后可以在代码中增加对反代的支持吗?

Suggested solution

我改动了两处,简单实现了一下,可以放到您的代码库中吗? .env文件:

# Your API Key for OpenAI
OPENAI_API_KEY=keykeykey
# Provide proxy for OpenAI API. e.g. http://127.0.0.1:7890
#HTTPS_PROXY=no set
Reverse_Proxy_Server=https://xxx.com/openai/
#this is my honkong blog
# Inject analytics or other scripts before </head> of the page
HEAD_SCRIPTS=

在generate.ts:

import type { APIRoute } from 'astro'
import { generatePayload, parseOpenAIStream } from '@/utils/openAI'
// #vercel-disable-blocks
import { fetch, ProxyAgent } from 'undici'
// #vercel-end

const apiKey = import.meta.env.OPENAI_API_KEY
const https_proxy = import.meta.env.HTTPS_PROXY
const Reverse_Proxy_Server = import.meta.env.Reverse_Proxy_Server //我增加的

export const post: APIRoute = async (context) => {
  const body = await context.request.json()
  const messages = body.messages

  if (!messages) {
    return new Response('No input text')
  }
  const initOptions = generatePayload(apiKey, messages)
  // #vercel-disable-blocks
  if (https_proxy) {
    initOptions['dispatcher'] = new ProxyAgent(https_proxy)
  }
  // #vercel-end

  // @ts-ignore
  const response = await fetch(Reverse_Proxy_Server?Reverse_Proxy_Server.trim():'https://api.openai.com/v1/chat/completions', initOptions) as Response //我改动的

  return new Response(parseOpenAIStream(response))
}

另外,我用nodejs实现stream反代,可以给第三方参考:

const http = require("http");
const https = require("https");
const url = require("url");

/***************************************
 * 
 * 请留意,这仅仅是链接到openai的一个接口,纯文本,
 * 并不消耗大量服务器流量,望理解
 * 
 * ***********************************/
process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0;

process.NODE_NO_WARNINGS = 1;
process.removeAllListeners('warning');


var server = http.createServer( function(request,response) {
    response.writeHead(200,{'Content-Type':'application/json;charset=UTF8','Access-Control-Allow-Origin':'*',"Access-Control-Allow-Headers":"Authorization,Content-Type"});
    var body = ''
    request.on('data', function (chunk) {
            body += chunk;
        });
 
        request.on('end', async function () {
           
    
    try{
        headers = request.headers
        var authorization = ""
        for(let i in headers){
            if(i.trim().toLocaleLowerCase()==="authorization"){
            authorization = headers[i].trim()
            break;
            }
        }
        
	var json1 = await fetchData(authorization, body,response);
   // response.write(json1);
    }catch(e){
        response.write('{"error":"'+e+'"}');
    }
     response.end();
        });
   
});
server.listen(3001);

function fetchData(authorization, body,response) {
  const https = require('https');

  const options = {
    hostname: 'api.openai.com',
    path: '/v1/chat/completions',
    method: 'POST',
    headers: {
      'authorization': authorization,
      'content-type': 'application/json'
    }
  };

  return new Promise((resolve, reject) => {
    const req = https.request(options, (res) => {
      let data = '';

      res.on('data', (chunk) => {
        data += chunk;
        response.write(chunk)
   });

      res.on('end', () => {
        const result = data.trim();
        resolve(result);
      });
    });

    req.on('error', (error) => {
      reject(error);
    });

    req.write(body);
    req.end();
  });
}



Alternative

No response

Additional context

No response

Validations

  • [X] Follow our Code of Conduct
  • [X] Read the Contributing Guide.
  • [X] Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.

st6091741 avatar Mar 05 '23 06:03 st6091741

PR Welcome. 另外,反代服务器建议仅填入 host 前缀部分,如 "https://api.proxy-openai.com/",环境变量起名可以用 OPENAI_API_BASE_URL

ddiu8081 avatar Mar 05 '23 16:03 ddiu8081