feat:天气工具,调整tools
This commit is contained in:
parent
4b1c297ed3
commit
c73327e805
|
|
@ -71,6 +71,10 @@ tools:
|
|||
zltxOrderAfterSaleResellerBatch:
|
||||
enabled: true
|
||||
base_url: "https://gateway.dev.cdlsxd.cn/zltx_api/admin/afterSales/reseller_pre_ai"
|
||||
weather:
|
||||
enabled: true
|
||||
base_url: "https://restapi.amap.com/v3/weather/weatherInfo"
|
||||
api_key: "12afbde5ab78cb7e575ff76bd0bdef2b"
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -131,7 +131,8 @@ func (d *Do) loadSystemInfo(ctx context.Context, client *gateway.Client, require
|
|||
// 获取任务列表的辅助函数
|
||||
func (d *Do) loadTaskList(ctx context.Context, client *gateway.Client, requireData *entitys.RequireData) error {
|
||||
if taskInfo := client.GetTasks(); len(taskInfo) == 0 {
|
||||
tasks, err := d.GetTasks(requireData.Sys.SysID)
|
||||
// 从数据库获取任务列表, 0 表示获取公共的任务
|
||||
tasks, err := d.GetTasks(requireData.Sys.SysID, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -140,6 +141,7 @@ func (d *Do) loadTaskList(ctx context.Context, client *gateway.Client, requireDa
|
|||
} else {
|
||||
requireData.Tasks = taskInfo
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -242,12 +244,12 @@ func (d *Do) getSessionChatHis(requireData *entitys.RequireData) (his []model.Ai
|
|||
return
|
||||
}
|
||||
|
||||
func (d *Do) GetTasks(sysId int32) (tasks []model.AiTask, err error) {
|
||||
func (d *Do) GetTasks(sysId ...int32) (tasks []model.AiTask, err error) {
|
||||
|
||||
cond := builder.NewCond()
|
||||
cond = cond.And(builder.Eq{"sys_id": sysId})
|
||||
//cond = cond.And(builder.Eq{"sys_id": sysId})
|
||||
cond = cond.And(builder.IsNull{"delete_at"})
|
||||
cond = cond.And(builder.Eq{"status": 1})
|
||||
cond = cond.And(builder.Eq{"status": 1}.And(builder.In("sys_id", sysId)))
|
||||
_, err = d.taskImpl.GetListToStruct(&cond, nil, &tasks, "")
|
||||
|
||||
return
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import (
|
|||
"ai_scheduler/internal/pkg/l_request"
|
||||
"ai_scheduler/internal/pkg/mapstructure"
|
||||
"ai_scheduler/internal/tools"
|
||||
"ai_scheduler/internal/tools/public"
|
||||
"ai_scheduler/internal/tools_bot"
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
|
@ -182,7 +183,7 @@ func (r *Handle) handleKnowle(ctx context.Context, requireData *entitys.RequireD
|
|||
return fmt.Errorf("tool not found: %s", configData.Tool)
|
||||
}
|
||||
|
||||
if knowledgeTool, ok := tool.(*tools.KnowledgeBaseTool); !ok {
|
||||
if knowledgeTool, ok := tool.(*public.KnowledgeBaseTool); !ok {
|
||||
return fmt.Errorf("未找到知识库Tool: %s", configData.Tool)
|
||||
} else {
|
||||
host = knowledgeTool.GetConfig().BaseURL
|
||||
|
|
@ -193,7 +194,7 @@ func (r *Handle) handleKnowle(ctx context.Context, requireData *entitys.RequireD
|
|||
// 知识库的session为空,请求知识库获取, 并绑定
|
||||
if requireData.SessionInfo.KnowlegeSessionID == "" {
|
||||
// 请求知识库
|
||||
if sessionIdKnowledge, err = tools.GetKnowledgeBaseSession(host, requireData.Sys.KnowlegeBaseID, requireData.Sys.KnowlegeTenantKey); err != nil {
|
||||
if sessionIdKnowledge, err = public.GetKnowledgeBaseSession(host, requireData.Sys.KnowlegeBaseID, requireData.Sys.KnowlegeTenantKey); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,121 +0,0 @@
|
|||
package tools
|
||||
|
||||
import (
|
||||
"ai_scheduler/internal/entitys"
|
||||
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
// CalculatorTool 计算器工具
|
||||
type CalculatorTool struct{}
|
||||
|
||||
// NewCalculatorTool 创建计算器工具
|
||||
func NewCalculatorTool() *CalculatorTool {
|
||||
return &CalculatorTool{}
|
||||
}
|
||||
|
||||
// Name 返回工具名称
|
||||
func (c *CalculatorTool) Name() string {
|
||||
return "calculate"
|
||||
}
|
||||
|
||||
// Description 返回工具描述
|
||||
func (c *CalculatorTool) Description() string {
|
||||
return "执行基本的数学运算,支持加减乘除和幂运算"
|
||||
}
|
||||
|
||||
// Definition 返回工具定义
|
||||
func (c *CalculatorTool) Definition() entitys.ToolDefinition {
|
||||
return entitys.ToolDefinition{
|
||||
Type: "function",
|
||||
Function: entitys.FunctionDef{
|
||||
Name: c.Name(),
|
||||
Description: c.Description(),
|
||||
Parameters: map[string]interface{}{
|
||||
"type": "object",
|
||||
"properties": map[string]interface{}{
|
||||
"operation": map[string]interface{}{
|
||||
"type": "string",
|
||||
"description": "运算类型",
|
||||
"enum": []string{"add", "subtract", "multiply", "divide", "power"},
|
||||
},
|
||||
"a": map[string]interface{}{
|
||||
"type": "number",
|
||||
"description": "第一个数字",
|
||||
},
|
||||
"b": map[string]interface{}{
|
||||
"type": "number",
|
||||
"description": "第二个数字",
|
||||
},
|
||||
},
|
||||
"required": []string{"operation", "a", "b"},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// CalculateRequest 计算请求参数
|
||||
type CalculateRequest struct {
|
||||
Operation string `json:"operation"`
|
||||
A float64 `json:"a"`
|
||||
B float64 `json:"b"`
|
||||
}
|
||||
|
||||
// CalculateResponse 计算响应
|
||||
type CalculateResponse struct {
|
||||
Operation string `json:"operation"`
|
||||
A float64 `json:"a"`
|
||||
B float64 `json:"b"`
|
||||
Result float64 `json:"result"`
|
||||
Expression string `json:"expression"`
|
||||
}
|
||||
|
||||
// Execute 执行计算
|
||||
func (c *CalculatorTool) Execute(ctx context.Context, args json.RawMessage) (interface{}, error) {
|
||||
var req CalculateRequest
|
||||
if err := json.Unmarshal(args, &req); err != nil {
|
||||
return nil, fmt.Errorf("invalid calculate request: %w", err)
|
||||
}
|
||||
|
||||
var result float64
|
||||
var expression string
|
||||
|
||||
switch req.Operation {
|
||||
case "add":
|
||||
result = req.A + req.B
|
||||
expression = fmt.Sprintf("%.2f + %.2f = %.2f", req.A, req.B, result)
|
||||
case "subtract":
|
||||
result = req.A - req.B
|
||||
expression = fmt.Sprintf("%.2f - %.2f = %.2f", req.A, req.B, result)
|
||||
case "multiply":
|
||||
result = req.A * req.B
|
||||
expression = fmt.Sprintf("%.2f × %.2f = %.2f", req.A, req.B, result)
|
||||
case "divide":
|
||||
if req.B == 0 {
|
||||
return nil, fmt.Errorf("division by zero is not allowed")
|
||||
}
|
||||
result = req.A / req.B
|
||||
expression = fmt.Sprintf("%.2f ÷ %.2f = %.2f", req.A, req.B, result)
|
||||
case "power":
|
||||
result = math.Pow(req.A, req.B)
|
||||
expression = fmt.Sprintf("%.2f ^ %.2f = %.2f", req.A, req.B, result)
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported operation: %s", req.Operation)
|
||||
}
|
||||
|
||||
// 检查结果是否有效
|
||||
if math.IsNaN(result) || math.IsInf(result, 0) {
|
||||
return nil, fmt.Errorf("calculation resulted in invalid number")
|
||||
}
|
||||
|
||||
return &CalculateResponse{
|
||||
Operation: req.Operation,
|
||||
A: req.A,
|
||||
B: req.B,
|
||||
Result: result,
|
||||
Expression: expression,
|
||||
}, nil
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"ai_scheduler/internal/data/constants"
|
||||
"ai_scheduler/internal/entitys"
|
||||
"ai_scheduler/internal/pkg/utils_ollama"
|
||||
"ai_scheduler/internal/tools/public"
|
||||
zltxtool "ai_scheduler/internal/tools/zltx"
|
||||
"context"
|
||||
|
||||
|
|
@ -44,30 +45,30 @@ func NewManager(config *config.Config, llm *utils_ollama.Client) *Manager {
|
|||
|
||||
// 注册直连天下订单详情工具
|
||||
if config.Tools.ZltxOrderDetail.Enabled {
|
||||
zltxOrderDetailTool := NewZltxOrderDetailTool(config.Tools.ZltxOrderDetail, m.llm)
|
||||
zltxOrderDetailTool := zltxtool.NewZltxOrderDetailTool(config.Tools.ZltxOrderDetail, m.llm)
|
||||
m.tools[zltxOrderDetailTool.Name()] = zltxOrderDetailTool
|
||||
}
|
||||
|
||||
//注册直连天下订单日志工具
|
||||
if config.Tools.ZltxOrderDirectLog.Enabled {
|
||||
zltxOrderLogTool := NewZltxOrderLogTool(config.Tools.ZltxOrderDirectLog)
|
||||
zltxOrderLogTool := zltxtool.NewZltxOrderLogTool(config.Tools.ZltxOrderDirectLog)
|
||||
m.tools[zltxOrderLogTool.Name()] = zltxOrderLogTool
|
||||
}
|
||||
|
||||
//注册直连天下商品工具
|
||||
if config.Tools.ZltxProduct.Enabled {
|
||||
zltxProductTool := NewZltxProductTool(config.Tools.ZltxProduct)
|
||||
zltxProductTool := zltxtool.NewZltxProductTool(config.Tools.ZltxProduct)
|
||||
m.tools[zltxProductTool.Name()] = zltxProductTool
|
||||
}
|
||||
//注册直连天下订单统计工具
|
||||
if config.Tools.ZltxOrderStatistics.Enabled {
|
||||
zltxOrderStatisticsTool := NewZltxOrderStatisticsTool(config.Tools.ZltxOrderStatistics)
|
||||
zltxOrderStatisticsTool := zltxtool.NewZltxOrderStatisticsTool(config.Tools.ZltxOrderStatistics)
|
||||
m.tools[zltxOrderStatisticsTool.Name()] = zltxOrderStatisticsTool
|
||||
}
|
||||
|
||||
// 注册知识库工具
|
||||
if config.Tools.Knowledge.Enabled {
|
||||
knowledgeTool := NewKnowledgeBaseTool(config.Tools.Knowledge)
|
||||
knowledgeTool := public.NewKnowledgeBaseTool(config.Tools.Knowledge)
|
||||
m.tools[knowledgeTool.Name()] = knowledgeTool
|
||||
}
|
||||
|
||||
|
|
@ -86,9 +87,14 @@ func NewManager(config *config.Config, llm *utils_ollama.Client) *Manager {
|
|||
zltxOrderAfterSaleResellerBatchTool := zltxtool.NewOrderAfterSaleResellerBatchTool(config.Tools.ZltxOrderAfterSaleResellerBatch)
|
||||
m.tools[zltxOrderAfterSaleResellerBatchTool.Name()] = zltxOrderAfterSaleResellerBatchTool
|
||||
}
|
||||
// 注册天气工具
|
||||
if config.Tools.Weather.Enabled {
|
||||
weatherTool := public.NewWeatherTool(config.Tools.Weather)
|
||||
m.tools[weatherTool.Name()] = weatherTool
|
||||
}
|
||||
|
||||
// 普通对话
|
||||
chat := NewNormalChatTool(m.llm, config)
|
||||
chat := public.NewNormalChatTool(m.llm, config)
|
||||
m.tools[chat.Name()] = chat
|
||||
|
||||
return m
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package tools
|
||||
package public
|
||||
|
||||
import (
|
||||
"ai_scheduler/internal/config"
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package tools
|
||||
package public
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package tools
|
||||
package public
|
||||
|
||||
import (
|
||||
"ai_scheduler/internal/config"
|
||||
|
|
@ -0,0 +1,345 @@
|
|||
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
|
||||
|
||||
}
|
||||
|
|
@ -1,139 +0,0 @@
|
|||
package tools
|
||||
|
||||
import (
|
||||
"ai_scheduler/internal/entitys"
|
||||
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
// WeatherTool 天气查询工具
|
||||
type WeatherTool struct {
|
||||
mockData bool
|
||||
}
|
||||
|
||||
// NewWeatherTool 创建天气工具
|
||||
func NewWeatherTool() *WeatherTool {
|
||||
return &WeatherTool{}
|
||||
}
|
||||
|
||||
// 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",
|
||||
},
|
||||
},
|
||||
"required": []string{"city"},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// WeatherRequest 天气请求参数
|
||||
type WeatherRequest struct {
|
||||
City string `json:"city"`
|
||||
Unit string `json:"unit,omitempty"`
|
||||
}
|
||||
|
||||
// WeatherResponse 天气响应
|
||||
type WeatherResponse struct {
|
||||
City string `json:"city"`
|
||||
Temperature float64 `json:"temperature"`
|
||||
Unit string `json:"unit"`
|
||||
Condition string `json:"condition"`
|
||||
Humidity int `json:"humidity"`
|
||||
WindSpeed float64 `json:"wind_speed"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
}
|
||||
|
||||
// Execute 执行天气查询
|
||||
func (w *WeatherTool) Execute(ctx context.Context, args json.RawMessage) (interface{}, error) {
|
||||
var req WeatherRequest
|
||||
if err := json.Unmarshal(args, &req); err != nil {
|
||||
return nil, fmt.Errorf("invalid weather request: %w", err)
|
||||
}
|
||||
|
||||
if req.City == "" {
|
||||
return nil, fmt.Errorf("city is required")
|
||||
}
|
||||
|
||||
if req.Unit == "" {
|
||||
req.Unit = "celsius"
|
||||
}
|
||||
|
||||
if w.mockData {
|
||||
return w.getMockWeather(req.City, req.Unit), nil
|
||||
}
|
||||
|
||||
// 这里可以集成真实的天气API
|
||||
return w.getMockWeather(req.City, req.Unit), 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"),
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package tools
|
||||
package zltx
|
||||
|
||||
import (
|
||||
"ai_scheduler/internal/config"
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package tools
|
||||
package zltx
|
||||
|
||||
import (
|
||||
"ai_scheduler/internal/config"
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package tools
|
||||
package zltx
|
||||
|
||||
import (
|
||||
"ai_scheduler/internal/config"
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package tools
|
||||
package zltx
|
||||
|
||||
import (
|
||||
"ai_scheduler/internal/config"
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package tools
|
||||
package zltx
|
||||
|
||||
import (
|
||||
"ai_scheduler/internal/config"
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package tools
|
||||
package zltx
|
||||
|
||||
import (
|
||||
"ai_scheduler/internal/config"
|
||||
Loading…
Reference in New Issue