feat:天气工具,调整tools
This commit is contained in:
parent
4b1c297ed3
commit
c73327e805
|
|
@ -71,6 +71,10 @@ tools:
|
||||||
zltxOrderAfterSaleResellerBatch:
|
zltxOrderAfterSaleResellerBatch:
|
||||||
enabled: true
|
enabled: true
|
||||||
base_url: "https://gateway.dev.cdlsxd.cn/zltx_api/admin/afterSales/reseller_pre_ai"
|
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 {
|
func (d *Do) loadTaskList(ctx context.Context, client *gateway.Client, requireData *entitys.RequireData) error {
|
||||||
if taskInfo := client.GetTasks(); len(taskInfo) == 0 {
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -140,6 +141,7 @@ func (d *Do) loadTaskList(ctx context.Context, client *gateway.Client, requireDa
|
||||||
} else {
|
} else {
|
||||||
requireData.Tasks = taskInfo
|
requireData.Tasks = taskInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -242,12 +244,12 @@ func (d *Do) getSessionChatHis(requireData *entitys.RequireData) (his []model.Ai
|
||||||
return
|
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 := 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.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, "")
|
_, err = d.taskImpl.GetListToStruct(&cond, nil, &tasks, "")
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"ai_scheduler/internal/pkg/l_request"
|
"ai_scheduler/internal/pkg/l_request"
|
||||||
"ai_scheduler/internal/pkg/mapstructure"
|
"ai_scheduler/internal/pkg/mapstructure"
|
||||||
"ai_scheduler/internal/tools"
|
"ai_scheduler/internal/tools"
|
||||||
|
"ai_scheduler/internal/tools/public"
|
||||||
"ai_scheduler/internal/tools_bot"
|
"ai_scheduler/internal/tools_bot"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"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)
|
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)
|
return fmt.Errorf("未找到知识库Tool: %s", configData.Tool)
|
||||||
} else {
|
} else {
|
||||||
host = knowledgeTool.GetConfig().BaseURL
|
host = knowledgeTool.GetConfig().BaseURL
|
||||||
|
|
@ -193,7 +194,7 @@ func (r *Handle) handleKnowle(ctx context.Context, requireData *entitys.RequireD
|
||||||
// 知识库的session为空,请求知识库获取, 并绑定
|
// 知识库的session为空,请求知识库获取, 并绑定
|
||||||
if requireData.SessionInfo.KnowlegeSessionID == "" {
|
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
|
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/data/constants"
|
||||||
"ai_scheduler/internal/entitys"
|
"ai_scheduler/internal/entitys"
|
||||||
"ai_scheduler/internal/pkg/utils_ollama"
|
"ai_scheduler/internal/pkg/utils_ollama"
|
||||||
|
"ai_scheduler/internal/tools/public"
|
||||||
zltxtool "ai_scheduler/internal/tools/zltx"
|
zltxtool "ai_scheduler/internal/tools/zltx"
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
|
@ -44,30 +45,30 @@ func NewManager(config *config.Config, llm *utils_ollama.Client) *Manager {
|
||||||
|
|
||||||
// 注册直连天下订单详情工具
|
// 注册直连天下订单详情工具
|
||||||
if config.Tools.ZltxOrderDetail.Enabled {
|
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
|
m.tools[zltxOrderDetailTool.Name()] = zltxOrderDetailTool
|
||||||
}
|
}
|
||||||
|
|
||||||
//注册直连天下订单日志工具
|
//注册直连天下订单日志工具
|
||||||
if config.Tools.ZltxOrderDirectLog.Enabled {
|
if config.Tools.ZltxOrderDirectLog.Enabled {
|
||||||
zltxOrderLogTool := NewZltxOrderLogTool(config.Tools.ZltxOrderDirectLog)
|
zltxOrderLogTool := zltxtool.NewZltxOrderLogTool(config.Tools.ZltxOrderDirectLog)
|
||||||
m.tools[zltxOrderLogTool.Name()] = zltxOrderLogTool
|
m.tools[zltxOrderLogTool.Name()] = zltxOrderLogTool
|
||||||
}
|
}
|
||||||
|
|
||||||
//注册直连天下商品工具
|
//注册直连天下商品工具
|
||||||
if config.Tools.ZltxProduct.Enabled {
|
if config.Tools.ZltxProduct.Enabled {
|
||||||
zltxProductTool := NewZltxProductTool(config.Tools.ZltxProduct)
|
zltxProductTool := zltxtool.NewZltxProductTool(config.Tools.ZltxProduct)
|
||||||
m.tools[zltxProductTool.Name()] = zltxProductTool
|
m.tools[zltxProductTool.Name()] = zltxProductTool
|
||||||
}
|
}
|
||||||
//注册直连天下订单统计工具
|
//注册直连天下订单统计工具
|
||||||
if config.Tools.ZltxOrderStatistics.Enabled {
|
if config.Tools.ZltxOrderStatistics.Enabled {
|
||||||
zltxOrderStatisticsTool := NewZltxOrderStatisticsTool(config.Tools.ZltxOrderStatistics)
|
zltxOrderStatisticsTool := zltxtool.NewZltxOrderStatisticsTool(config.Tools.ZltxOrderStatistics)
|
||||||
m.tools[zltxOrderStatisticsTool.Name()] = zltxOrderStatisticsTool
|
m.tools[zltxOrderStatisticsTool.Name()] = zltxOrderStatisticsTool
|
||||||
}
|
}
|
||||||
|
|
||||||
// 注册知识库工具
|
// 注册知识库工具
|
||||||
if config.Tools.Knowledge.Enabled {
|
if config.Tools.Knowledge.Enabled {
|
||||||
knowledgeTool := NewKnowledgeBaseTool(config.Tools.Knowledge)
|
knowledgeTool := public.NewKnowledgeBaseTool(config.Tools.Knowledge)
|
||||||
m.tools[knowledgeTool.Name()] = knowledgeTool
|
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)
|
zltxOrderAfterSaleResellerBatchTool := zltxtool.NewOrderAfterSaleResellerBatchTool(config.Tools.ZltxOrderAfterSaleResellerBatch)
|
||||||
m.tools[zltxOrderAfterSaleResellerBatchTool.Name()] = zltxOrderAfterSaleResellerBatchTool
|
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
|
m.tools[chat.Name()] = chat
|
||||||
|
|
||||||
return m
|
return m
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package tools
|
package public
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"ai_scheduler/internal/config"
|
"ai_scheduler/internal/config"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package tools
|
package public
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package tools
|
package public
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"ai_scheduler/internal/config"
|
"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 (
|
import (
|
||||||
"ai_scheduler/internal/config"
|
"ai_scheduler/internal/config"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package tools
|
package zltx
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"ai_scheduler/internal/config"
|
"ai_scheduler/internal/config"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package tools
|
package zltx
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"ai_scheduler/internal/config"
|
"ai_scheduler/internal/config"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package tools
|
package zltx
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"ai_scheduler/internal/config"
|
"ai_scheduler/internal/config"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package tools
|
package zltx
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"ai_scheduler/internal/config"
|
"ai_scheduler/internal/config"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package tools
|
package zltx
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"ai_scheduler/internal/config"
|
"ai_scheduler/internal/config"
|
||||||
Loading…
Reference in New Issue