-
Notifications
You must be signed in to change notification settings - Fork 471
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d4dbaba
commit 2a97921
Showing
5 changed files
with
186 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# 功能说明 | ||
`chatgpt-proxy`插件实现了代理请求AI大语言模型服务的功能。 | ||
|
||
# 配置字段 | ||
|
||
| 名称 | 数据类型 | 填写要求 | 默认值 | 描述 | | ||
| -------- | -------- | -------- | -------- | -------- | | ||
| model | string | 选填 | text-davinci-003 | 配置使用的模型模型名称 | | ||
| apiKey | string | 必填 | - | 配置使用的OpenAI API密钥 | | ||
| promptParam | string | 选填 | prompt | 配置prompt的来源字段名称,URL参数 | | ||
| chatgptUri | string | 选填 | api.openai.com/v1/completions | 配置调用AI模型服务的URL路径,默认值为OPENAI的API调用路径 | | ||
# 配置示例 | ||
|
||
## 进行OpenAI curie模型的调用 | ||
```yaml | ||
apiKey: "xxxxxxxxxxxxxx", | ||
promptParam: "text", | ||
model: "curie" | ||
``` | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
module chatgpt-proxy | ||
|
||
go 1.19 | ||
|
||
require ( | ||
github.com/alibaba/higress/plugins/wasm-go v0.0.0-20230629030002-81e467b6242d | ||
github.com/tetratelabs/proxy-wasm-go-sdk v0.22.0 | ||
github.com/tidwall/gjson v1.14.4 | ||
) | ||
|
||
require ( | ||
github.com/google/uuid v1.3.0 // indirect | ||
github.com/tidwall/match v1.1.1 // indirect | ||
github.com/tidwall/pretty v1.2.0 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
github.com/alibaba/higress/plugins/wasm-go v0.0.0-20230619024848-7d2a05ef1c35 h1:9xBMl8mJ5CGE1ebqtx9s11zrKJHs0559Yf/QWFh0WIQ= | ||
github.com/alibaba/higress/plugins/wasm-go v0.0.0-20230619024848-7d2a05ef1c35/go.mod h1:AzSnkuon5c26nIePTiJQIAFsKdhkNdncLcTuahpGtQs= | ||
github.com/alibaba/higress/plugins/wasm-go v0.0.0-20230629030002-81e467b6242d h1:PyBnIfssGRMKvBf6wKH11Z1t+X1Z7qegD1pAO60sFrk= | ||
github.com/alibaba/higress/plugins/wasm-go v0.0.0-20230629030002-81e467b6242d/go.mod h1:AzSnkuon5c26nIePTiJQIAFsKdhkNdncLcTuahpGtQs= | ||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= | ||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | ||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= | ||
github.com/tetratelabs/proxy-wasm-go-sdk v0.19.1-0.20220822060051-f9d179a57f8c h1:OCUFXVGixHLfNjg6/QYEhv+jHJ5mRGhpEUVFv9eWPJE= | ||
github.com/tetratelabs/proxy-wasm-go-sdk v0.19.1-0.20220822060051-f9d179a57f8c/go.mod h1:5t/pWFNJ9eMyu/K/Z+OeGhDJ9sN9eCo8fc2pyM/Qjg4= | ||
github.com/tetratelabs/proxy-wasm-go-sdk v0.22.0 h1:kS7BvMKN+FiptV4pfwiNX8e3q14evxAWkhYbxt8EI1M= | ||
github.com/tetratelabs/proxy-wasm-go-sdk v0.22.0/go.mod h1:qkW5MBz2jch2u8bS59wws65WC+Gtx3x0aPUX5JL7CXI= | ||
github.com/tidwall/gjson v1.14.3 h1:9jvXn7olKEHU1S9vwoMGliaT8jq1vJ7IH/n9zD9Dnlw= | ||
github.com/tidwall/gjson v1.14.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= | ||
github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= | ||
github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= | ||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= | ||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= | ||
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= | ||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= | ||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
package main | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"net/http" | ||
"net/url" | ||
"strings" | ||
|
||
"github.com/alibaba/higress/plugins/wasm-go/pkg/wrapper" | ||
"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm" | ||
"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm/types" | ||
"github.com/tidwall/gjson" | ||
) | ||
|
||
func main() { | ||
wrapper.SetCtx( | ||
"chatgpt-proxy", | ||
wrapper.ParseConfigBy(parseConfig), | ||
wrapper.ProcessRequestHeadersBy(onHttpRequestHeaders), | ||
) | ||
} | ||
|
||
type MyConfig struct { | ||
Model string | ||
ApiKey string | ||
PromptParam string | ||
ChatgptPath string | ||
HumainId string | ||
AIId string | ||
client wrapper.HttpClient | ||
} | ||
|
||
func parseConfig(json gjson.Result, config *MyConfig, log wrapper.Log) error { | ||
chatgptUri := json.Get("chatgptUri").String() | ||
var chatgptHost string | ||
if chatgptUri == "" { | ||
config.ChatgptPath = "/v1/completions" | ||
chatgptHost = "api.openai.com" | ||
} else { | ||
cp, err := url.Parse(chatgptUri) | ||
if err != nil { | ||
return err | ||
} | ||
config.ChatgptPath = cp.Path | ||
chatgptHost = cp.Host | ||
} | ||
if config.ChatgptPath == "" { | ||
return errors.New("not found path in chatgptUri") | ||
} | ||
if chatgptHost == "" { | ||
return errors.New("not found host in chatgptUri") | ||
} | ||
config.client = wrapper.NewClusterClient(wrapper.RouteCluster{ | ||
Host: chatgptHost, | ||
}) | ||
config.Model = json.Get("model").String() | ||
if config.Model == "" { | ||
config.Model = "text-davinci-003" | ||
} | ||
config.ApiKey = json.Get("apiKey").String() | ||
if config.ApiKey == "" { | ||
return errors.New("no apiKey found in config") | ||
} | ||
config.PromptParam = json.Get("promptParam").String() | ||
if config.PromptParam == "" { | ||
config.PromptParam = "prompt" | ||
} | ||
config.HumainId = json.Get("HumainId").String() | ||
if config.HumainId == "" { | ||
config.HumainId = "Humain:" | ||
} | ||
config.AIId = json.Get("AIId").String() | ||
if config.AIId == "" { | ||
config.AIId = "AI:" | ||
} | ||
return nil | ||
} | ||
|
||
const bodyTemplate string = ` | ||
{ | ||
"model":"%s", | ||
"prompt":"%s", | ||
"temperature":0.9, | ||
"max_tokens": 150, | ||
"top_p": 1, | ||
"frequency_penalty": 0.0, | ||
"presence_penalty": 0.6, | ||
"stop": [" %s", " %s"] | ||
} | ||
` | ||
|
||
func onHttpRequestHeaders(ctx wrapper.HttpContext, config MyConfig, log wrapper.Log) types.Action { | ||
pairs := strings.SplitN(ctx.Path(), "?", 2) | ||
|
||
if len(pairs) < 2 { | ||
proxywasm.SendHttpResponse(400, nil, []byte("1-need prompt param"), -1) | ||
return types.ActionContinue | ||
} | ||
querys, err := url.ParseQuery(pairs[1]) | ||
if err != nil { | ||
proxywasm.SendHttpResponse(400, nil, []byte("2-need prompt param"), -1) | ||
return types.ActionContinue | ||
} | ||
var prompt []string | ||
var ok bool | ||
if prompt, ok = querys[config.PromptParam]; !ok || len(prompt) == 0 { | ||
proxywasm.SendHttpResponse(400, nil, []byte("3-need prompt param"), -1) | ||
return types.ActionContinue | ||
} | ||
body := fmt.Sprintf(bodyTemplate, config.Model, prompt[0], config.HumainId, config.AIId) | ||
err = config.client.Post(config.ChatgptPath, [][2]string{ | ||
{"Content-Type", "application/json"}, | ||
{"Authorization", "Bearer " + config.ApiKey}, | ||
}, []byte(body), | ||
func(statusCode int, responseHeaders http.Header, responseBody []byte) { | ||
var headers [][2]string | ||
for key, value := range responseHeaders { | ||
headers = append(headers, [2]string{key, value[0]}) | ||
} | ||
proxywasm.SendHttpResponse(uint32(statusCode), headers, responseBody, -1) | ||
}, 10000) | ||
if err != nil { | ||
proxywasm.SendHttpResponse(500, nil, []byte("Internel Error: "+err.Error()), -1) | ||
return types.ActionContinue | ||
} | ||
return types.ActionPause | ||
} |
Binary file not shown.