You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
116 lines
2.8 KiB
116 lines
2.8 KiB
package mcp
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
|
|
"yunyan/lego/core"
|
|
"yunyan/lego/core/cbase"
|
|
"yunyan/lego/sys/log"
|
|
lgmigu "yunyan/sys/migu"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/mark3labs/mcp-go/mcp"
|
|
)
|
|
|
|
type tool_migu_music struct {
|
|
cbase.ModuleCompBase
|
|
module *Mcp
|
|
}
|
|
|
|
func (this *tool_migu_music) Init(service core.IService, module core.IModule, comp core.IModuleComp, opt core.IModuleOptions) (err error) {
|
|
this.ModuleCompBase.Init(service, module, comp, opt)
|
|
this.module = module.(*Mcp)
|
|
return
|
|
}
|
|
|
|
func (this *tool_migu_music) Start() (err error) {
|
|
err = this.ModuleCompBase.Start()
|
|
if this.module.AddTool(ToolGroup_CHINA, this.Tool(), this.Handl) {
|
|
if initErr := lgmigu.OnInit(this.module.service.GetSettings().Sys["migu"]); initErr != nil {
|
|
panic(fmt.Sprintf("init sys.migu err: %s", initErr.Error()))
|
|
} else {
|
|
log.Infof("init sys.migu success!")
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func (this *tool_migu_music) Tool() mcp.Tool {
|
|
return mcp.NewTool("migu_music_search",
|
|
mcp.WithDescription("通过咪咕灵犀搜索音乐,返回带播放信息的音乐列表卡片"),
|
|
mcp.WithString("query",
|
|
mcp.Description("搜索的音乐关键字,例如:小苹果、周杰伦、流行音乐等"),
|
|
mcp.Required(),
|
|
),
|
|
)
|
|
}
|
|
|
|
// MiguMusicCard 单条咪咕音乐卡片(H5/模板卡片的原始结构)
|
|
type MiguMusicCard struct {
|
|
Type string `json:"type"` // "2"=H5, "3"=模板
|
|
Data json.RawMessage `json:"data"` // 咪咕返回的原始卡片数据
|
|
}
|
|
|
|
func (this *tool_migu_music) Handl(ctx context.Context, request mcp.CallToolRequest) (result *mcp.CallToolResult, err error) {
|
|
query, err := request.RequireString("query")
|
|
if err != nil {
|
|
err = fmt.Errorf("query is required")
|
|
return
|
|
}
|
|
|
|
reqId := uuid.NewString()
|
|
miguReq := &lgmigu.Request{
|
|
ReqId: reqId,
|
|
Messages: []lgmigu.Message{{Role: "user", Content: fmt.Sprintf("帮我搜索并播放:%s", query)}},
|
|
Stream: true,
|
|
Session: &lgmigu.Session{SessionId: reqId},
|
|
}
|
|
|
|
ch := make(chan *lgmigu.StreamResp, 8)
|
|
go func() {
|
|
if e := lgmigu.Chat(ctx, miguReq, ch); e != nil {
|
|
log.Errorf("migu music search err: %v", e)
|
|
}
|
|
}()
|
|
|
|
var cards []*MiguMusicCard
|
|
for sr := range ch {
|
|
if sr == nil || len(sr.Choices) == 0 {
|
|
continue
|
|
}
|
|
c := sr.Choices[0]
|
|
if c.Delta.Content == nil {
|
|
continue
|
|
}
|
|
switch c.Delta.Content.Type {
|
|
case lgmigu.ContentTypeH5, lgmigu.ContentTypeTemplate:
|
|
cards = append(cards, &MiguMusicCard{
|
|
Type: c.Delta.Content.Type,
|
|
Data: c.Delta.Content.Data,
|
|
})
|
|
}
|
|
}
|
|
|
|
var text string
|
|
if len(cards) == 0 {
|
|
text = fmt.Sprintf(`{"result":"no_music","message":"未找到相关音乐:%s"}`, query)
|
|
} else {
|
|
b, _ := json.Marshal(map[string]interface{}{
|
|
"result": "success",
|
|
"data": cards,
|
|
})
|
|
text = string(b)
|
|
}
|
|
|
|
result = &mcp.CallToolResult{
|
|
Content: []mcp.Content{
|
|
mcp.TextContent{
|
|
Type: "text",
|
|
Text: text,
|
|
},
|
|
},
|
|
}
|
|
return
|
|
}
|
|
|