package public import ( "ai_scheduler/internal/config" "ai_scheduler/internal/entitys" "ai_scheduler/internal/pkg/l_request" "log" "strconv" "context" "encoding/json" "fmt" "time" ) // WeatherTool 天气查询工具 type WeatherTool struct { mockData bool config config.ToolConfig } // NewWeatherTool 创建天气工具 func NewWeatherTool(config config.ToolConfig) *WeatherTool { return &WeatherTool{config: config} } // Name 返回工具名称 func (w *WeatherTool) Name() string { return "get_weather" } // Description 返回工具描述 func (w *WeatherTool) Description() string { return "获取指定城市的天气信息" } // Definition 返回工具定义 func (w *WeatherTool) Definition() entitys.ToolDefinition { return entitys.ToolDefinition{ Type: "function", Function: entitys.FunctionDef{ Name: w.Name(), Description: w.Description(), Parameters: map[string]interface{}{ "type": "object", "properties": map[string]interface{}{ "city": map[string]interface{}{ "type": "string", "description": "城市名称,如:北京、上海、广州", }, "unit": map[string]interface{}{ "type": "string", "description": "温度单位,celsius(摄氏度)或fahrenheit(华氏度)", "enum": []string{"celsius", "fahrenheit"}, "default": "celsius", }, "extensions": map[string]interface{}{ "type": "string", "description": "扩展参数,base/all base:返回实况天气 all:返回预报天气", "enum": []string{"base", "all"}, "default": "base", }, }, "required": []string{"city"}, }, }, } } // WeatherRequest 天气请求参数 type WeatherRequest struct { City string `json:"city"` Extensions string `json:"extensions"` // 扩展参数,base/all base:返回实况天气 all:返回预报天气 Unit string `json:"unit,omitempty"` } // WeatherResponse 天气响应 type WeatherResponse struct { City string `json:"city"` Unit string `json:"unit"` Timestamp string `json:"timestamp"` LiveWeather *LiveWeather `json:"live_weather,omitempty"` // 实时天气 Forecasts []ForecastWeather `json:"forecasts,omitempty"` // 预报天气 } // ForecastWeather 预报天气 type ForecastWeather struct { Date string `json:"date"` Week string `json:"week"` DayWeather string `json:"day_weather"` NightWeather string `json:"night_weather"` DayTemp float64 `json:"day_temp"` NightTemp float64 `json:"night_temp"` DayWind string `json:"day_wind"` NightWind string `json:"night_wind"` DayWindPower string `json:"day_wind_power"` NightWindPower string `json:"night_wind_power"` } // LiveWeather 实时天气 type LiveWeather struct { Temperature float64 `json:"temperature"` Condition string `json:"condition"` Humidity int `json:"humidity"` WindSpeed float64 `json:"wind_speed"` WindDirection string `json:"wind_direction"` } // Execute 执行天气查询 func (w *WeatherTool) Execute(ctx context.Context, requireData *entitys.RequireData) error { var req WeatherRequest if err := json.Unmarshal([]byte(requireData.Match.Parameters), &req); err != nil { return fmt.Errorf("invalid weather request: %w", err) } if req.City == "" { return fmt.Errorf("city is required") } if req.Unit == "" { req.Unit = "celsius" } // 设置默认获取实时天气信息 if req.Extensions == "" { req.Extensions = "base" } // 这里可以集成真实的天气API responseMsg, err := w.getRealWeather(req) if err != nil { return fmt.Errorf("failed to get real weather: %w", err) } // 根据 extensions 参数返回不同的天气信息 if req.Extensions == "base" { entitys.ResText(requireData.Ch, "", fmt.Sprintf("%s实时天气:%s,温度:%.1f℃,湿度:%d%%,风速:%.1fkm/h,风向:%s", req.City, responseMsg.LiveWeather.Condition, responseMsg.LiveWeather.Temperature, responseMsg.LiveWeather.Humidity, responseMsg.LiveWeather.WindSpeed, responseMsg.LiveWeather.WindDirection)) } else { rspStr := fmt.Sprintf("%s天气预报:\n", req.City) for _, forecast := range responseMsg.Forecasts { rspStr += fmt.Sprintf("%s 温度:%.1f℃/%.1f℃ 风力:%s %s\n", forecast.Date, forecast.DayTemp, forecast.NightTemp, forecast.DayWind, forecast.NightWind) } entitys.ResText(requireData.Ch, "", rspStr) } return nil } //// getMockWeather 获取模拟天气数据 //func (w *WeatherTool) getMockWeather(city, unit string) *WeatherResponse { // rand.Seed(time.Now().UnixNano()) // // // 模拟不同城市的基础温度 // baseTemp := map[string]float64{ // "北京": 15.0, // "上海": 18.0, // "广州": 25.0, // "深圳": 26.0, // "杭州": 17.0, // "成都": 16.0, // } // // temp := baseTemp[city] // if temp == 0 { // temp = 20.0 // 默认温度 // } // // // 添加随机变化 // temp += (rand.Float64() - 0.5) * 10 // // // 转换温度单位 // if unit == "fahrenheit" { // temp = temp*9/5 + 32 // } // // conditions := []string{"晴朗", "多云", "阴天", "小雨", "中雨"} // condition := conditions[rand.Intn(len(conditions))] // // return &WeatherResponse{ // City: city, // Temperature: float64(int(temp*10)) / 10, // 保留一位小数 // Unit: unit, // Condition: condition, // Humidity: rand.Intn(40) + 40, // 40-80% // WindSpeed: float64(rand.Intn(20)) + 1.0, // Timestamp: time.Now().Format("2006-01-02 15:04:05"), // } //} // getRealWeather 调用高德天气API func (w *WeatherTool) getRealWeather(request WeatherRequest) (*WeatherResponse, error) { // 构建请求URL req := l_request.Request{ Url: w.config.BaseURL, Headers: map[string]string{}, Params: map[string]string{ "city": request.City, // 城市名称 "key": w.config.APIKey, // API密钥 // extensions: 基础天气数据 可选值:base/all base:返回实况天气 all:返回预报天气 "extensions": request.Extensions, // 基础天气数据 "output": "JSON", // JSON格式返回 }, Method: "GET", } res, err := req.Send() if err != nil { return nil, err } // 解析API响应 var apiResp struct { Status string `json:"status"` Count string `json:"count"` Info string `json:"info"` Infocode string `json:"infocode"` // 预报天气信息数据 Forecasts []struct { City string `json:"city"` Adcode string `json:"adcode"` Province string `json:"province"` Reporttime string `json:"reporttime"` Casts []struct { Date string `json:"date"` Week string `json:"week"` Dayweather string `json:"dayweather"` Nightweather string `json:"nightweather"` Daytemp string `json:"daytemp"` Nighttemp string `json:"nighttemp"` Daywind string `json:"daywind"` Nightwind string `json:"nightwind"` Daypower string `json:"daypower"` Nightpower string `json:"nightpower"` DaytempFloat string `json:"daytemp_float"` NighttempFloat string `json:"nighttemp_float"` } `json:"casts"` } `json:"forecasts"` // 实况天气信息数据 Lives []struct { Province string `json:"province"` City string `json:"city"` Adcode string `json:"adcode"` Weather string `json:"weather"` Temperature string `json:"temperature"` Winddirection string `json:"winddirection"` Windpower string `json:"windpower"` Humidity string `json:"humidity"` Reporttime string `json:"reporttime"` TemperatureFloat string `json:"temperature_float"` HumidityFloat string `json:"humidity_float"` } `json:"lives"` } log.Printf("weather API response: %s", string(res.Content)) if err = json.Unmarshal(res.Content, &apiResp); err != nil { return nil, fmt.Errorf("parse weather API response failed: %w", err) } // 检查API返回状态 if apiResp.Status != "1" { return nil, fmt.Errorf("weather API returned error: %s, info: %s", apiResp.Status, apiResp.Info) } // 获取城市名称 cityName := "" if len(apiResp.Lives) > 0 { cityName = apiResp.Lives[0].City } else if len(apiResp.Forecasts) > 0 { cityName = apiResp.Forecasts[0].City } else { return nil, fmt.Errorf("no weather data found") } // 构建响应 response := &WeatherResponse{ City: cityName, Unit: request.Unit, Timestamp: time.Now().Format("2006-01-02 15:04:05"), } // 处理实时天气 if len(apiResp.Lives) > 0 { liveData := apiResp.Lives[0] // 转换温度 temp, _ := strconv.ParseFloat(liveData.Temperature, 64) if request.Unit == "fahrenheit" { temp = temp*9/5 + 32 } // 转换湿度和风速 humidity, _ := strconv.Atoi(liveData.Humidity) windSpeed, _ := strconv.ParseFloat(liveData.Windpower, 64) response.LiveWeather = &LiveWeather{ Temperature: temp, Condition: liveData.Weather, Humidity: humidity, WindSpeed: windSpeed, WindDirection: liveData.Winddirection, } } // 处理预报天气 if len(apiResp.Forecasts) > 0 && len(apiResp.Forecasts[0].Casts) > 0 { response.Forecasts = make([]ForecastWeather, 0, len(apiResp.Forecasts[0].Casts)) for _, cast := range apiResp.Forecasts[0].Casts { // 转换温度 dayTemp, _ := strconv.ParseFloat(cast.Daytemp, 64) nightTemp, _ := strconv.ParseFloat(cast.Nighttemp, 64) if request.Unit == "fahrenheit" { dayTemp = dayTemp*9/5 + 32 nightTemp = nightTemp*9/5 + 32 } forecast := ForecastWeather{ Date: cast.Date, Week: cast.Week, DayWeather: cast.Dayweather, NightWeather: cast.Nightweather, DayTemp: dayTemp, NightTemp: nightTemp, DayWind: cast.Daywind, NightWind: cast.Nightwind, DayWindPower: cast.Daypower, NightWindPower: cast.Nightpower, } response.Forecasts = append(response.Forecasts, forecast) } } return response, nil }