-
Notifications
You must be signed in to change notification settings - Fork 800
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
b08c36b
commit ec45794
Showing
14 changed files
with
367 additions
and
9 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
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
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
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,24 @@ | ||
package slack | ||
|
||
import ( | ||
"chat/globals" | ||
"context" | ||
"github.com/spf13/viper" | ||
) | ||
|
||
type ChatProps struct { | ||
Message []globals.Message | ||
} | ||
|
||
func (c *ChatInstance) CreateStreamChatRequest(props *ChatProps, hook globals.Hook) error { | ||
if err := c.Instance.NewChannel(viper.GetString("slack.channel")); err != nil { | ||
return err | ||
} | ||
|
||
resp, err := c.Instance.Reply(context.Background(), c.FormatMessage(props.Message), nil) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return c.ProcessPartialResponse(resp, hook) | ||
} |
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,77 @@ | ||
package slack | ||
|
||
import ( | ||
"chat/globals" | ||
"fmt" | ||
"github.com/bincooo/claude-api" | ||
"github.com/bincooo/claude-api/types" | ||
"github.com/bincooo/claude-api/vars" | ||
"github.com/spf13/viper" | ||
"strings" | ||
) | ||
|
||
type ChatInstance struct { | ||
BotId string | ||
Token string | ||
Instance types.Chat | ||
} | ||
|
||
func (c *ChatInstance) GetBotId() string { | ||
return c.BotId | ||
} | ||
|
||
func (c *ChatInstance) GetToken() string { | ||
return c.Token | ||
} | ||
|
||
func (c *ChatInstance) GetInstance() types.Chat { | ||
return c.Instance | ||
} | ||
|
||
func NewChatInstance(botId, token string) *ChatInstance { | ||
options := claude.NewDefaultOptions(token, botId, vars.Model4Slack) | ||
if instance, err := claude.New(options); err != nil { | ||
return nil | ||
} else { | ||
return &ChatInstance{ | ||
BotId: botId, | ||
Token: token, | ||
Instance: instance, | ||
} | ||
} | ||
} | ||
|
||
func NewChatInstanceFromConfig() *ChatInstance { | ||
return NewChatInstance( | ||
viper.GetString("slack.bot_id"), | ||
viper.GetString("slack.token"), | ||
) | ||
} | ||
|
||
func (c *ChatInstance) FormatMessage(message []globals.Message) string { | ||
result := make([]string, len(message)) | ||
for i, item := range message { | ||
result[i] = fmt.Sprintf("%s: %s", item.Role, item.Content) | ||
} | ||
|
||
return strings.Join(result, "\n\n") | ||
} | ||
|
||
func (c *ChatInstance) ProcessPartialResponse(res chan types.PartialResponse, hook globals.Hook) error { | ||
for { | ||
select { | ||
case data, ok := <-res: | ||
if !ok { | ||
return nil | ||
} | ||
|
||
if data.Error != nil { | ||
return data.Error | ||
} else if data.Text != "" { | ||
if err := hook(data.Text); err != nil { | ||
return err | ||
} | ||
} | ||
} | ||
} | ||
} |
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,54 @@ | ||
package sparkdesk | ||
|
||
import ( | ||
"chat/globals" | ||
"chat/utils" | ||
"fmt" | ||
) | ||
|
||
type ChatProps struct { | ||
Message []globals.Message | ||
Token int | ||
} | ||
|
||
func (c *ChatInstance) CreateStreamChatRequest(props *ChatProps, hook globals.Hook) error { | ||
var conn *utils.WebSocket | ||
if conn = utils.NewWebsocketClient(c.GenerateUrl()); conn == nil { | ||
return fmt.Errorf("sparkdesk error: websocket connection failed") | ||
} | ||
defer conn.DeferClose() | ||
|
||
if err := conn.SendJSON(&ChatRequest{ | ||
Header: RequestHeader{ | ||
AppId: c.AppId, | ||
}, | ||
Payload: RequestPayload{ | ||
Message: MessagePayload{ | ||
Text: props.Message, | ||
}, | ||
}, | ||
Parameter: RequestParameter{ | ||
Chat: ChatParameter{ | ||
Domain: c.Model, | ||
MaxToken: props.Token, | ||
}, | ||
}, | ||
}); err != nil { | ||
return err | ||
} | ||
|
||
for { | ||
form := utils.ReadForm[ChatResponse](conn) | ||
if form == nil { | ||
return nil | ||
} | ||
|
||
if form.Header.Code != 0 { | ||
return fmt.Errorf("sparkdesk error: %s (sid: %s)", form.Header.Message, form.Header.Sid) | ||
} | ||
|
||
if err := hook(form.Payload.Choices.Text[0].Content); err != nil { | ||
return err | ||
} | ||
} | ||
} |
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,72 @@ | ||
package sparkdesk | ||
|
||
import ( | ||
"crypto/hmac" | ||
"crypto/sha256" | ||
"encoding/base64" | ||
"fmt" | ||
"github.com/spf13/viper" | ||
"net/url" | ||
"strings" | ||
"time" | ||
) | ||
|
||
type ChatInstance struct { | ||
AppId string | ||
ApiSecret string | ||
ApiKey string | ||
Model string | ||
Endpoint string | ||
} | ||
|
||
func NewChatInstance() *ChatInstance { | ||
return &ChatInstance{ | ||
AppId: viper.GetString("sparkdesk.app_id"), | ||
ApiSecret: viper.GetString("sparkdesk.api_secret"), | ||
ApiKey: viper.GetString("sparkdesk.api_key"), | ||
Model: viper.GetString("sparkdesk.model"), | ||
Endpoint: viper.GetString("sparkdesk.endpoint"), | ||
} | ||
} | ||
|
||
func (c *ChatInstance) CreateUrl(host, date, auth string) string { | ||
v := make(url.Values) | ||
v.Add("host", host) | ||
v.Add("date", date) | ||
v.Add("authorization", auth) | ||
return fmt.Sprintf("%s?%s", c.Endpoint, v.Encode()) | ||
} | ||
|
||
func (c *ChatInstance) Sign(data, key string) string { | ||
mac := hmac.New(sha256.New, []byte(key)) | ||
mac.Write([]byte(data)) | ||
return base64.StdEncoding.EncodeToString(mac.Sum(nil)) | ||
} | ||
|
||
// GenerateUrl will generate the signed url for sparkdesk api | ||
func (c *ChatInstance) GenerateUrl() string { | ||
uri, err := url.Parse(c.Endpoint) | ||
if err != nil { | ||
return "" | ||
} | ||
|
||
date := time.Now().UTC().Format(time.RFC1123) | ||
data := strings.Join([]string{ | ||
fmt.Sprintf("host: %s", uri.Host), | ||
fmt.Sprintf("date: %s", date), | ||
fmt.Sprintf("GET %s HTTP/1.1", uri.Path), | ||
}, "\n") | ||
|
||
signature := c.Sign(data, c.ApiSecret) | ||
authorization := base64.StdEncoding.EncodeToString([]byte( | ||
fmt.Sprintf( | ||
"hmac username=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", | ||
c.ApiKey, | ||
"hmac-sha256", | ||
"host date request-line", | ||
signature, | ||
), | ||
)) | ||
|
||
return c.CreateUrl(uri.Host, date, authorization) | ||
} |
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,60 @@ | ||
package sparkdesk | ||
|
||
import "chat/globals" | ||
|
||
// ChatRequest is the request body for sparkdesk | ||
type ChatRequest struct { | ||
Header RequestHeader `json:"header"` | ||
Payload RequestPayload `json:"payload"` | ||
Parameter RequestParameter `json:"parameter"` | ||
} | ||
|
||
type RequestHeader struct { | ||
AppId string `json:"app_id"` | ||
} | ||
|
||
type RequestPayload struct { | ||
Message MessagePayload `json:"message"` | ||
} | ||
|
||
type MessagePayload struct { | ||
Text []globals.Message `json:"text"` | ||
} | ||
|
||
type RequestParameter struct { | ||
Chat ChatParameter `json:"chat"` | ||
} | ||
|
||
type ChatParameter struct { | ||
Domain string `json:"domain"` | ||
MaxToken int `json:"max_tokens"` | ||
} | ||
|
||
// ChatResponse is the websocket partial response body for sparkdesk | ||
type ChatResponse struct { | ||
Header struct { | ||
Code int `json:"code" required:"true"` | ||
Message string `json:"message"` | ||
Sid string `json:"sid"` | ||
Status int `json:"status"` | ||
} `json:"header"` | ||
Payload struct { | ||
Choices struct { | ||
Status int `json:"status"` | ||
Seq int `json:"seq"` | ||
Text []struct { | ||
Role string `json:"role"` | ||
Content string `json:"content"` | ||
Index int `json:"index"` | ||
} `json:"text"` | ||
} `json:"choices"` | ||
Usage struct { | ||
Text struct { | ||
QuestionTokens int `json:"question_tokens"` | ||
PromptTokens int `json:"prompt_tokens"` | ||
CompletionTokens int `json:"completion_tokens"` | ||
TotalTokens int `json:"total_tokens"` | ||
} | ||
} | ||
} | ||
} |
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
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
Oops, something went wrong.