Git Product home page Git Product logo

openai-proxy's Introduction

GO-OPENAI-PROXY

基于 Go 实现的 OpenAI API HTTP 代理

想要快速体验,将 OpenAI API 调用域名从默认的 api.openai.com 调整为 proxy.geekai.co 即可。你可以在这里预览演示效果:演示应用

切换到 Azure OpenAI

默认在 9000 端口代理 OpenAI API,要想切换到 Azure OpenAI API,可以在 scf_bootstrap 的启动命令中添加域名参数来指定你的 Azure OpenAI API Endpoint:

./main -domain=your-azure-openai-endpoint

如果 9000 端口被占用,可以通过 -post=9001 指定其他端口。

代理任意全球域名

这个工具最早是为 OpenAI 代理而生,但实际上现在已经可以支持通过一个入口代理任意域名,只需要在发起发起代理请求的时候通过 X-Target-Host 设置你想要代理的域名(不带 http(s):// 前缀)即可,优先级是请求头>命令行参数>默认值

req.Header.Set("x-target-host", "api.open.ai")

编译打包

你可以修改源代码调整代理逻辑,然后编译打包进行部署:

./build.sh

此命令需要本地安装go开发环境,如果不想本地安装 go 环境进行编译打包,可以直接下载根据最新源代码编译打包好的 main.zipReleases

部署测试

支持部署到腾讯/阿里云函数、AWS lambda 函数以及任意云服务器,以下以腾讯云函数为例进行演示。

然后在腾讯云云函数代码管理界面上传打包好 zip 包即可完成部署:

你可以通过腾讯云云函数提供的测试工具进行测试,也可以本地通过 curl/postman 进行测试,使用的时候只需要将 api.openai.com 替换成代理域名 proxy.geekai.co 即可:

你可以选择自己搭建,也可以直接使用我提供的代理域名 proxy.geekai.co,反正是免费的。关于代理背后的原理,可以看我在极客书房发布的这篇教程:国内无法调用 OpenAI 接口的解决办法

本地调试走VPN的话可以设置环境变量 ENV=local,然后直连 api.openai.com

// 本地测试通过代理请求 OpenAI 接口
if os.Getenv("ENV") == "local" {
    proxyURL, _ := url.Parse("http://127.0.0.1:10809")
    client.Transport = &http.Transport{
        Proxy:           http.ProxyURL(proxyURL),
        TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
    }
}

流式响应支持

这个源代码本身是支持 stream 流式响应代理的,但目前很多云函数并不支持分块流式传输。所以,如果你需要实现流式响应,可以把编译后的二进制文件 main 丢到任意海外云服务器运行,这样就变成支持流式响应的 OpenAI HTTP 代理了,如果你不想折腾,可以使用我这边提供的 proxy.geekai.co 作为代理进行测试:

image

如果你是通过 Nginx 这种反向代理对外提供服务,记得通过如下配置项将默认缓冲和缓存关掉才会生效:

proxy_buffering off;
proxy_cache off;

openai-proxy's People

Contributors

geekr-dev avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

openai-proxy's Issues

aws lambda

package main

import (
	"context"
	"crypto/tls"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"

	"github.com/aws/aws-lambda-go/events"
	"github.com/aws/aws-lambda-go/lambda"
)

var (
	target    = "https://api.openai.com" // 目标域名
	httpProxy = "http://127.0.0.1:10809" // 本地代理地址和端口
)

func HandleRequest(ctx context.Context, request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
	// 过滤无效URL
	_, err := http.NewRequest(request.HTTPMethod, request.Path, nil)
	if err != nil {
		return events.APIGatewayProxyResponse{StatusCode: http.StatusInternalServerError}, err
	}

	// 去掉环境前缀(针对腾讯云,如果包含的话,目前我只用到了test和release)
	newPath := strings.Replace(request.Path, "/openai-go", "", 1)
	newPath = strings.Replace(newPath, "/default", "", 1)

	// 拼接目标URL
	targetURL := target + newPath

	// 创建代理HTTP请求
	proxyReq, err := http.NewRequest(request.HTTPMethod, targetURL, strings.NewReader(request.Body))
	if err != nil {
		return events.APIGatewayProxyResponse{StatusCode: http.StatusInternalServerError}, err
	}

	// 将原始请求头复制到新请求中
	for headerKey, headerValues := range request.Headers {
		for _, headerValue := range headerValues {
			proxyReq.Header.Add(headerKey, string(headerValue))
		}
	}

	// 默认超时时间设置为60s
	client := &http.Client{
		Timeout: 60 * time.Second,
	}

	// 本地测试通过代理请求 OpenAI 接口
	if os.Getenv("ENV") == "local" {
		proxyURL, _ := url.Parse(httpProxy) // 本地HTTP代理配置
		client.Transport = &http.Transport{
			Proxy:           http.ProxyURL(proxyURL),
			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
		}
	}

	// 向 OpenAI 发起代理请求
	resp, err := client.Do(proxyReq)
	if err != nil {
		return events.APIGatewayProxyResponse{StatusCode: http.StatusInternalServerError}, err
	}
	defer resp.Body.Close()

	// 将响应头复制到代理响应头中
	responseHeaders := make(map[string]string)
	for key, values := range resp.Header {
		var headerValue string
		for _, value := range values {
			headerValue += value + ","
		}
		responseHeaders[key] = strings.TrimSuffix(headerValue, ",")
	}

	// 读取响应实体到字节数组中
	responseBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return events.APIGatewayProxyResponse{StatusCode: http.StatusInternalServerError}, err
	}

	// 返回API Gateway响应
	return events.APIGatewayProxyResponse{
		StatusCode: resp.StatusCode,
		Headers:    responseHeaders,
		Body:       string(responseBody),
	}, nil
}

func main() {
	lambda.Start(HandleRequest)
}

hello。请教一下。我使用了咱们的地址做了转发。结果报错是 400 。是咱们这边的协议转换吃了什么特殊值么

ObjectMapper mapper = defaultObjectMapper();
        OkHttpClient client = OpenAiService.defaultClient("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",
                        Duration.ofMinutes(2))
                .newBuilder()
                .build();

        Retrofit retrofit = new retrofit2.Retrofit.Builder().
                baseUrl("https://open.aiproxy.xyz/").
                client(client).
                addConverterFactory(JacksonConverterFactory.create(mapper)).
                addCallAdapterFactory(RxJava2CallAdapterFactory.create()).
                build();

        Retrofit defaultRetrofit = OpenAiService.defaultRetrofit(client, mapper);
        OpenAiApi api = retrofit.create(OpenAiApi.class);
        OpenAiService openAiService = new OpenAiService(api);

        ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder()
                .model("gpt-3.5-turbo-0301")
                .messages(Lists.newArrayList(
                        new ChatMessage("user", ""),
                        new ChatMessage("user", "他有什么贡献")
                ))
                .build();
        ChatCompletionResult result = openAiService.createChatCompletion(chatCompletionRequest);
        System.out.println(result);
Caused by: retrofit2.adapter.rxjava2.HttpException: HTTP 400 
	at retrofit2.adapter.rxjava2.BodyObservable$BodyObserver.onNext(BodyObservable.java:57)
	at retrofit2.adapter.rxjava2.BodyObservable$BodyObserver.onNext(BodyObservable.java:38)
	at retrofit2.adapter.rxjava2.CallExecuteObservable.subscribeActual(CallExecuteObservable.java:48)
	at io.reactivex.Observable.subscribe(Observable.java:12267)
	at retrofit2.adapter.rxjava2.BodyObservable.subscribeActual(BodyObservable.java:35)
	at io.reactivex.Observable.subscribe(Observable.java:12267)
	at io.reactivex.internal.operators.observable.ObservableSingleSingle.subscribeActual(ObservableSingleSingle.java:35)
	at io.reactivex.Single.subscribe(Single.java:3603)
	at io.reactivex.Single.blockingGet(Single.java:2834)
	at com.theokanning.openai.service.OpenAiService.execute(OpenAiService.java:217)

吐槽一下golang版本导致的编译问题

纯路人,没学过golang

想重新编译一下项目,以适配长文本输出(gpt3.5-16k)

结果编译通过,部署到腾讯云函数上面就会出现HTTP405

排查了一个小时,最后发现是因为使用了最新的go 1.20,使用go 1.17.5在Ubuntu22.04下编译就正常了😅

请教在宝塔中如何部署呢

没用过go语言,不知道怎么部署,将你的main.zip解压到服务器
里面有两个文件,在宝塔中是运行哪个文件?

我执行后打开链接报错

Get "https://api.openai.com/": http2: invalid Connection request header: ["upgrade"]

Streaming模式并不实时

io.Copy无法保证实时转发streaming流,需要改进

`buf := make([]byte, 1024*1024) // 1MB buffer
for {

n, err := resp.Body.Read(buf)
if err != nil && err != io.EOF {
    http.Error(w, err.Error(), http.StatusInternalServerError)
    return
}
if n == 0 {
    break
}
if _, err := w.Write(buf[:n]); err != nil {
    http.Error(w, err.Error(), http.StatusInternalServerError)
    return
}
w.(http.Flusher).Flush()

}`

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.