diff --git a/controller/token.go b/controller/token.go index 668ccd97..cb8df90b 100644 --- a/controller/token.go +++ b/controller/token.go @@ -2,6 +2,9 @@ package controller import ( "fmt" + "net/http" + "strconv" + "github.com/gin-gonic/gin" "github.com/songquanpeng/one-api/common/config" "github.com/songquanpeng/one-api/common/ctxkey" @@ -9,8 +12,6 @@ import ( "github.com/songquanpeng/one-api/common/network" "github.com/songquanpeng/one-api/common/random" "github.com/songquanpeng/one-api/model" - "net/http" - "strconv" ) func GetAllTokens(c *gin.Context) { @@ -20,6 +21,14 @@ func GetAllTokens(c *gin.Context) { p = 0 } + myRole := c.GetInt(ctxkey.Role) + if myRole == model.RoleRootUser { + uId, _ := strconv.Atoi(c.Query("user_id")) + if uId != 0 { + userId = uId + } + } + order := c.Query("order") tokens, err := model.GetAllUserTokens(userId, p*config.ItemsPerPage, config.ItemsPerPage, order) @@ -41,6 +50,13 @@ func GetAllTokens(c *gin.Context) { func SearchTokens(c *gin.Context) { userId := c.GetInt(ctxkey.Id) keyword := c.Query("keyword") + myRole := c.GetInt(ctxkey.Role) + if myRole == model.RoleRootUser { + uId, _ := strconv.Atoi(c.Query("user_id")) + if uId != 0 { + userId = uId + } + } tokens, err := model.SearchUserTokens(userId, keyword) if err != nil { c.JSON(http.StatusOK, gin.H{ @@ -67,6 +83,13 @@ func GetToken(c *gin.Context) { }) return } + myRole := c.GetInt(ctxkey.Role) + if myRole == model.RoleRootUser { + uId, _ := strconv.Atoi(c.Query("user_id")) + if uId != 0 { + userId = uId + } + } token, err := model.GetTokenByIds(id, userId) if err != nil { c.JSON(http.StatusOK, gin.H{ @@ -151,6 +174,15 @@ func AddToken(c *gin.Context) { Models: token.Models, Subnet: token.Subnet, } + // if the user is root and add the token for other user, set the user id + myRole := c.GetInt(ctxkey.Role) + if myRole == model.RoleRootUser { + if token.UserId == 0 { + cleanToken.UserId = c.GetInt(ctxkey.Id) + } else { + cleanToken.UserId = token.UserId + } + } err = cleanToken.Insert() if err != nil { c.JSON(http.StatusOK, gin.H{ @@ -170,6 +202,14 @@ func AddToken(c *gin.Context) { func DeleteToken(c *gin.Context) { id, _ := strconv.Atoi(c.Param("id")) userId := c.GetInt(ctxkey.Id) + myRole := c.GetInt(ctxkey.Role) + // if the user is root and delete the token for other user, set the user id + if myRole == model.RoleRootUser { + uId, _ := strconv.Atoi(c.Query("user_id")) + if uId != 0 { + userId = uId + } + } err := model.DeleteTokenById(id, userId) if err != nil { c.JSON(http.StatusOK, gin.H{ @@ -205,6 +245,14 @@ func UpdateToken(c *gin.Context) { }) return } + // if the user is root and update the token for other user, set the user id + myRole := c.GetInt(ctxkey.Role) + if myRole == model.RoleRootUser { + if token.UserId == 0 { + userId = token.UserId + } + } + cleanToken, err := model.GetTokenByIds(token.Id, userId) if err != nil { c.JSON(http.StatusOK, gin.H{ diff --git a/sdk/api/channel.go b/sdk/api/channel.go new file mode 100644 index 00000000..192a6f7d --- /dev/null +++ b/sdk/api/channel.go @@ -0,0 +1,186 @@ +package sdk + +import ( + "encoding/json" + "fmt" + "strings" +) + +type Channel struct { + ID int `json:"id"` + Type int `json:"type"` + Key string `json:"key"` + Status int `json:"status"` + Name string `json:"name"` + Weight int `json:"weight"` + CreatedTime int `json:"created_time"` + TestTime int `json:"test_time"` + ResponseTime int `json:"response_time"` + BaseUrl string `json:"base_url"` + Other string `json:"other"` + Balance int `json:"balance"` + BalanceUpdatedTime int `json:"balance_updated_time"` + Models string `json:"models"` + Group string `json:"group"` + UsedQuota int `json:"used_quota"` + ModelMapping string `json:"model_mapping"` + Priority int `json:"priority"` + Config string `json:"config"` + SystemPrompt string `json:"system_prompt"` + ChannelConfig ChannelConfig `json:"channel_confi"` +} + +type ChannelConfig struct { + Region string `json:"region"` + Sk string `json:"sk"` + Ak string `json:"ak"` + UserId string `json:"user_id"` + VertexAiProjectId string `json:"vertex_ai_project_id"` + VertexAiAdc string `json:"vertex_ai_adc"` +} +type NewChannel struct { + BaseUrl string `json:"base_url"` + Config string `json:"config"` + Group string `json:"group"` + Groups []string `json:"groups"` + Key string `json:"key"` + ModelMapping string `json:"model_mapping"` + Models string `json:"models"` + Name string `json:"name"` + Other string `json:"other"` + SystemPrompt string `json:"system_prompt"` + Type int `json:"type"` +} + +type Channels struct { + Channels []*Channel + Query map[string]string +} + +type ChannelRespData struct { + Data interface{} `json:"data"` + Message string `json:"message"` + Success bool `json:"success"` +} + +type ChannelResp struct { + Message string `json:"message"` + ModelName string `json:"modelName"` + Success bool `json:"success"` + Time float64 `json:"time"` +} + +type ChannelImpl interface { + Add(channel *Channel) error + Get(id int) error + Update(channel *Channel) error + Delete(id int) error + Test() error +} + +// list channel +func (channels *Channels) List(client *OneClient) error { + if channels.Query != nil { + client.Url = "/api/channel/search?" + for k, v := range channels.Query { + client.Url += k + "=" + v + "&" + } + client.Url += "p=0&order=" + } else { + client.Url = "/api/channel/?p=0&order=" + } + resp, err := client.get() + if err != nil { + return err + } + defer resp.Body.Close() + data := ChannelRespData{Data: []*Channel{}, Message: "", Success: false} + if err := json.NewDecoder(resp.Body).Decode(&data); err != nil { + return err + } + for _, v := range data.Data.([]interface{}) { + channel := &Channel{} + channelData, _ := json.Marshal(v) + err = json.Unmarshal(channelData, channel) + if err != nil { + return err + } + channels.Channels = append(channels.Channels, channel) + } + return nil +} + +// add channel +func (channel *Channel) Add(client *OneClient) error { + client.Url = "/api/channel/" + channelConfigData, err := json.Marshal(channel.ChannelConfig) + newChannel := NewChannel{ + BaseUrl: channel.BaseUrl, + Config: string(channelConfigData), + Group: channel.Group, + Groups: []string{channel.Group}, + Key: channel.Key, + ModelMapping: channel.ModelMapping, + Models: channel.Models, + Name: channel.Name, + Other: channel.Other, + SystemPrompt: channel.SystemPrompt, + Type: channel.Type, + } + data, err := json.Marshal(newChannel) + if err != nil { + return err + } + return client.post(data) +} + +// update channel +func (channel *Channel) Update(client *OneClient) error { + client.Url = "/api/channel/" + data, err := json.Marshal(channel) + if err != nil { + return err + } + return client.put(data) +} + +// delete channel +func (channel *Channel) Delete(client *OneClient) error { + client.Url = "/api/channel/" + fmt.Sprintf("%d", channel.ID) + return client.delete(nil) +} + +// get channel +func (channel *Channel) Get(client *OneClient) error { + client.Url = "/api/channel/" + fmt.Sprintf("%d", channel.ID) + "/" + resp, err := client.get() + if err != nil { + return err + } + defer resp.Body.Close() + data := ChannelRespData{Data: channel, Message: "", Success: false} + if err := json.NewDecoder(resp.Body).Decode(&data); err != nil { + return err + } + channel = data.Data.(*Channel) + return nil +} + +// test channel +func (channel *Channel) Test(client *OneClient) error { + client.Url = "/api/channel/test/" + fmt.Sprintf("%d", channel.ID) + "/?model=" + strings.Split(channel.Models, ",")[0] + resp, err := client.get() + if err != nil { + return err + } + defer resp.Body.Close() + data := ChannelResp{Message: "", ModelName: "", Success: false, Time: 0} + if err := json.NewDecoder(resp.Body).Decode(&data); err != nil { + return err + } + if data.Success { + return nil + } else { + return fmt.Errorf("test channel failed: %s", data.Message) + } +} diff --git a/sdk/api/client.go b/sdk/api/client.go new file mode 100644 index 00000000..160a7ea1 --- /dev/null +++ b/sdk/api/client.go @@ -0,0 +1,116 @@ +package sdk + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" + "strconv" +) + +type Config struct { + Host string `json:"host"` + Port int `json:"port"` + Key string `json:"key"` +} + +type OneClient struct { + Client *http.Client + Config *Config + Url string +} + +type RespMessage struct { + Message string `json:"message"` + Success bool `json:"success"` +} + +// get +func (OneClient *OneClient) get() (*http.Response, error) { + OneClient.Client = &http.Client{} + port := strconv.Itoa(OneClient.Config.Port) + url := OneClient.Config.Host + ":" + port + OneClient.Url + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", "Bearer "+OneClient.Config.Key) + resp, err := OneClient.Client.Do(req) + if err != nil { + return nil, err + } + return resp, nil +} + +// post +func (OneClient *OneClient) post(data []byte) error { + OneClient.Client = &http.Client{} + port := strconv.Itoa(OneClient.Config.Port) + url := OneClient.Config.Host + ":" + port + OneClient.Url + payload := bytes.NewBuffer(data) + req, err := http.NewRequest("POST", url, payload) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", "Bearer "+OneClient.Config.Key) + resp, err := OneClient.Client.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + message := RespMessage{} + if err := json.NewDecoder(resp.Body).Decode(&message); err != nil { + return err + } + if message.Success { + return nil + } + return fmt.Errorf("create user failed: %s", message.Message) +} + +// put +func (OneClient *OneClient) put(data []byte) error { + OneClient.Client = &http.Client{} + port := strconv.Itoa(OneClient.Config.Port) + url := OneClient.Config.Host + ":" + port + OneClient.Url + payload := bytes.NewBuffer(data) + req, err := http.NewRequest("PUT", url, payload) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", "Bearer "+OneClient.Config.Key) + resp, err := OneClient.Client.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + message := RespMessage{} + if err := json.NewDecoder(resp.Body).Decode(&message); err != nil { + return err + } + if message.Success { + return nil + } + return fmt.Errorf("update user failed: %s", message.Message) +} + +// delete +func (OneClient *OneClient) delete(data []byte) error { + OneClient.Client = &http.Client{} + port := strconv.Itoa(OneClient.Config.Port) + url := OneClient.Config.Host + ":" + port + OneClient.Url + payload := bytes.NewBuffer(data) + req, err := http.NewRequest("DELETE", url, payload) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", "Bearer "+OneClient.Config.Key) + resp, err := OneClient.Client.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + message := RespMessage{} + if err := json.NewDecoder(resp.Body).Decode(&message); err != nil { + return err + } + if message.Success { + return nil + } + return fmt.Errorf("delete user failed: %s", message.Message) +} diff --git a/sdk/api/log.go b/sdk/api/log.go new file mode 100644 index 00000000..41c83eed --- /dev/null +++ b/sdk/api/log.go @@ -0,0 +1,91 @@ +package sdk + +import ( + "encoding/json" + "time" +) + +// get log url like http://172.18.2.63:8300/api/log/?p=0&type=0&username=&token_name=&model_name=&start_timestamp=0&end_timestamp=1745237472&channel= +// define log struct :{ +// "id": 349, +// "user_id": 21, +// "created_at": 1745206602, +// "type": 3, +// "content": "管理员将用户额度从 $0.000000 额度修改为 $1000.000000 额度", +// "username": "test1", +// "token_name": "", +// "model_name": "", +// "quota": 0, +// "prompt_tokens": 0, +// "completion_tokens": 0, +// "channel": 0, +// "request_id": "2025042111364245599153931550114", +// "elapsed_time": 0, +// "is_stream": false, +// "system_prompt_reset": false +// }, + +type Log struct { + ID int `json:"id"` + UserID int `json:"user_id"` + CreatedAt int `json:"created_at"` + Type int `json:"type"` + Content string `json:"content"` + Username string `json:"username"` + TokenName string `json:"token_name"` + ModelName string `json:"model_name"` + Quota int `json:"quota"` + PromptTokens int `json:"prompt_tokens"` + CompletionTokens int `json:"completion_tokens"` + Channel int `json:"channel"` + RequestID string `json:"request_id"` + ElapsedTime int `json:"elapsed_time"` + IsStream bool `json:"is_stream"` + SystemPromptReset bool `json:"system_prompt_reset"` +} + +type Logs struct { + Logs []*Log + Query map[string]string +} + +type Logsimpl interface { + Get(client *OneClient) error +} + +type LogRespData struct { + Data interface{} `json:"data"` + Message string `json:"message"` + Success bool `json:"success"` +} + +// get log +func (logs *Logs) Get(client *OneClient) error { + client.Url = "/api/log/?" + if logs.Query != nil { + for k, v := range logs.Query { + client.Url += k + "=" + v + "&" + } + } else { + client.Url = "/api/log/?p=0&type=0&username=&token_name=&model_name=&start_timestamp=0&end_timestamp=" + time.Now().String() + "&channel=" + } + resp, err := client.get() + if err != nil { + return err + } + defer resp.Body.Close() + data := LogRespData{Data: []*Log{}, Message: "", Success: false} + if err := json.NewDecoder(resp.Body).Decode(&data); err != nil { + return err + } + for _, v := range data.Data.([]interface{}) { + log := &Log{} + logData, _ := json.Marshal(v) + err = json.Unmarshal(logData, log) + if err != nil { + return err + } + logs.Logs = append(logs.Logs, log) + } + return nil +} diff --git a/sdk/api/token.go b/sdk/api/token.go new file mode 100644 index 00000000..b1c71acf --- /dev/null +++ b/sdk/api/token.go @@ -0,0 +1,131 @@ +package sdk + +import ( + "encoding/json" + "strconv" +) + +type Token struct { + ID int `json:"id"` + UserID int `json:"user_id"` + Key string `json:"key"` + Status int `json:"status"` + Name string `json:"name"` + CreatedTime int `json:"created_time"` + AccessedTime int `json:"accessed_time"` + ExpiredTime int `json:"expired_time"` + RemainQuota int `json:"remain_quota"` + UnlimitedQuota bool `json:"unlimited_quota"` + UsedQuota int `json:"used_quota"` + Models string `json:"models"` + Subnet string `json:"subnet"` +} + +// define add token function +type Tokenimpl interface { + Add(token *Token) error + List(id int) error + Update(token *Token) error + Delete(id int) error +} + +type Tokens struct { + Tokens []*Token + UserID int + Query map[string]string +} + +type TokensImpl interface { + List(token *Token) error +} + +type TokenRespData struct { + Data interface{} `json:"data"` +} + +// add token +func (token *Token) Add(client *OneClient) error { + client.Url = "/api/token/" + data, err := json.Marshal(token) + if err != nil { + return err + } + return client.post(data) +} + +// update token +func (token *Token) Update(client *OneClient) error { + client.Url = "/api/token/" + data, err := json.Marshal(token) + if err != nil { + return err + } + return client.put(data) +} + +// list token +func (tokens *Tokens) List(client *OneClient) error { + if tokens.UserID != 0 { + if tokens.Query != nil { + client.Url = "/api/token/search?user_id=" + strconv.Itoa(tokens.UserID) + for k, v := range tokens.Query { + client.Url += "&" + k + "=" + v + } + client.Url += "&p=0&order=" + } else { + client.Url = "/api/token/?user_id=" + strconv.Itoa(tokens.UserID) + "&p=0&order=" + } + } else { + if tokens.Query != nil { + client.Url = "/api/token/search?p=0" + for k, v := range tokens.Query { + client.Url += "&" + k + "=" + v + } + } else { + client.Url = "/api/token/?p=0" + } + client.Url += "&order=" + } + resp, err := client.get() + if err != nil { + return err + } + defer resp.Body.Close() + data := TokenRespData{Data: []*Token{}} + if err := json.NewDecoder(resp.Body).Decode(&data); err != nil { + return err + } + for _, v := range data.Data.([]interface{}) { + token := &Token{} + tokenData, _ := json.Marshal(v) + err = json.Unmarshal(tokenData, token) + if err != nil { + return err + } + tokens.Tokens = append(tokens.Tokens, token) + } + return nil +} + +// delete token +func (token *Token) Delete(client *OneClient) error { + client.Url = "/api/token/" + strconv.Itoa(token.ID) + "/" + "?user_id=" + strconv.Itoa(token.UserID) + return client.delete(nil) +} + +// get token +func (token *Token) Get(client *OneClient) error { + client.Url = "/api/token/" + strconv.Itoa(token.ID) + "/" + "?user_id=" + strconv.Itoa(token.UserID) + resp, err := client.get() + if err != nil { + return err + } + defer resp.Body.Close() + data := TokenRespData{Data: token} + if err := json.NewDecoder(resp.Body).Decode(&data); err != nil { + return err + } + tokenData, _ := json.Marshal(data.Data) + err = json.Unmarshal(tokenData, token) + return nil +} diff --git a/sdk/api/user.go b/sdk/api/user.go new file mode 100644 index 00000000..2eefe9cb --- /dev/null +++ b/sdk/api/user.go @@ -0,0 +1,134 @@ +// 6ca91f95d29749db8a93d5b8903c7949 + +// description: User API +// use httprequest to get user list and user info +package sdk + +import ( + "encoding/json" + "fmt" +) + +type User struct { + ID int `json:"id"` + Username string `json:"username"` + Password string `json:"password"` + DisplayName string `json:"display_name"` + Role int `json:"role"` + Status int `json:"status"` + Email string `json:"email"` + GithubID string `json:"github_id"` + WechatID string `json:"wechat_id"` + LarkID string `json:"lark_id"` + OidcID string `json:"oidc_id"` + VerificationCode string `json:"verification_code"` + AccessToken string `json:"access_token"` + Quota int `json:"quota"` + UsedQuota int `json:"used_quota"` + RequestCount int `json:"request_count"` + Group string `json:"group"` + AffCode string `json:"aff_code"` + InviterID int `json:"inviter_id"` +} + +type UserRespData struct { + Data interface{} `json:"data"` +} + +type UserImpl interface { + Add(user *User) error + Get(id int) error + Updater(user *User) error + Delete(id int) error +} + +type Users struct { + Users []*User + Query map[string]string +} + +// list user +func (users *Users) List(client *OneClient) error { + if users.Query != nil { + client.Url = "/api/user/search?" + for k, v := range users.Query { + client.Url += k + "=" + v + "&" + } + client.Url += "p=0&order=" + } else { + client.Url = "/api/user/?p=0&order=" + } + resp, err := client.get() + if err != nil { + return err + } + defer resp.Body.Close() + data := UserRespData{Data: []*User{}} + if err := json.NewDecoder(resp.Body).Decode(&data); err != nil { + return err + } + for _, v := range data.Data.([]interface{}) { + user := &User{} + userData, _ := json.Marshal(v) + err = json.Unmarshal(userData, user) + if err != nil { + return err + } + users.Users = append(users.Users, user) + } + return nil +} + +// add user +func (user *User) Add(client *OneClient) error { + client.Url = "/api/user/" + data, err := json.Marshal(user) + if err != nil { + return err + } + return client.post(data) +} + +// delete user +func (user *User) Delete(client *OneClient) error { + client.Url = "/api/user/manage" + deleteData := map[string]interface{}{ + "username": user.Username, + "action": "delete", + } + data, err := json.Marshal(deleteData) + if err != nil { + return err + } + return client.post(data) +} + +// update user +func (user *User) Update(client *OneClient) error { + client.Url = "/api/user" + data, err := json.Marshal(user) + if err != nil { + return err + } + return client.put(data) +} + +// get user +func (user *User) Get(client *OneClient) error { + client.Url = "/api/user/" + fmt.Sprintf("%d", user.ID) + resp, err := client.get() + if err != nil { + return err + } + defer resp.Body.Close() + data := UserRespData{Data: user} + if err := json.NewDecoder(resp.Body).Decode(&data); err != nil { + return err + } + userData, _ := json.Marshal(data.Data) + err = json.Unmarshal(userData, user) + if err != nil { + return err + } + return nil +} diff --git a/sdk/chat/chat.go b/sdk/chat/chat.go new file mode 100644 index 00000000..d9b5820e --- /dev/null +++ b/sdk/chat/chat.go @@ -0,0 +1,126 @@ +package chat + +import ( + "bufio" + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "log" + "net/http" + "os" + "strings" +) + +// ChatCompletionRequest defines the request structure +type ChatCompletionRequest struct { + Model string `json:"model"` + Messages []Message `json:"messages"` + Stream bool `json:"stream"` +} + +// Message defines the message structure +type Message struct { + Role string `json:"role"` + Content string `json:"content"` +} + +// ChatCompletionChunk defines the chunk structure for streaming response +type ChatCompletionChunk struct { + Choices []Choice `json:"choices"` +} + +// Choice defines the choice structure +type Choice struct { + Delta struct { + Content string `json:"content"` + } `json:"delta"` +} + +// Config defines the OpenAI API configuration +type Config struct { + Host string `json:"host"` + Port int `json:"port"` + Key string `json:"key"` +} + +func Chatting(config Config) { + apiKey := config.Key + messages := []Message{} + + scanner := bufio.NewScanner(os.Stdin) + for { + fmt.Print("Enter your message: ") + if !scanner.Scan() { + break + } + userInput := scanner.Text() + messages = append(messages, Message{Role: "user", Content: userInput}) + + request := ChatCompletionRequest{ + Model: "ERNIE-3.5-8K", + Messages: messages, + Stream: true, + } + + requestBody, err := json.Marshal(request) + if err != nil { + log.Fatalf("Error encoding JSON request body: %v", err) + } + + url := fmt.Sprintf("%s:%d/v1/chat/completions", config.Host, config.Port) + req, err := http.NewRequestWithContext(context.Background(), "POST", url, bytes.NewBuffer(requestBody)) + if err != nil { + log.Fatalf("Error creating HTTP request: %v", err) + } + + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", "Bearer "+apiKey) + + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + log.Fatalf("Error sending HTTP request: %v", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + body, _ := io.ReadAll(resp.Body) + log.Fatalf("Request failed, status code: %d, response content: %s", resp.StatusCode, string(body)) + } + + reader := bufio.NewReader(resp.Body) + totalResponse := "" + for { + line, err := reader.ReadBytes('\n') + if err != nil { + if err == io.EOF { + break + } + log.Fatalf("Error reading response line: %v", err) + } + + if len(line) > 6 && string(line[:6]) == "data: " { + line = line[6:] + if strings.Contains(string(line), "[DONE]") { + break + } + + var chunk ChatCompletionChunk + err = json.Unmarshal(line, &chunk) + if err != nil { + log.Printf("Error parsing JSON chunk: %v, data: %s", err, string(line)) + continue + } + + for _, choice := range chunk.Choices { + fmt.Print(choice.Delta.Content) + totalResponse += choice.Delta.Content + } + } + } + messages = append(messages, Message{Role: "assistant", Content: totalResponse}) + fmt.Println() + } +} diff --git a/sdk/main.go b/sdk/main.go new file mode 100644 index 00000000..56ed722f --- /dev/null +++ b/sdk/main.go @@ -0,0 +1,259 @@ +package main + +import ( + "fmt" + "github.com/songquanpeng/one-api/model" + onesdk "github.com/songquanpeng/one-api/sdk/api" + "log" + "strconv" +) + +func main() { + // for test + config := onesdk.Config{ + Host: "http://127.0.0.1", + Port: 3000, + Key: "123456789012345678901234567890", + } + client := onesdk.OneClient{ + Config: &config, + } + + // 用户API使用测试 + // 添加用户 + user := onesdk.User{ + Username: "user1", + DisplayName: "user1", + Password: "user1@123_%6", + } + err := user.Add(&client) + if err != nil { + log.Fatal("add user err=", err) + } + fmt.Println("add user:", user, "success!") + // 查找用户 + users := onesdk.Users{} + // 可根据用户名、显示名、邮箱、手机号等信息进行模糊查询 + users.Query = map[string]string{ + "keyword": "user1", + } + err = users.List(&client) + if err != nil { + log.Fatal("list user err=", err) + } + tmpUser := onesdk.User{} + for i, u := range users.Users { + // 删除的不显示 + if u.Status == model.UserStatusDeleted { + continue + } + fmt.Println("user["+strconv.Itoa(i)+"]:", *u) + if u.Username == "user1" { + tmpUser = *u + } + } + fmt.Println("list user success!") + // 获取用户 + user = onesdk.User{} + user.ID = tmpUser.ID + err = user.Get(&client) + if err != nil { + log.Fatal("get user err=", err) + } + fmt.Println("get user:", user, "success!") + //更新用户 + user.Quota = 500000000 + err = user.Update(&client) + if err != nil { + log.Fatal("update user err=", err) + } + fmt.Println("update user:", user, "success!\r\n") + + // 渠道API使用测试 + channel := onesdk.Channel{ + Name: "ch1", + ChannelConfig: onesdk.ChannelConfig{ + Region: "", + Sk: "", + Ak: "", + }, + Group: "default", + Models: "moonshot-v1-8k,moonshot-v1-32k,moonshot-v1-128k", + ModelMapping: "", + Other: "", + SystemPrompt: "", + Type: 25, + Key: "key", + } + err = channel.Add(&client) + if err != nil { + log.Fatal("add channel err=", err) + } + fmt.Println("add channel:", channel, "success!") + // 查询渠道 + channels := onesdk.Channels{} + err = channels.List(&client) + channels.Query = map[string]string{ + "keyword": "ch1", + } + if err != nil { + log.Fatal("list channel err=", err) + } + tmpChannel := onesdk.Channel{} + for i, c := range channels.Channels { + fmt.Println("channel["+strconv.Itoa(i)+"]:", *c) + if c.Name == "ch1" { + tmpChannel = *c + } + } + fmt.Println("list channel success!") + // 更新渠道 + updateChannel := tmpChannel + updateChannel.Name = "ch1-updated" + err = updateChannel.Update(&client) + if err != nil { + log.Fatal("update channel err=", err) + } + fmt.Println("update channel:", updateChannel, "success!") + // 获取渠道 + channel = onesdk.Channel{} + channel.ID = tmpChannel.ID + err = channel.Get(&client) + if err != nil { + log.Fatal("get channel err=", err) + } + fmt.Println("get channel:", channel, "success!") + // 测试渠道(模型)是否正常 + err = channel.Test(&client) + if err != nil { + log.Fatal("test channel err=", err) + } + fmt.Println("test channel:", channel, "success!") + // 删除渠道 + err = updateChannel.Delete(&client) + if err != nil { + log.Fatal("delete channel err=", err) + } + fmt.Println("delete channel:", updateChannel, "success!\r\n") + + // 令牌API使用测试 + // 添加令牌 + token := onesdk.Token{ + Name: "token1", + UserID: user.ID, + Models: "/data/DeepSeek-R1,ERNIE-3.5-8K", + RemainQuota: 5000000000, + UnlimitedQuota: false, + ExpiredTime: -1, + Subnet: "", + } + err = token.Add(&client) + if err != nil { + log.Fatal("add token err=", err) + } + fmt.Println("add token:", token, "success!") + //查询令牌 + tokens := onesdk.Tokens{} + tokens.UserID = user.ID + tokens.Query = map[string]string{ + "keyword": "token1", + } + err = tokens.List(&client) + if err != nil { + log.Fatal("list token err=", err) + } + tmpToken := onesdk.Token{} + for i, t := range tokens.Tokens { + fmt.Println("token["+strconv.Itoa(i)+"]:", *t) + if t.Name == "token1" { + tmpToken = *t + } + } + //更新令牌 + token = tmpToken + token.Models = "/data/DeepSeek-R1" + token.RemainQuota = 9009000000 + err = token.Update(&client) + if err != nil { + log.Fatal("update token err=", err) + } + fmt.Println("update token:", token, "success!") + // 获取token + token = onesdk.Token{ID: token.ID, UserID: tmpToken.UserID} + err = token.Get(&client) + if err != nil { + log.Fatal("get token err=", err) + } + fmt.Println("get token:", token, "success!") + // delete token + err = token.Delete(&client) + if err != nil { + log.Fatal("delete token err=", err) + } + fmt.Println("delete token:", token, "success!\r\n") + + // 日志API使用测试 + logs := onesdk.Logs{} + logs.Query = map[string]string{ + "username": "user1", + } + err = logs.Get(&client) + if err != nil { + log.Fatal(err) + } + for i, l := range logs.Logs { + fmt.Println("log["+strconv.Itoa(i)+"]=", *l) + } + fmt.Println("get logs success!\r\n\r\n") + + // 删除用户 + err = user.Delete(&client) + if err != nil { + log.Fatal("delete user err=", err) + } + fmt.Println("delete user:", user, "success!") + + // 操作root自己的令牌 + rootToken := onesdk.Token{ + Name: "token1", + Models: "/data/DeepSeek-R1,ERNIE-3.5-8K", + RemainQuota: 5000000000, + UnlimitedQuota: false, + ExpiredTime: -1, + Subnet: "", + } + err = rootToken.Add(&client) + if err != nil { + log.Fatal("add root token err=", err) + } + fmt.Println("add root token:", rootToken, "success!") + //查询令牌 + tokens = onesdk.Tokens{} + tokens.Query = map[string]string{ + "keyword": "token1", + } + err = tokens.List(&client) + if err != nil { + log.Fatal("list root token err=", err) + } + tmpToken = onesdk.Token{} + for i, t := range tokens.Tokens { + fmt.Println("token["+strconv.Itoa(i)+"]:", *t) + if t.Name == "token1" { + tmpToken = *t + } + } + // 获取令牌 + rootToken = onesdk.Token{ID: tmpToken.ID} + err = rootToken.Get(&client) + if err != nil { + log.Fatal("get root token err=", err) + } + fmt.Println("get root token:", rootToken, "success!") + // 删除令牌 + err = rootToken.Delete(&client) + if err != nil { + log.Fatal("delete root token err=", err) + } + fmt.Println("delete root token:", rootToken, "success!") +} diff --git a/sdk/readme.md b/sdk/readme.md new file mode 100644 index 00000000..ef5e3931 --- /dev/null +++ b/sdk/readme.md @@ -0,0 +1,145 @@ +## golang sdk 使用方式 +### 1. 安装 + +``` +import sdk oneapi "github.com/songquanpeng/one-api/sdk/api" +``` +### 2. 初始化 + +``` +config := oneapi.Config{ + Host: "http://127.0.0.1", //实际使用时请替换为实际的host + Port: 3000, //实际使用时请替换为实际的port + Key: "12345678901234567890", //实际使用时请替换为root用户下生成的系统访问令牌 + } + client := oneapi.OneClient{ + Config: &config, +} +``` +### 3. 调用 + +``` +(1) 用户操作 + // 添加用户 + user := oneapi.User{ + Username: "test1", + DisplayName: "test1", + Password: "test@123_%6", + } + err := user.Add(&client) + // 查询用户(列表) + users := oneapi.Users{} + // 可以模糊查找条件,username LIKE ? or email LIKE ? or display_name LIKE ?", keyword, keyword+"%", keyword+"%", keyword+"%" + users.Query = map[string]string{ + "keyword": "test1", + } + err := users.List(&client) + // 根据uid获取用户 + user = oneapi.User{} + for _, u := range users.Users { + if u.Username == "test1" { + user.ID = u.ID + } + } + _ = u.Get(&client) + //更新用户信息 + user.Quota = 500000000 + err = user.Update(&client) + //删除用户 + //err = user.Delete(&client) + +``` +``` +(2) 渠道(模型)操作 + // 添加渠道 + channel := oneapi.Channel{ + Name: "ch1", + BaseUrl: "", + ChannelConfig: oneapi.ChannelConfig{ + Region: "", + Sk: "", + Ak: "", + }, + Group: "default", + Models: "deepseek-r1", + ModelMapping: "", + Other: "", + SystemPrompt: "", + Type: 50, //渠道类型是前端constant,参考web/default/src/constants/channel.constants.js 50是openai兼容格式 + Key: "12345678901234567890", + } + err = channel.Add(&client) + // 查询渠道 + channels := oneapi.Channels{} + err = channels.List(&client) + // 可模糊查询 + channels.Query = map[string]string{ + "keyword": "ch1", + } + // 修改渠道 + updateChannel := oneapi.Channel{} + for _, c := range channels.Channels { + if c.Name == "ch1" { + updateChannel = *c + } + } + // update channel + updateChannel.Name = "ch1-updated" + err = updateChannel.Update(&client) + //删除渠道 + //err = updateChannel.Delete(&client) + if err != nil { + log.Fatal(err) + } +``` +``` + (3) 令牌操作 + // 添加令牌 // expired_time : -1 ,models : "/data/DeepSeek-R1,ERNIE-3.5-8K" ,name : "test" ,remain_quota : 5000000000 ,subnet : "" ,unlimited_quota : false + token := oneapi.Token{ + Name: "test1", + UserID: user.ID, + Models: "/data/DeepSeek-R1,ERNIE-3.5-8K", + RemainQuota: 5000000000, + UnlimitedQuota: false, + ExpiredTime: -1, + Subnet: "", + } + err := token.Add(&client) + // list tokens + tokens := oneapi.Tokens{} + // 可模糊查询 + tokens.Query = map[string]string{ + "keyword": "test1", + } + // 根据uid获取令牌 + tokens.userID = user.ID + err := tokens.List(&client, 0) + if err != nil { + log.Fatal(err) + } + updateToken = tokens.Tokens[0] + //更新令牌 + updateToken.Models = "/data/DeepSeek-R1" + updateToken.RemainQuota = 9009000000 + err = updateToken.Update(&client) + fmt.Println("update token err=", err, "updateToken=", updateToken) + + //删除令牌 + err = updateToken.Delete(&client) + fmt.Println("delete token err=", err) +``` +``` + (4) 日志操作 + // 获取日志 + logs := oneapi.Logs{} + logs.Query = map[string]string{ + "username": "test", + } + err = logs.Get(&client) + if err != nil { + log.Fatal(err) + } + for _, l := range logs.Logs { + fmt.Println("l=", *l) + } +```