-
Notifications
You must be signed in to change notification settings - Fork 5
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
Showing
96 changed files
with
5,230 additions
and
15 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,29 @@ | ||
package blacklist | ||
|
||
import ( | ||
"fmt" | ||
"sync" | ||
) | ||
|
||
var blackList sync.Map | ||
|
||
func init() { | ||
blackList = sync.Map{} | ||
} | ||
|
||
func userId2Key(id int) string { | ||
return fmt.Sprintf("userid_%d", id) | ||
} | ||
|
||
func BanUser(id int) { | ||
blackList.Store(userId2Key(id), true) | ||
} | ||
|
||
func UnbanUser(id int) { | ||
blackList.Delete(userId2Key(id)) | ||
} | ||
|
||
func IsUserBanned(id int) bool { | ||
_, ok := blackList.Load(userId2Key(id)) | ||
return ok | ||
} |
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,66 @@ | ||
package client | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"net/http" | ||
"net/url" | ||
"time" | ||
|
||
"github.com/hoshinonyaruko/gensokyo-llm/common/config" | ||
"github.com/hoshinonyaruko/gensokyo-llm/common/logger" | ||
llmconfig "github.com/hoshinonyaruko/gensokyo-llm/config" | ||
) | ||
|
||
var HTTPClient *http.Client | ||
var ImpatientHTTPClient *http.Client | ||
var UserContentRequestHTTPClient *http.Client | ||
|
||
func Init() { | ||
proxyURLstr := llmconfig.GetProxy() | ||
if proxyURLstr != "" { | ||
logger.SysLog(fmt.Sprintf("using %s as proxy to fetch user content", config.UserContentRequestProxy)) | ||
// 解析 proxyURL 字符串 | ||
proxyURL, err := url.Parse(proxyURLstr) | ||
if err != nil { | ||
log.Fatalf("Invalid proxy URL: %v", err) | ||
} | ||
|
||
transport := &http.Transport{ | ||
Proxy: http.ProxyURL(proxyURL), | ||
} | ||
UserContentRequestHTTPClient = &http.Client{ | ||
Transport: transport, | ||
Timeout: time.Second * time.Duration(config.UserContentRequestTimeout), | ||
} | ||
} else { | ||
UserContentRequestHTTPClient = &http.Client{} | ||
} | ||
var transport http.RoundTripper | ||
if config.RelayProxy != "" { | ||
logger.SysLog(fmt.Sprintf("using %s as api relay proxy", config.RelayProxy)) | ||
proxyURL, err := url.Parse(config.RelayProxy) | ||
if err != nil { | ||
logger.FatalLog(fmt.Sprintf("USER_CONTENT_REQUEST_PROXY set but invalid: %s", config.UserContentRequestProxy)) | ||
} | ||
transport = &http.Transport{ | ||
Proxy: http.ProxyURL(proxyURL), | ||
} | ||
} | ||
|
||
if config.RelayTimeout == 0 { | ||
HTTPClient = &http.Client{ | ||
Transport: transport, | ||
} | ||
} else { | ||
HTTPClient = &http.Client{ | ||
Timeout: time.Duration(config.RelayTimeout) * time.Second, | ||
Transport: transport, | ||
} | ||
} | ||
|
||
ImpatientHTTPClient = &http.Client{ | ||
Timeout: 5 * time.Second, | ||
Transport: transport, | ||
} | ||
} |
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,155 @@ | ||
package config | ||
|
||
import ( | ||
"os" | ||
"strconv" | ||
"strings" | ||
"sync" | ||
"time" | ||
|
||
"github.com/hoshinonyaruko/gensokyo-llm/common/env" | ||
|
||
"github.com/google/uuid" | ||
) | ||
|
||
var SystemName = "One API" | ||
var ServerAddress = "http://localhost:3000" | ||
var Footer = "" | ||
var Logo = "" | ||
var TopUpLink = "" | ||
var ChatLink = "" | ||
var QuotaPerUnit = 500 * 1000.0 // $0.002 / 1K tokens | ||
var DisplayInCurrencyEnabled = true | ||
var DisplayTokenStatEnabled = true | ||
|
||
// Any options with "Secret", "Token" in its key won't be return by GetOptions | ||
|
||
var SessionSecret = uuid.New().String() | ||
|
||
var OptionMap map[string]string | ||
var OptionMapRWMutex sync.RWMutex | ||
|
||
var ItemsPerPage = 10 | ||
var MaxRecentItems = 100 | ||
|
||
var PasswordLoginEnabled = true | ||
var PasswordRegisterEnabled = true | ||
var EmailVerificationEnabled = false | ||
var GitHubOAuthEnabled = false | ||
var WeChatAuthEnabled = false | ||
var TurnstileCheckEnabled = false | ||
var RegisterEnabled = true | ||
|
||
var EmailDomainRestrictionEnabled = false | ||
var EmailDomainWhitelist = []string{ | ||
"gmail.com", | ||
"163.com", | ||
"126.com", | ||
"qq.com", | ||
"outlook.com", | ||
"hotmail.com", | ||
"icloud.com", | ||
"yahoo.com", | ||
"foxmail.com", | ||
} | ||
|
||
var DebugEnabled = strings.ToLower(os.Getenv("DEBUG")) == "true" | ||
var DebugSQLEnabled = strings.ToLower(os.Getenv("DEBUG_SQL")) == "true" | ||
var MemoryCacheEnabled = strings.ToLower(os.Getenv("MEMORY_CACHE_ENABLED")) == "true" | ||
|
||
var LogConsumeEnabled = true | ||
|
||
var SMTPServer = "" | ||
var SMTPPort = 587 | ||
var SMTPAccount = "" | ||
var SMTPFrom = "" | ||
var SMTPToken = "" | ||
|
||
var GitHubClientId = "" | ||
var GitHubClientSecret = "" | ||
|
||
var LarkClientId = "" | ||
var LarkClientSecret = "" | ||
|
||
var WeChatServerAddress = "" | ||
var WeChatServerToken = "" | ||
var WeChatAccountQRCodeImageURL = "" | ||
|
||
var MessagePusherAddress = "" | ||
var MessagePusherToken = "" | ||
|
||
var TurnstileSiteKey = "" | ||
var TurnstileSecretKey = "" | ||
|
||
var QuotaForNewUser int64 = 0 | ||
var QuotaForInviter int64 = 0 | ||
var QuotaForInvitee int64 = 0 | ||
var ChannelDisableThreshold = 5.0 | ||
var AutomaticDisableChannelEnabled = false | ||
var AutomaticEnableChannelEnabled = false | ||
var QuotaRemindThreshold int64 = 1000 | ||
var PreConsumedQuota int64 = 500 | ||
var ApproximateTokenEnabled = false | ||
var RetryTimes = 0 | ||
|
||
var RootUserEmail = "" | ||
|
||
var IsMasterNode = os.Getenv("NODE_TYPE") != "slave" | ||
|
||
var requestInterval, _ = strconv.Atoi(os.Getenv("POLLING_INTERVAL")) | ||
var RequestInterval = time.Duration(requestInterval) * time.Second | ||
|
||
var SyncFrequency = env.Int("SYNC_FREQUENCY", 10*60) // unit is second | ||
|
||
var BatchUpdateEnabled = false | ||
var BatchUpdateInterval = env.Int("BATCH_UPDATE_INTERVAL", 5) | ||
|
||
var RelayTimeout = env.Int("RELAY_TIMEOUT", 0) // unit is second | ||
|
||
var GeminiSafetySetting = env.String("GEMINI_SAFETY_SETTING", "BLOCK_NONE") | ||
|
||
var Theme = env.String("THEME", "default") | ||
var ValidThemes = map[string]bool{ | ||
"default": true, | ||
"berry": true, | ||
"air": true, | ||
} | ||
|
||
// All duration's unit is seconds | ||
// Shouldn't larger then RateLimitKeyExpirationDuration | ||
var ( | ||
GlobalApiRateLimitNum = env.Int("GLOBAL_API_RATE_LIMIT", 240) | ||
GlobalApiRateLimitDuration int64 = 3 * 60 | ||
|
||
GlobalWebRateLimitNum = env.Int("GLOBAL_WEB_RATE_LIMIT", 120) | ||
GlobalWebRateLimitDuration int64 = 3 * 60 | ||
|
||
UploadRateLimitNum = 10 | ||
UploadRateLimitDuration int64 = 60 | ||
|
||
DownloadRateLimitNum = 10 | ||
DownloadRateLimitDuration int64 = 60 | ||
|
||
CriticalRateLimitNum = 20 | ||
CriticalRateLimitDuration int64 = 20 * 60 | ||
) | ||
|
||
var RateLimitKeyExpirationDuration = 20 * time.Minute | ||
|
||
var EnableMetric = env.Bool("ENABLE_METRIC", false) | ||
var MetricQueueSize = env.Int("METRIC_QUEUE_SIZE", 10) | ||
var MetricSuccessRateThreshold = env.Float64("METRIC_SUCCESS_RATE_THRESHOLD", 0.8) | ||
var MetricSuccessChanSize = env.Int("METRIC_SUCCESS_CHAN_SIZE", 1024) | ||
var MetricFailChanSize = env.Int("METRIC_FAIL_CHAN_SIZE", 128) | ||
|
||
var InitialRootToken = os.Getenv("INITIAL_ROOT_TOKEN") | ||
|
||
var InitialRootAccessToken = os.Getenv("INITIAL_ROOT_ACCESS_TOKEN") | ||
|
||
var GeminiVersion = env.String("GEMINI_VERSION", "v1") | ||
|
||
var OnlyOneLogFile = env.Bool("ONLY_ONE_LOG_FILE", false) | ||
|
||
var RelayProxy = env.String("RELAY_PROXY", "") | ||
var UserContentRequestProxy = env.String("USER_CONTENT_REQUEST_PROXY", "") | ||
var UserContentRequestTimeout = env.Int("USER_CONTENT_REQUEST_TIMEOUT", 30) |
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,6 @@ | ||
package common | ||
|
||
import "time" | ||
|
||
var StartTime = time.Now().Unix() // unit: second | ||
var Version = "v0.0.0" // this hard coding will be replaced automatically when building, no need to manually change |
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,6 @@ | ||
package conv | ||
|
||
func AsString(v any) string { | ||
str, _ := v.(string) | ||
return str | ||
} |
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,14 @@ | ||
package common | ||
|
||
import "golang.org/x/crypto/bcrypt" | ||
|
||
func Password2Hash(password string) (string, error) { | ||
passwordBytes := []byte(password) | ||
hashedPassword, err := bcrypt.GenerateFromPassword(passwordBytes, bcrypt.DefaultCost) | ||
return string(hashedPassword), err | ||
} | ||
|
||
func ValidatePasswordAndHash(password string, hash string) bool { | ||
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) | ||
return err == nil | ||
} |
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,23 @@ | ||
package ctxkey | ||
|
||
const ( | ||
Config = "config" | ||
Id = "id" | ||
Username = "username" | ||
Role = "role" | ||
Status = "status" | ||
Channel = "channel" | ||
ChannelId = "channel_id" | ||
SpecificChannelId = "specific_channel_id" | ||
RequestModel = "request_model" | ||
ConvertedRequest = "converted_request" | ||
OriginalModel = "original_model" | ||
Group = "group" | ||
ModelMapping = "model_mapping" | ||
ChannelName = "channel_name" | ||
TokenId = "token_id" | ||
TokenName = "token_name" | ||
BaseURL = "base_url" | ||
AvailableModels = "available_models" | ||
KeyRequestBody = "key_request_body" | ||
) |
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,82 @@ | ||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved. | ||
// Use of this source code is governed by a MIT style | ||
// license that can be found in the LICENSE file. | ||
|
||
package common | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
"net/http" | ||
"strings" | ||
) | ||
|
||
type stringWriter interface { | ||
io.Writer | ||
writeString(string) (int, error) | ||
} | ||
|
||
type stringWrapper struct { | ||
io.Writer | ||
} | ||
|
||
func (w stringWrapper) writeString(str string) (int, error) { | ||
return w.Writer.Write([]byte(str)) | ||
} | ||
|
||
func checkWriter(writer io.Writer) stringWriter { | ||
if w, ok := writer.(stringWriter); ok { | ||
return w | ||
} else { | ||
return stringWrapper{writer} | ||
} | ||
} | ||
|
||
// Server-Sent Events | ||
// W3C Working Draft 29 October 2009 | ||
// http://www.w3.org/TR/2009/WD-eventsource-20091029/ | ||
|
||
var contentType = []string{"text/event-stream"} | ||
var noCache = []string{"no-cache"} | ||
|
||
var fieldReplacer = strings.NewReplacer( | ||
"\n", "\\n", | ||
"\r", "\\r") | ||
|
||
var dataReplacer = strings.NewReplacer( | ||
"\n", "\ndata:", | ||
"\r", "\\r") | ||
|
||
type CustomEvent struct { | ||
Event string | ||
Id string | ||
Retry uint | ||
Data interface{} | ||
} | ||
|
||
func encode(writer io.Writer, event CustomEvent) error { | ||
w := checkWriter(writer) | ||
return writeData(w, event.Data) | ||
} | ||
|
||
func writeData(w stringWriter, data interface{}) error { | ||
dataReplacer.WriteString(w, fmt.Sprint(data)) | ||
if strings.HasPrefix(data.(string), "data") { | ||
w.writeString("\n\n") | ||
} | ||
return nil | ||
} | ||
|
||
func (r CustomEvent) Render(w http.ResponseWriter) error { | ||
r.WriteContentType(w) | ||
return encode(w, r) | ||
} | ||
|
||
func (r CustomEvent) WriteContentType(w http.ResponseWriter) { | ||
header := w.Header() | ||
header["Content-Type"] = contentType | ||
|
||
if _, exist := header["Cache-Control"]; !exist { | ||
header["Cache-Control"] = noCache | ||
} | ||
} |
Oops, something went wrong.