Files
kevinandClaude d57dff58f3 重构:把剩余 12 个顶层包全部迁到 internal/
继续之前的重构:把根目录残留的非数据/资源类子目录(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>
2026-06-18 18:43:42 +08:00

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
}