@@ -3,6 +3,7 @@ module github.com/casbin/casibase | |||||
go 1.18 | go 1.18 | ||||
require ( | require ( | ||||
github.com/Lok-Lu/go-openrouter v0.0.0-20230807015935-ab5cee433ad3 | |||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1585 | github.com/aliyun/alibaba-cloud-sdk-go v1.61.1585 | ||||
github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible | github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible | ||||
github.com/anhao/go-ernie v1.0.4 | github.com/anhao/go-ernie v1.0.4 | ||||
@@ -38,6 +38,8 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym | |||||
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= | github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= | ||||
github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= | github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= | ||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= | github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= | ||||
github.com/Lok-Lu/go-openrouter v0.0.0-20230807015935-ab5cee433ad3 h1:E15Zr1fu3QEIleqINqXpl4SlYuWkwWPJ4cx6UVaJITE= | |||||
github.com/Lok-Lu/go-openrouter v0.0.0-20230807015935-ab5cee433ad3/go.mod h1:nM0kITDAJEkwn9x2DQPdfJynThaLe0vGNpPcqJ8vjAI= | |||||
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= | github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= | ||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= | github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= | ||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= | github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= | ||||
@@ -0,0 +1,130 @@ | |||||
// Copyright 2023 The casbin Authors. All Rights Reserved. | |||||
// | |||||
// Licensed under the Apache License, Version 2.0 (the "License"); | |||||
// you may not use this file except in compliance with the License. | |||||
// You may obtain a copy of the License at | |||||
// | |||||
// http://www.apache.org/licenses/LICENSE-2.0 | |||||
// | |||||
// Unless required by applicable law or agreed to in writing, software | |||||
// distributed under the License is distributed on an "AS IS" BASIS, | |||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
// See the License for the specific language governing permissions and | |||||
// limitations under the License. | |||||
package model | |||||
import ( | |||||
"context" | |||||
"fmt" | |||||
"io" | |||||
"net/http" | |||||
"strings" | |||||
"github.com/Lok-Lu/go-openrouter" | |||||
"github.com/casbin/casibase/proxy" | |||||
) | |||||
type OpenRouterModelProvider struct { | |||||
subType string | |||||
secretKey string | |||||
siteName string | |||||
siteUrl string | |||||
} | |||||
func NewOpenRouterModelProvider(subType string, secretKey string) (*OpenRouterModelProvider, error) { | |||||
p := &OpenRouterModelProvider{ | |||||
subType: subType, | |||||
secretKey: secretKey, | |||||
siteName: "Casibase", | |||||
siteUrl: "https://casibase.org", | |||||
} | |||||
return p, nil | |||||
} | |||||
func (p *OpenRouterModelProvider) getProxyClientFromToken() *openrouter.Client { | |||||
config, err := openrouter.DefaultConfig(p.secretKey, p.siteName, p.siteUrl) | |||||
if err != nil { | |||||
panic(err) | |||||
} | |||||
config.HTTPClient = proxy.ProxyHttpClient | |||||
c := openrouter.NewClientWithConfig(config) | |||||
return c | |||||
} | |||||
func (p *OpenRouterModelProvider) QueryText(question string, writer io.Writer, builder *strings.Builder) error { | |||||
client := p.getProxyClientFromToken() | |||||
ctx := context.Background() | |||||
flusher, ok := writer.(http.Flusher) | |||||
if !ok { | |||||
return fmt.Errorf("writer does not implement http.Flusher") | |||||
} | |||||
model := p.subType | |||||
if model == "" { | |||||
model = openrouter.Gpt35Turbo | |||||
} | |||||
promptTokens, err := GetTokenSize(model, question) | |||||
if err != nil { | |||||
return err | |||||
} | |||||
maxTokens := 4097 - promptTokens | |||||
respStream, err := client.CreateChatCompletionStream( | |||||
ctx, | |||||
&openrouter.ChatCompletionRequest{ | |||||
Model: p.subType, | |||||
Messages: []openrouter.ChatCompletionMessage{ | |||||
{ | |||||
Role: openrouter.ChatMessageRoleSystem, | |||||
Content: "You are a helpful assistant.", | |||||
}, | |||||
{ | |||||
Role: openrouter.ChatMessageRoleUser, | |||||
Content: question, | |||||
}, | |||||
}, | |||||
Stream: false, | |||||
Temperature: nil, | |||||
TopP: nil, | |||||
MaxTokens: maxTokens, | |||||
}, | |||||
) | |||||
if err != nil { | |||||
return err | |||||
} | |||||
defer respStream.Close() | |||||
isLeadingReturn := true | |||||
for { | |||||
completion, streamErr := respStream.Recv() | |||||
if streamErr != nil { | |||||
if streamErr == io.EOF { | |||||
break | |||||
} | |||||
return streamErr | |||||
} | |||||
data := completion.Choices[0].Message.Content | |||||
if isLeadingReturn && len(data) != 0 { | |||||
if strings.Count(data, "\n") == len(data) { | |||||
continue | |||||
} else { | |||||
isLeadingReturn = false | |||||
} | |||||
} | |||||
if _, err = fmt.Fprintf(writer, "event: message\ndata: %s\n\n", data); err != nil { | |||||
return err | |||||
} | |||||
flusher.Flush() | |||||
builder.WriteString(data) | |||||
} | |||||
return nil | |||||
} |
@@ -30,6 +30,8 @@ func GetModelProvider(typ string, subType string, clientId string, clientSecret | |||||
p, err = NewOpenAiModelProvider(subType, clientSecret) | p, err = NewOpenAiModelProvider(subType, clientSecret) | ||||
} else if typ == "Hugging Face" { | } else if typ == "Hugging Face" { | ||||
p, err = NewHuggingFaceModelProvider(subType, clientSecret) | p, err = NewHuggingFaceModelProvider(subType, clientSecret) | ||||
} else if typ == "OpenRouter" { | |||||
p, err = NewOpenRouterModelProvider(subType, clientSecret) | |||||
} else if typ == "Ernie" { | } else if typ == "Ernie" { | ||||
p, err = NewErnieModelProvider(subType, clientId, clientSecret) | p, err = NewErnieModelProvider(subType, clientId, clientSecret) | ||||
} | } | ||||
@@ -659,6 +659,7 @@ export function getProviderTypeOptions(category) { | |||||
[ | [ | ||||
{id: "OpenAI", name: "OpenAI"}, | {id: "OpenAI", name: "OpenAI"}, | ||||
{id: "Hugging Face", name: "Hugging Face"}, | {id: "Hugging Face", name: "Hugging Face"}, | ||||
{id: "OpenRouter", name: "OpenRouter"}, | |||||
{id: "Ernie", name: "Ernie"}, | {id: "Ernie", name: "Ernie"}, | ||||
] | ] | ||||
); | ); | ||||
@@ -739,6 +740,31 @@ export function getProviderSubTypeOptions(category, type) { | |||||
{id: "THUDM/chatglm2-6b", name: "THUDM/chatglm2-6b"}, | {id: "THUDM/chatglm2-6b", name: "THUDM/chatglm2-6b"}, | ||||
] | ] | ||||
); | ); | ||||
} else if (type === "OpenRouter") { | |||||
return ( | |||||
[ | |||||
{id: "google/palm-2-codechat-bison", name: "google/palm-2-codechat-bison"}, | |||||
{id: "google/palm-2-chat-bison", name: "google/palm-2-chat-bison"}, | |||||
{id: "openai/gpt-3.5-turbo", name: "openai/gpt-3.5-turbo"}, | |||||
{id: "openai/gpt-3.5-turbo-16k", name: "openai/gpt-3.5-turbo-16k"}, | |||||
{id: "openai/gpt-4", name: "openai/gpt-4"}, | |||||
{id: "openai/gpt-4-32k", name: "openai/gpt-4-32k"}, | |||||
{id: "anthropic/claude-2", name: "anthropic/claude-2"}, | |||||
{id: "anthropic/claude-instant-v1", name: "anthropic/claude-instant-v1"}, | |||||
{id: "meta-llama/llama-2-13b-chat", name: "meta-llama/llama-2-13b-chat"}, | |||||
{id: "meta-llama/llama-2-70b-chat", name: "meta-llama/llama-2-70b-chat"}, | |||||
{id: "palm-2-codechat-bison", name: "palm-2-codechat-bison"}, | |||||
{id: "palm-2-chat-bison", name: "palm-2-chat-bison"}, | |||||
{id: "gpt-3.5-turbo", name: "gpt-3.5-turbo"}, | |||||
{id: "gpt-3.5-turbo-16k", name: "gpt-3.5-turbo-16k"}, | |||||
{id: "gpt-4", name: "gpt-4"}, | |||||
{id: "gpt-4-32k", name: "gpt-4-32k"}, | |||||
{id: "claude-2", name: "claude-2"}, | |||||
{id: "claude-instant-v1", name: "claude-instant-v1"}, | |||||
{id: "llama-2-13b-chat", name: "llama-2-13b-chat"}, | |||||
{id: "llama-2-70b-chat", name: "llama-2-70b-chat"}, | |||||
] | |||||
); | |||||
} else if (type === "Ernie") { | } else if (type === "Ernie") { | ||||
return ( | return ( | ||||
[ | [ | ||||