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.
190 lines
5.4 KiB
190 lines
5.4 KiB
package mcp
|
|
|
|
import (
|
|
"context"
|
|
"yunyan/lego/core"
|
|
"yunyan/lego/core/cbase"
|
|
"yunyan/lego/sys/log"
|
|
"yunyan/sys/amap"
|
|
"yunyan/utils"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/mark3labs/mcp-go/mcp"
|
|
)
|
|
|
|
// 天气卡片数据 结构统一化输出
|
|
type WeatherCard struct {
|
|
City string `json:"city"` //城市
|
|
Day *WeatherCarditem `json:"day"` //查询的天气
|
|
DayWeather []*WeatherCarditem `json:"dayweather"` //天气
|
|
}
|
|
|
|
// 天气卡片数据 结构统一化输出
|
|
type WeatherCarditem struct {
|
|
Date string `json:"date"` //时间
|
|
Temperature string `json:"temperature"` //实时温度
|
|
MinTemperature string `json:"minTemperature"` //最低温度
|
|
MaxTemperature string `json:"maxTemperature"` //最高温度
|
|
WeatherCondition string `json:"weatherCondition"` //天气现象,如:"阴"
|
|
WindDirection string `json:"windDirection"` //风向
|
|
WindForce string `json:"windForce"` //风力
|
|
}
|
|
|
|
// 天气查询
|
|
type tool_gaode_map_weather struct {
|
|
cbase.ModuleCompBase
|
|
module *Mcp
|
|
}
|
|
|
|
// 组件初始化接口
|
|
func (this *tool_gaode_map_weather) 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_gaode_map_weather) Start() (err error) {
|
|
err = this.ModuleCompBase.Start()
|
|
if this.module.AddTool(ToolGroup_CHINA, this.Tool(), this.Handl) {
|
|
if err := amap.OnInit(this.module.service.GetSettings().Sys["amap"]); err != nil {
|
|
panic(fmt.Sprintf("init sys.amap err: %s", err.Error()))
|
|
} else {
|
|
log.Infof("init sys.amap success!")
|
|
}
|
|
}
|
|
return
|
|
}
|
|
func (this *tool_gaode_map_weather) Tool() (tool mcp.Tool) {
|
|
return mcp.NewTool("gaode_map_weather",
|
|
mcp.WithDescription("根据城市名称查询对应城市的当前实时天气信息"),
|
|
mcp.WithString("city",
|
|
mcp.Description("城市名称 例如:'北京市'"),
|
|
mcp.Required(),
|
|
),
|
|
mcp.WithString("time",
|
|
mcp.Description("查询时间 ,格式:'yyyy-MM-dd',例如:'2025-03-12'"),
|
|
),
|
|
)
|
|
}
|
|
|
|
// Handl 工具处理接口
|
|
// 参数:
|
|
// - ctx: 上下文
|
|
// - request: MCP 工具调用请求
|
|
//
|
|
// 返回值:
|
|
// - result: MCP 工具调用结果
|
|
// - err: 处理过程中的错误
|
|
//
|
|
// 异常:
|
|
// - 无(不主动 panic)
|
|
func (this *tool_gaode_map_weather) Handl(ctx context.Context, request mcp.CallToolRequest) (result *mcp.CallToolResult, err error) {
|
|
var (
|
|
city string
|
|
day string
|
|
georesult *amap.GeocodeResponse
|
|
weatherresult *amap.WeatherResponse
|
|
daydata *WeatherCarditem
|
|
card *WeatherCard
|
|
context string
|
|
)
|
|
this.module.Debug("tool_gaode_map_weather",
|
|
log.Field{Key: "request.Params.Arguments", Value: request.GetRawArguments()},
|
|
)
|
|
day = request.GetString("time", "")
|
|
if day == "" {
|
|
day = time.Now().Format("2006-01-02")
|
|
} else {
|
|
if !isValidDate(day) {
|
|
switch day {
|
|
case "今天":
|
|
day = time.Now().Format("2006-01-02")
|
|
case "明天":
|
|
day = time.Now().AddDate(0, 0, 1).Format("2006-01-02")
|
|
case "后天":
|
|
day = time.Now().AddDate(0, 0, 2).Format("2006-01-02")
|
|
default:
|
|
day = time.Now().Format("2006-01-02")
|
|
}
|
|
}
|
|
}
|
|
if city, err = request.RequireString("city"); err != nil || city == "" {
|
|
err = fmt.Errorf("必要参数丢失")
|
|
}
|
|
if err == nil {
|
|
if georesult, err = amap.Geo("", city); err == nil {
|
|
if georesult.Geocodes != nil && len(georesult.Geocodes) > 0 {
|
|
weatherresult, err = amap.Weather(georesult.Geocodes[0].Adcode, "all")
|
|
} else {
|
|
err = fmt.Errorf("查询目标城市信息失败 city:%s", city)
|
|
}
|
|
}
|
|
}
|
|
if err != nil {
|
|
context = "获取天气信息失败"
|
|
this.module.Debug("tool_gaode_map_weather fail",
|
|
log.Field{Key: "city", Value: city},
|
|
log.Field{Key: "day", Value: day},
|
|
log.Field{Key: "err", Value: err},
|
|
)
|
|
} else {
|
|
if len(weatherresult.Forecasts) > 0 && weatherresult.Forecasts[0].Casts != nil && len(weatherresult.Forecasts[0].Casts) > 0 {
|
|
card = &WeatherCard{
|
|
City: city,
|
|
DayWeather: make([]*WeatherCarditem, 0),
|
|
}
|
|
for _, v := range weatherresult.Forecasts[0].Casts {
|
|
daydata = &WeatherCarditem{
|
|
Date: v.Date,
|
|
Temperature: v.Daytemp,
|
|
MinTemperature: v.Nighttemp,
|
|
MaxTemperature: v.Daytemp,
|
|
WeatherCondition: v.Dayweather,
|
|
WindDirection: v.Daywind,
|
|
WindForce: v.Daypower,
|
|
}
|
|
card.DayWeather = append(card.DayWeather, daydata)
|
|
if strings.Contains(v.Date, day) {
|
|
card.Day = daydata
|
|
context = fmt.Sprintf("%s:%s的天气情况:%s,温度:%s,风向:%s,风力:%s",
|
|
city,
|
|
day,
|
|
v.Dayweather,
|
|
v.Daytemp,
|
|
v.Daywind,
|
|
v.Daypower,
|
|
)
|
|
}
|
|
}
|
|
if card.Day == nil {
|
|
card.Day = card.DayWeather[0]
|
|
}
|
|
if context == "" {
|
|
context = utils.ToString(weatherresult)
|
|
}
|
|
this.module.Debug("tool_gaode_map_weather success",
|
|
log.Field{Key: "city", Value: city},
|
|
log.Field{Key: "card", Value: card},
|
|
log.Field{Key: "context", Value: context},
|
|
)
|
|
} else {
|
|
context = "获取天气信息失败,我只能获取未来4天的天气数据"
|
|
}
|
|
|
|
}
|
|
result = &mcp.CallToolResult{
|
|
Content: []mcp.Content{
|
|
mcp.TextContent{
|
|
Type: "text",
|
|
Text: context,
|
|
},
|
|
},
|
|
}
|
|
// if card != nil {
|
|
// result.Meta = map[string]interface{}{
|
|
// "card_weather": card,
|
|
// }
|
|
// }
|
|
return
|
|
}
|
|
|