继续之前的重构:把根目录残留的非数据/资源类子目录(agents、agenttool、ai、 autoreply、completion、conversation、llm、message、mqtpp、stream、 toolmanager、toolrouter)一并搬到 internal/ 下,并把全工程引用它们的 import 路径从 "meshtastic_mqtt_server/<x>" 重写为 "meshtastic_mqtt_server/internal/<x>"。 变更 - git mv 12 个顶层目录进 internal/,无函数体改动。 - 全工程 sed 把 import path 加上 internal/ 前缀,包括 main.go、 internal/bot/bot_service.go、internal/store/bot_store.go 中对 mqtpp 的引用,以及 ai 子系统内部 agents/agenttool/autoreply/conversation/ llm/toolmanager/toolrouter 之间的相互引用。 验证 - go build ./... 通过;go test ./... 全部包通过。 - AI 自动回复链路(main → ai.NewService → autoreply.Service → botSender) 保持不变,仅 import 路径调整。 - 根目录最终只剩 main.go / main_test.go / internal/ 加 go.mod / go.sum 与数据资源目录(dist、doc、firmware、py、win、meshmap_frontend)。 Co-Authored-By: Claude <noreply@anthropic.com>
116 lines
3.5 KiB
Go
116 lines
3.5 KiB
Go
package completion
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"meshtastic_mqtt_server/internal/llm"
|
|
"meshtastic_mqtt_server/internal/message"
|
|
|
|
"github.com/volcengine/volcengine-go-sdk/service/arkruntime/model"
|
|
)
|
|
|
|
// ChatCompleter is a function that completes a chat
|
|
type ChatCompleter func(ctx context.Context, profile *llm.Profile, req model.CreateChatCompletionRequest, timeout time.Duration) (model.ChatCompletionResponse, error)
|
|
|
|
// CompleteChat completes a chat conversation
|
|
func CompleteChat(ctx context.Context, profile *llm.Profile, req model.CreateChatCompletionRequest, timeout time.Duration) (model.ChatCompletionResponse, error) {
|
|
if profile == nil || profile.Client == nil {
|
|
return model.ChatCompletionResponse{}, fmt.Errorf("llm profile or client is nil")
|
|
}
|
|
|
|
// Use context with timeout if provided
|
|
if timeout > 0 {
|
|
var cancel context.CancelFunc
|
|
ctx, cancel = context.WithTimeout(ctx, timeout)
|
|
defer cancel()
|
|
}
|
|
|
|
resp, err := profile.Client.CreateChatCompletion(ctx, req)
|
|
if err != nil {
|
|
return model.ChatCompletionResponse{}, fmt.Errorf("chat completion failed: %w", err)
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
// CompleteText completes a text prompt using conversation messages
|
|
// If systemPrompt is not empty, it will be added as the first message
|
|
func CompleteText(ctx context.Context, profile *llm.Profile, systemPrompt string, messages []message.ChatMessage, maxTokens int) (string, error) {
|
|
if profile == nil || profile.Client == nil {
|
|
return "", fmt.Errorf("llm profile or client is nil")
|
|
}
|
|
|
|
arkMessages := make([]*model.ChatCompletionMessage, 0, len(messages)+1)
|
|
|
|
// Add system prompt if provided
|
|
if strings.TrimSpace(systemPrompt) != "" {
|
|
content := &model.ChatCompletionMessageContent{
|
|
StringValue: &systemPrompt,
|
|
}
|
|
arkMessages = append(arkMessages, &model.ChatCompletionMessage{
|
|
Role: "system",
|
|
Content: content,
|
|
})
|
|
}
|
|
|
|
for _, msg := range messages {
|
|
content := &model.ChatCompletionMessageContent{
|
|
StringValue: &msg.Content,
|
|
}
|
|
arkMessages = append(arkMessages, &model.ChatCompletionMessage{
|
|
Role: msg.Role,
|
|
Content: content,
|
|
})
|
|
}
|
|
|
|
req := model.CreateChatCompletionRequest{
|
|
Model: profile.Config.Model,
|
|
Messages: arkMessages,
|
|
MaxTokens: &maxTokens,
|
|
}
|
|
|
|
resp, err := profile.Client.CreateChatCompletion(ctx, req)
|
|
if err != nil {
|
|
return "", fmt.Errorf("text completion failed: %w", err)
|
|
}
|
|
|
|
if len(resp.Choices) == 0 {
|
|
return "", fmt.Errorf("no completion choices returned")
|
|
}
|
|
|
|
if resp.Choices[0].Message.Content != nil && resp.Choices[0].Message.Content.StringValue != nil {
|
|
return *resp.Choices[0].Message.Content.StringValue, nil
|
|
}
|
|
return "", nil
|
|
}
|
|
|
|
// CompleteTextWithArkMessages completes a text prompt using already converted Ark messages
|
|
// This is used when messages have already been converted (e.g. after tool loop)
|
|
func CompleteTextWithArkMessages(ctx context.Context, profile *llm.Profile, arkMessages []*model.ChatCompletionMessage, maxTokens int) (string, error) {
|
|
if profile == nil || profile.Client == nil {
|
|
return "", fmt.Errorf("llm profile or client is nil")
|
|
}
|
|
|
|
req := model.CreateChatCompletionRequest{
|
|
Model: profile.Config.Model,
|
|
Messages: arkMessages,
|
|
MaxTokens: &maxTokens,
|
|
}
|
|
|
|
resp, err := profile.Client.CreateChatCompletion(ctx, req)
|
|
if err != nil {
|
|
return "", fmt.Errorf("text completion failed: %w", err)
|
|
}
|
|
|
|
if len(resp.Choices) == 0 {
|
|
return "", fmt.Errorf("no completion choices returned")
|
|
}
|
|
|
|
if resp.Choices[0].Message.Content != nil && resp.Choices[0].Message.Content.StringValue != nil {
|
|
return *resp.Choices[0].Message.Content.StringValue, nil
|
|
}
|
|
return "", nil
|
|
}
|