Merge pull request #826 from trheyi/main
Refactor Neo API assistant message handling and content processing
This commit is contained in:
commit
a8b82248a2
4 changed files with 121 additions and 15 deletions
|
|
@ -387,7 +387,11 @@ func (ast *Assistant) withHistory(ctx chatctx.Context, input string) ([]chatMess
|
||||||
|
|
||||||
// Add history messages
|
// Add history messages
|
||||||
for _, h := range history {
|
for _, h := range history {
|
||||||
messages = append(messages, *chatMessage.New().Map(h))
|
msgs, err := chatMessage.NewHistory(h)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
messages = append(messages, msgs...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -416,6 +420,7 @@ func (ast *Assistant) Chat(ctx context.Context, messages []chatMessage.Message,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ast *Assistant) requestMessages(ctx context.Context, messages []chatMessage.Message) ([]map[string]interface{}, error) {
|
func (ast *Assistant) requestMessages(ctx context.Context, messages []chatMessage.Message) ([]map[string]interface{}, error) {
|
||||||
|
|
||||||
newMessages := []map[string]interface{}{}
|
newMessages := []map[string]interface{}{}
|
||||||
length := len(messages)
|
length := len(messages)
|
||||||
|
|
||||||
|
|
@ -425,7 +430,7 @@ func (ast *Assistant) requestMessages(ctx context.Context, messages []chatMessag
|
||||||
return nil, fmt.Errorf("role must be string")
|
return nil, fmt.Errorf("role must be string")
|
||||||
}
|
}
|
||||||
|
|
||||||
content := message.Text
|
content := message.String()
|
||||||
if content == "" {
|
if content == "" {
|
||||||
return nil, fmt.Errorf("content must be string")
|
return nil, fmt.Errorf("content must be string")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -276,6 +276,12 @@ func (ast *Assistant) call(ctx context.Context, method string, c *gin.Context, c
|
||||||
return bridge.JsException(info.Context(), err.Error())
|
return bridge.JsException(info.Context(), err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save history by default
|
||||||
|
saveHistory := true
|
||||||
|
if len(args) > 1 && args[1].IsBoolean() {
|
||||||
|
saveHistory = args[1].Boolean()
|
||||||
|
}
|
||||||
|
|
||||||
switch v := input.(type) {
|
switch v := input.(type) {
|
||||||
case string:
|
case string:
|
||||||
// Check if the message is json
|
// Check if the message is json
|
||||||
|
|
@ -285,13 +291,17 @@ func (ast *Assistant) call(ctx context.Context, method string, c *gin.Context, c
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append the message to the contents
|
// Append the message to the contents
|
||||||
msg.AppendTo(contents)
|
if saveHistory {
|
||||||
|
msg.AppendTo(contents)
|
||||||
|
}
|
||||||
msg.Write(c.Writer)
|
msg.Write(c.Writer)
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
case map[string]interface{}:
|
case map[string]interface{}:
|
||||||
msg := message.New().Map(v)
|
msg := message.New().Map(v)
|
||||||
msg.AppendTo(contents)
|
if saveHistory {
|
||||||
|
msg.AppendTo(contents)
|
||||||
|
}
|
||||||
msg.Write(c.Writer)
|
msg.Write(c.Writer)
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,73 @@ func New() *Message {
|
||||||
return &Message{Actions: []Action{}, Props: map[string]interface{}{}}
|
return &Message{Actions: []Action{}, Props: map[string]interface{}{}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewHistory create a new message from history
|
||||||
|
func NewHistory(history map[string]interface{}) ([]Message, error) {
|
||||||
|
if history == nil {
|
||||||
|
return []Message{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var copy map[string]interface{} = map[string]interface{}{}
|
||||||
|
for key, value := range history {
|
||||||
|
if key != "content" {
|
||||||
|
copy[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
globalMessage := New().Map(copy)
|
||||||
|
messages := []Message{}
|
||||||
|
if content, ok := history["content"].(string); ok {
|
||||||
|
if strings.HasPrefix(content, "{") && strings.HasSuffix(content, "}") {
|
||||||
|
var msg Message = *globalMessage
|
||||||
|
if err := jsoniter.UnmarshalFromString(content, &msg); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
messages = append(messages, msg)
|
||||||
|
} else if strings.HasPrefix(content, "[") && strings.HasSuffix(content, "]") {
|
||||||
|
var msgs []Message
|
||||||
|
if err := jsoniter.UnmarshalFromString(content, &msgs); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, msg := range msgs {
|
||||||
|
msg.AssistantID = globalMessage.AssistantID
|
||||||
|
msg.AssistantName = globalMessage.AssistantName
|
||||||
|
msg.AssistantAvatar = globalMessage.AssistantAvatar
|
||||||
|
msg.Role = globalMessage.Role
|
||||||
|
msg.Name = globalMessage.Name
|
||||||
|
msg.Mentions = globalMessage.Mentions
|
||||||
|
messages = append(messages, msg)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
messages = append(messages, Message{Text: content})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return messages, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewContent create a new message from content
|
||||||
|
func NewContent(content string) ([]Message, error) {
|
||||||
|
messages := []Message{}
|
||||||
|
if strings.HasPrefix(content, "{") && strings.HasSuffix(content, "}") {
|
||||||
|
var msg Message
|
||||||
|
if err := jsoniter.UnmarshalFromString(content, &msg); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
messages = append(messages, msg)
|
||||||
|
} else if strings.HasPrefix(content, "[") && strings.HasSuffix(content, "]") {
|
||||||
|
var msgs []Message
|
||||||
|
if err := jsoniter.UnmarshalFromString(content, &msgs); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, msg := range msgs {
|
||||||
|
messages = append(messages, msg)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
messages = append(messages, Message{Text: content})
|
||||||
|
}
|
||||||
|
return messages, nil
|
||||||
|
}
|
||||||
|
|
||||||
// NewString create a new message from string
|
// NewString create a new message from string
|
||||||
func NewString(content string) (*Message, error) {
|
func NewString(content string) (*Message, error) {
|
||||||
if strings.HasPrefix(content, "{") && strings.HasSuffix(content, "}") {
|
if strings.HasPrefix(content, "{") && strings.HasSuffix(content, "}") {
|
||||||
|
|
@ -86,10 +153,6 @@ func NewOpenAI(data []byte) *Message {
|
||||||
msg := New()
|
msg := New()
|
||||||
text := string(data)
|
text := string(data)
|
||||||
data = []byte(strings.TrimPrefix(text, "data: "))
|
data = []byte(strings.TrimPrefix(text, "data: "))
|
||||||
// fmt.Println("--------------------------------")
|
|
||||||
// fmt.Println(string(data))
|
|
||||||
// fmt.Println("--------------------------------")
|
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
|
|
||||||
case strings.Contains(text, `"delta":{`) && strings.Contains(text, `"tool_calls"`):
|
case strings.Contains(text, `"delta":{`) && strings.Contains(text, `"tool_calls"`):
|
||||||
|
|
@ -138,10 +201,18 @@ func NewOpenAI(data []byte) *Message {
|
||||||
|
|
||||||
// String returns the string representation
|
// String returns the string representation
|
||||||
func (m *Message) String() string {
|
func (m *Message) String() string {
|
||||||
if m.Text != "" {
|
typ := m.Type
|
||||||
return m.Text
|
if typ == "" {
|
||||||
|
typ = "text"
|
||||||
|
}
|
||||||
|
|
||||||
|
switch typ {
|
||||||
|
case "text":
|
||||||
|
return m.Text
|
||||||
|
default:
|
||||||
|
raw, _ := jsoniter.MarshalToString(map[string]interface{}{"type": m.Type, "props": m.Props})
|
||||||
|
return raw
|
||||||
}
|
}
|
||||||
return ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetText set the text
|
// SetText set the text
|
||||||
|
|
@ -222,7 +293,7 @@ func (m *Message) AppendTo(contents *Contents) *Message {
|
||||||
contents.AppendFunction([]byte(m.Text))
|
contents.AppendFunction([]byte(m.Text))
|
||||||
return m
|
return m
|
||||||
|
|
||||||
case "loading":
|
case "loading", "error": // Ignore loading and error messages
|
||||||
return m
|
return m
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
@ -307,6 +378,11 @@ func (m *Message) Map(msg map[string]interface{}) *Message {
|
||||||
|
|
||||||
if assistantID, ok := msg["assistant_id"].(string); ok {
|
if assistantID, ok := msg["assistant_id"].(string); ok {
|
||||||
m.AssistantID = assistantID
|
m.AssistantID = assistantID
|
||||||
|
|
||||||
|
// Set name
|
||||||
|
if m.Role == "assistant" {
|
||||||
|
m.Name = m.AssistantID
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if assistantName, ok := msg["assistant_name"].(string); ok {
|
if assistantName, ok := msg["assistant_name"].(string); ok {
|
||||||
|
|
|
||||||
21
neo/neo.go
21
neo/neo.go
|
|
@ -104,10 +104,25 @@ func (neo *DSL) GenerateWithAI(ctx chatctx.Context, input string, messageType st
|
||||||
|
|
||||||
// Chat with AI in background
|
// Chat with AI in background
|
||||||
go func() {
|
go func() {
|
||||||
msgList := make([]message.Message, len(messages))
|
msgList := []message.Message{}
|
||||||
for i, msg := range messages {
|
for _, vv := range messages {
|
||||||
msgList[i] = *message.New().Map(msg)
|
msg := message.New().Map(vv)
|
||||||
|
if content, ok := vv["content"].(string); ok {
|
||||||
|
msgs, err := message.NewContent(content)
|
||||||
|
if err == nil {
|
||||||
|
for _, v := range msgs {
|
||||||
|
v.AssistantID = msg.AssistantID
|
||||||
|
v.AssistantName = msg.AssistantName
|
||||||
|
v.AssistantAvatar = msg.AssistantAvatar
|
||||||
|
v.Role = msg.Role
|
||||||
|
v.Name = msg.Name
|
||||||
|
v.Mentions = msg.Mentions
|
||||||
|
msgList = append(msgList, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err := ast.Chat(c.Request.Context(), msgList, neo.Option, func(data []byte) int {
|
err := ast.Chat(c.Request.Context(), msgList, neo.Option, func(data []byte) int {
|
||||||
select {
|
select {
|
||||||
case <-clientBreak:
|
case <-clientBreak:
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue