diff --git a/app/main/api/internal/service/1.md b/app/main/api/internal/service/1.md
index f64b0ac..2122c64 100644
--- a/app/main/api/internal/service/1.md
+++ b/app/main/api/internal/service/1.md
@@ -1,10 +1,10 @@
首页
-企业商务
-节假日
-节假日接口
-139 146929
-节假日正常服务支持MCP
-判断指定日期是否为法定节假日、调休日或工作日,并返回薪资倍数。
+知识问答
+百科题库
+百科题库接口
+185 23883
+百科题库正常服务支持MCP
+随机返回一道生活百科问答题,覆盖科学、健康、安全、常识等实用知识。
会员免费・升级会员畅享160+免费接口,立即升级>>
收藏
普通会员
@@ -29,32 +29,18 @@ MCP服务
帮助
生成小程序
-查询节假日信息,接口返回节日名称类型、农历信息、上班调休、工资倍数、假期范围、拼假建议、及工作日相关信息等。通过请求参数mode还可以指定是否返回当天有关的国内外节日信息。使用前建议阅读参考文章:节假日接口增加多种查询方式
-接口支持按年、按月、按日期范围和多个日期批量查询。如按年查询(type=1&date=2020)、按月查询(type=2&date=2020-10)、按日期范围查询(type=3&date=2020-11-1~2020-11-10)、按多个日期批量查询(date=2020-10-1,2020-11-12)
-
-请注意,按年查询只返回中国官方节假日信息;按月查询如只传年月,则为从该月第一天到最后一天;按范围查询,起点和终点用波浪号~分隔;按多个日期批量查询用英文半角逗号分隔。无论哪种查询方式,单次查询所包含的总日期数不能超过31天。
-
-daycode表示日期类型,0表示工作日、1节假日、2双休日、3调休日(需上班)。判断是否需要上班建议用isnotwork字段,其中值为0表示上班,为1表示休息。wage表示薪资倍数,周末为两倍,法定节假日当天为三倍其他两倍(按年查询时返回三倍薪资的具体日期)。
-
-提示:info字段和daycode并非对应关系,建议仅用于日期类型标记;节日指某个具体日期(如2021年1月1号),节假日指整个假期(如2021年1月1号至3号);节日范围宽泛(如会包含植树节、圣诞节),节假日指来自官方发布的有假节日,每年底政府公布后同步更新。
-
+生活百科题库大全接口,部分结果返回详细解释。
接入点列表:
-节假日查询
+百科题库查询
相关资源:
-节假日功能演示
-节假日接口更新了,增加批量/范围按年按月查询
-如何利用节假日API让日程规划更轻松
-为什么节假日查询接口,按年查询返回250错误?
-节假日接口数据有误,怎么回事?
-节假日接口没有更新吗?
-我想知道哪天是国家规定的3倍工资呢?
-请问我如何知道节假日接口已经更新了下一年的数据呢?
+百科题库功能演示
+百科题库接口不能查询指定题目的答案么?
▼ 接口信息
-判断日期是否为官方节假日支持按年、按月和范围批量查询
+默认随机返回一个百科问答带答案
-接口地址:https://apis.tianapi.com/jiejiari/index?key={apiKey}
+接口地址:https://apis.tianapi.com/baiketiku/index?key={apiKey}
支持协议:http/https
请求方法:get/post
返回格式:utf-8 json
@@ -67,9 +53,6 @@ daycode表示日期类型,0表示工作日、1节假日、2双休日、3调休
名称 类型 必须 示例值/默认值 说明
key string 是 您自己的ApiKey(注册账号后获得) API密钥
-date string 是 2021-01-01 查询日期或日期范围
-type int 是 0 查询类型,0批量、1按年、2按月、3范围
-mode int 否 0 查询模式,为1同时返回中外特殊节日信息
▼ 返回示例
接口数据示例仅作为预览参考,请以实际测试结果为准
@@ -84,37 +67,13 @@ mode int 否 0 查询模式,为1同时返回中外特殊节日信息
"msg": "success",
"code": 200,
"result": {
- "list": [
- {
- "end": 2,
- "now": 0,
- "tip": "1月1日放假,共3天。",
- "date": "2021-01-01",
- "info": "节假日",
- "name": "元旦节",
- "rest": "2020年12月28日至2020年12月31日请假四天,与周末连休可拼七天长假。",
- "wage": 3,
- "start": 0,
- "enname": "NewYear",
- "remark": [
- "2021-12-26",
- "2021-01-08"
- ],
- "daycode": 1,
- "holiday": "1月1号",
- "weekday": 5,
- "lunarday": "十八",
- "vacation": [
- "2021-01-01",
- "2021-01-02",
- "2021-01-03"
- ],
- "cnweekday": "星期五",
- "isnotwork": 1,
- "lunaryear": "庚子",
- "lunarmonth": "冬月"
- }
- ]
+ "title": "新冠肺炎的最长潜伏期一般是多久?",
+ "answer": "C",
+ "answerA": "1-2天",
+ "answerB": "3-7天",
+ "answerC": "14天",
+ "answerD": "28天",
+ "analytic": "新型冠状病毒感染性肺炎属于呼吸道传播性疾病,该病一般最常见的传播途径有飞沫传播,气溶胶传播,粪口传播及眼部粘膜传播,潜伏期一般为3-5天,最长不超过14天左右,也有因人而异,超过以上天数。或许以无症状感染者,不发病。该病确诊有赖于核酸病毒检测,同时做好多饮水,勤洗手,出门戴口罩,避免人群聚集,导致交叉感染。"
}
}
@@ -142,37 +101,10 @@ code int 200 状态码
msg string success 错误信息
result object {} 返回结果集
应用参数
-end int 6 假期终点计数
-now int 0 假期当前计数
-tip string 10月1日至7日放假调休,共7天...... 放假提示
-date string 2019-10-01 当前阳历日期
-info string 节假日 文字提示,工作日、节假日、节日、双休日、调休日
-name string 国庆节 节假日名称(中文)
-rest string 10月8日至10月10日请假2天,与周末连休可拼11天长假。 拼假建议
-wage int 3 薪资法定倍数/按年查询时为具体日期
-start int 0 假期起点计数
-enname string National Day 节日名称(英文)
-remark array ["2021-12-26","2021-01-08"] 调休日数组
-update boolean true/false 是否更新法定节假日(按年查询专有字段)
-daycode int 1 日期类型,为0表示工作日、为1节假日、为2双休日、3为调休日(上班)
-holiday string 10月1日 节日日期
-weekday int 2 星期(数字)
-lunarday string 初三 农历日
-vacation array ["2021-01-01","2021-01-02","2021-01-03"] 节假日数组
-cnweekday string 星期二 星期(中文)
-isnotwork int 1 是否需要上班,0为工作日,1为休息日
-lunaryear string 己亥 农历年
-lunarmonth string 九月 农历月
-▼ 接口价格
-本接口为会员免费类接口,可根据业务需求选择升级会员方案>>
-
-
-不同会员方案仅每日调用量等配额上限不同,数据本身无区别
-
-
-会员方案 免费接口数 每日调用量 QPS 价格
-普通会员 10个 100次 3 免费
-高级会员 不限 1万次 20 29元/月、348元/年169元/年惠
-黄金会员 不限 50万次 30 89元/月、1068元/年529元/年惠
-钻石会员 不限 不限次 60 3380元/年1699元/年惠
-▼ 返回状态码
\ No newline at end of file
+title string 新冠肺炎的最长潜伏期一般是多久? 问题
+answer string C 正确答案
+answerA string 1-2天 答案A
+answerB string 3-7天 答案B
+answerC string 14天 答案C
+answerD string 28天 答案D
+analytic string 新型冠状病毒感染性肺炎属于呼吸道传播性疾病... 分析结果
\ No newline at end of file
diff --git a/app/main/api/internal/service/toolboxService.go b/app/main/api/internal/service/toolboxService.go
index 3e4dcff..130eac9 100644
--- a/app/main/api/internal/service/toolboxService.go
+++ b/app/main/api/internal/service/toolboxService.go
@@ -4,7 +4,6 @@ import (
"context"
"encoding/json"
"fmt"
- "math"
"net"
"net/http"
"regexp"
@@ -38,7 +37,7 @@ import (
// 2️⃣ 文字处理类 (20个)
// money-to-chinese, password-strength, days-between-dates, file-size-format,
// text-stats, pinyin, hanzipinyin, duoyinzi, chaizi, xhzd, jf-words,
-// lexicon, enwords, ensentence, fanyi, dailytel, charconvert, cnmoney,
+// lexicon, enwords, ensentence, fanyi, dailytel, charconvert,
// slogan, zimi
//
// 3️⃣ 文化知识类 (35个)
@@ -100,7 +99,7 @@ func (s *ToolboxService) registerAllProcessors() {
s.processors["beijing-time"] = processBeijingTime
s.processors["bank-card"] = processBankCard
s.processors["plate-parse"] = processPlateParse
- s.processors["money-to-chinese"] = processMoneyToChinese
+ s.processors["money-to-chinese"] = s.processMoneyToChinese
s.processors["password-strength"] = processPasswordStrength
s.processors["days-between-dates"] = processDaysBetweenDates
s.processors["file-size-format"] = processFileSizeFormat
@@ -196,10 +195,10 @@ func (s *ToolboxService) registerAllProcessors() {
// ─── 第二批新增工具 ───
s.processors["timezone"] = s.processTimeZone
s.processors["domain"] = s.processDomainParse // 域名解析
- s.processors["duoyinzi"] = s.processDuoYinZi
+ s.processors["duoyinzi"] = s.processDuoYinZi //多音字
s.processors["dailytel"] = s.processDailyTel
s.processors["obdcode"] = s.processObdCode
- s.processors["chaizi"] = s.processChaiZi
+ s.processors["chaizi"] = s.processChaiZi //拆字
s.processors["huayu"] = s.processHuaYu
s.processors["moodpoetry"] = s.processMoodPoetry
s.processors["pcterm"] = s.processPcTerm
@@ -680,74 +679,41 @@ func processPlateParse(ctx context.Context, params map[string]interface{}) (map[
}
// processMoneyToChinese 金额转换为中文
-func processMoneyToChinese(ctx context.Context, params map[string]interface{}) (map[string]interface{}, error) {
- var amount float64
- switch v := params["money"].(type) {
- case float64:
- amount = v
- case string:
- amount, _ = strconv.ParseFloat(v, 64)
- default:
- return nil, xerr.NewErrMsg("金额不合法")
+func (s *ToolboxService) processMoneyToChinese(ctx context.Context, params map[string]interface{}) (map[string]interface{}, error) {
+ reqParams := map[string]interface{}{}
+
+ // 金额(必填)
+ money, ok := params["money"].(string)
+ if !ok || money == "" {
+ return nil, xerr.NewErrMsg("金额不能为空")
}
- if amount < 0 || amount > 999999999999 {
- return nil, xerr.NewErrMsg("金额不合法")
+ reqParams["money"] = money
+
+ // 可选:单位类型,默认rmb(人民币元)
+ // type: usd美元单位元、usd_1美元单位分、rmb人民币单位元[默认]、rmb_1人民币单位分
+ if typ, ok := params["type"].(string); ok && typ != "" {
+ reqParams["type"] = typ
}
- nums := []string{"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"}
- units := []string{"", "拾", "佰", "仟"}
- bigUnits := []string{"", "万", "亿"}
-
- integer := int64(math.Floor(amount))
- decimal := int64(math.Round((amount - float64(integer)) * 100))
-
- var result strings.Builder
- if integer > 0 {
- unitPos, zeroFlag := 0, false
- for integer > 0 {
- cur := integer % 10
- if cur == 0 {
- if !zeroFlag {
- result.WriteString(nums[0])
- zeroFlag = true
- }
- } else {
- result.WriteString(nums[cur] + units[unitPos%4])
- zeroFlag = false
- }
- if unitPos%4 == 3 && !zeroFlag {
- result.WriteString(bigUnits[unitPos/4])
- zeroFlag = true
- }
- unitPos++
- integer /= 10
- }
- // 反转
- str := result.String()
- runes := []rune(str)
- for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
- runes[i], runes[j] = runes[j], runes[i]
- }
- result.Reset()
- result.WriteString(string(runes))
- result.WriteString("元")
+ // 调用天行API
+ resp, err := s.tianxingjuheClient.Get("cnmoney/index", reqParams)
+ if err != nil {
+ return nil, xerr.NewErrMsg(fmt.Sprintf("请求金额转大写接口失败: %v", err))
+ }
+ if resp.Code != 200 {
+ return nil, xerr.NewErrMsg(fmt.Sprintf("金额转大写接口异常: %s", resp.Msg))
}
- if decimal > 0 {
- jiao, fen := decimal/10, decimal%10
- if jiao > 0 {
- result.WriteString(nums[jiao] + "角")
- }
- if fen > 0 {
- result.WriteString(nums[fen] + "分")
- }
- } else {
- result.WriteString("整")
+ // 解析result
+ result, ok := resp.Result.(map[string]interface{})
+ if !ok {
+ return nil, xerr.NewErrMsg("解析金额转大写数据失败")
}
return map[string]interface{}{
- "amount": amount,
- "chinese": result.String(),
+ "cnresult": result["cnresult"], // 中文大写金额
+ "enresult": result["enresult"], // 英语大写金额
+ "fnresult": result["fnresult"], // 西式三位分节法数字
}, nil
}
@@ -1665,10 +1631,12 @@ func (s *ToolboxService) processAreaNews(ctx context.Context, params map[string]
}
reqParams["areaname"] = areaname
- // 可选参数:页码
- if page, ok := params["page"].(string); ok && page != "" {
- reqParams["page"] = page
+ // 可选参数:页码(默认1)
+ page := "1"
+ if pageStr, ok := params["page"].(string); ok && pageStr != "" {
+ page = pageStr
}
+ reqParams["page"] = page
// 可选参数:关键词
if word, ok := params["word"].(string); ok && word != "" {
@@ -1678,41 +1646,94 @@ func (s *ToolboxService) processAreaNews(ctx context.Context, params map[string]
// 调用天行SDK 地区新闻接口
resp, err := s.tianxingjuheClient.Get("areanews/index", reqParams)
if err != nil {
+ logx.WithContext(ctx).Errorf("[地区新闻] 请求失败: %v", err)
return nil, xerr.NewErrMsg(fmt.Sprintf("请求天行数据地区新闻API失败: %v", err))
}
if resp.Code != 200 {
+ logx.WithContext(ctx).Errorf("[地区新闻] API返回异常: code=%d, msg=%s", resp.Code, resp.Msg)
return nil, xerr.NewErrMsg(fmt.Sprintf("地区新闻接口返回异常: %s", resp.Msg))
}
+ logx.WithContext(ctx).Infof("[地区新闻] API响应: %+v", resp.Result)
+
resultMap, ok := resp.Result.(map[string]interface{})
if !ok {
+ logx.WithContext(ctx).Errorf("[地区新闻] 解析result失败,类型: %T", resp.Result)
return nil, xerr.NewErrMsg("解析地区新闻数据失败")
}
// 解析新闻列表
listArr, ok := resultMap["list"].([]interface{})
if !ok {
+ logx.WithContext(ctx).Errorf("[地区新闻] 解析list失败,result结构: %+v", resultMap)
return nil, xerr.NewErrMsg("解析地区新闻列表失败")
}
+ logx.WithContext(ctx).Infof("[地区新闻] 列表长度: %d", len(listArr))
+
+ // 字段白名单
+ allowed := map[string]bool{
+ "id": true,
+ "url": true,
+ "ctime": true,
+ "title": true,
+ "picUrl": true,
+ "source": true,
+ "description": true,
+ }
+
var newsList []map[string]interface{}
for _, item := range listArr {
if m, ok := item.(map[string]interface{}); ok {
- newsList = append(newsList, map[string]interface{}{
- "id": m["id"],
- "url": m["url"],
- "ctime": m["ctime"],
- "title": m["title"],
- "picUrl": m["picUrl"],
- "source": m["source"],
- "description": m["description"],
- })
+ clean := map[string]interface{}{}
+ for k, v := range m {
+ if allowed[k] {
+ // 清理HTML标签(title和description)
+ if k == "title" || k == "description" {
+ if str, ok := v.(string); ok {
+ clean[k] = cleanHTMLContent(str)
+ }
+ } else {
+ clean[k] = v
+ }
+ }
+ }
+ // 至少要有标题(允许清理后为空,但原始必须有值)
+ if m["title"] != nil {
+ newsList = append(newsList, clean)
+ }
}
}
+ logx.WithContext(ctx).Infof("[地区新闻] 清理后列表长度: %d", len(newsList))
+
+ // 如果清理后列表为空,但原始有数据,可能是HTML清理导致的问题
+ if len(newsList) == 0 && len(listArr) > 0 {
+ // logx.WithContext(ctx).Warnf("[地区新闻] 清理后列表为空,原始有%d条数据", len(listArr))
+ // 返回部分数据,不清理HTML
+ for _, item := range listArr {
+ if m, ok := item.(map[string]interface{}); ok {
+ clean := map[string]interface{}{}
+ for k, v := range m {
+ if allowed[k] {
+ clean[k] = v
+ }
+ }
+ if m["title"] != nil {
+ newsList = append(newsList, clean)
+ }
+ }
+ }
+ }
+
+ if len(newsList) == 0 {
+ return nil, xerr.NewErrMsg("未查询到该地区新闻")
+ }
+
return map[string]interface{}{
- "list": newsList,
+ "count": len(newsList),
+ "list": newsList,
}, nil
}
@@ -1836,14 +1857,23 @@ func (s *ToolboxService) processZhongyao(ctx context.Context, params map[string]
}
reqParams["word"] = word
- // 可选返回数量
- if num, ok := params["num"].(string); ok && num != "" {
- reqParams["num"] = num
+ // 可选返回数量(默认1)
+ num := 1
+ if numStr, ok := params["num"].(string); ok && numStr != "" {
+ if n, err := strconv.Atoi(numStr); err == nil && n > 0 {
+ num = n
+ }
}
- // 可选页码
- if page, ok := params["page"].(string); ok && page != "" {
- reqParams["page"] = page
+ reqParams["num"] = num
+
+ // 可选页码(默认1)
+ page := 1
+ if pageStr, ok := params["page"].(string); ok && pageStr != "" {
+ if p, err := strconv.Atoi(pageStr); err == nil && p > 0 {
+ page = p
+ }
}
+ reqParams["page"] = page
// 调用天行SDK 中药大全接口
resp, err := s.tianxingjuheClient.Get("zhongyao/index", reqParams)
@@ -1855,14 +1885,42 @@ func (s *ToolboxService) processZhongyao(ctx context.Context, params map[string]
return nil, xerr.NewErrMsg(fmt.Sprintf("中药大全接口返回异常: %s", resp.Msg))
}
+ logx.WithContext(ctx).Infof("[中药大全] API响应: %+v", resp.Result)
+
+ // 解析 result - 支持多种格式
resultMap, ok := resp.Result.(map[string]interface{})
if !ok {
- return nil, xerr.NewErrMsg("解析中药大全数据失败")
+ return nil, xerr.NewErrMsg("解析中药大全数据失败:返回格式不是对象")
+ }
+
+ // 检查是否是列表格式(有些天行API返回 { list: [...] })
+ if listData, hasList := resultMap["list"].([]interface{}); hasList && len(listData) > 0 {
+ // 取第一条记录
+ if firstItem, ok := listData[0].(map[string]interface{}); ok {
+ resultMap = firstItem
+ }
+ }
+
+ // 检查是否有数据
+ if resultMap["title"] == nil && resultMap["content"] == nil {
+ return nil, xerr.NewErrMsg("未查询到该中药信息")
+ }
+
+ // 清理HTML标签
+ title, _ := resultMap["title"].(string)
+ content, _ := resultMap["content"].(string)
+
+ // 如果是字符串类型,清理HTML标签
+ if title != "" {
+ title = cleanHTMLContent(title)
+ }
+ if content != "" {
+ content = cleanHTMLContent(content)
}
return map[string]interface{}{
- "title": resultMap["title"],
- "content": resultMap["content"],
+ "title": title,
+ "content": content,
}, nil
}
@@ -1877,15 +1935,23 @@ func (s *ToolboxService) processYaopin(ctx context.Context, params map[string]in
}
reqParams["word"] = word
- // 可选参数:数量
- if num, ok := params["num"].(string); ok && num != "" {
- reqParams["num"] = num
+ // 可选参数:数量(默认10)
+ num := 10
+ if numStr, ok := params["num"].(string); ok && numStr != "" {
+ if n, err := strconv.Atoi(numStr); err == nil && n > 0 {
+ num = n
+ }
}
+ reqParams["num"] = num
- // 可选参数:页码
- if page, ok := params["page"].(string); ok && page != "" {
- reqParams["page"] = page
+ // 可选参数:页码(默认1)
+ page := 1
+ if pageStr, ok := params["page"].(string); ok && pageStr != "" {
+ if p, err := strconv.Atoi(pageStr); err == nil && p > 0 {
+ page = p
+ }
}
+ reqParams["page"] = page
// 调用天行SDK 药品说明书接口
resp, err := s.tianxingjuheClient.Get("yaopin/index", reqParams)
@@ -1897,14 +1963,52 @@ func (s *ToolboxService) processYaopin(ctx context.Context, params map[string]in
return nil, xerr.NewErrMsg(fmt.Sprintf("药品说明书接口返回异常: %s", resp.Msg))
}
+ logx.WithContext(ctx).Infof("[药品说明书] API响应: %+v", resp.Result)
+
+ // 解析 result - 支持多种格式
+ var list []map[string]interface{}
+
resultMap, ok := resp.Result.(map[string]interface{})
if !ok {
- return nil, xerr.NewErrMsg("解析药品说明书数据失败")
+ return nil, xerr.NewErrMsg("解析药品说明书数据失败:返回格式不是对象")
+ }
+
+ // 情况1:返回格式为 { list: [...] }
+ if listData, hasList := resultMap["list"].([]interface{}); hasList {
+ for _, item := range listData {
+ if m, ok := item.(map[string]interface{}); ok {
+ // 字段白名单 + 清理HTML标签
+ clean := map[string]interface{}{}
+ if v, ok := m["title"].(string); ok {
+ clean["title"] = cleanHTMLContent(v)
+ }
+ if v, ok := m["content"].(string); ok {
+ clean["content"] = cleanHTMLContent(v)
+ }
+ if clean["title"] != nil {
+ list = append(list, clean)
+ }
+ }
+ }
+ } else if resultMap["title"] != nil {
+ // 情况2:返回格式为 { title: "...", content: "..." }(单条记录)
+ title, _ := resultMap["title"].(string)
+ content, _ := resultMap["content"].(string)
+
+ clean := map[string]interface{}{
+ "title": cleanHTMLContent(title),
+ "content": cleanHTMLContent(content),
+ }
+ list = append(list, clean)
+ }
+
+ if len(list) == 0 {
+ return nil, xerr.NewErrMsg("未查询到该药品说明书")
}
return map[string]interface{}{
- "title": resultMap["title"],
- "content": resultMap["content"],
+ "count": len(list),
+ "list": list,
}, nil
}
@@ -2120,7 +2224,7 @@ func (s *ToolboxService) processRiddle(ctx context.Context, params map[string]in
return map[string]interface{}{
"quest": resultMap["quest"],
- "answer": resultMap["answer"],
+ "result": resultMap["answer"],
}, nil
}
@@ -2159,8 +2263,20 @@ func (s *ToolboxService) processNutrient(
) (map[string]interface{}, error) {
// 1. 参数提取(必填)
- mode, ok := params["mode"].(float64)
- if !ok {
+ var mode float64
+ switch v := params["mode"].(type) {
+ case float64:
+ mode = v
+ case string:
+ if v == "" {
+ return nil, xerr.NewErrMsg("缺少必填参数 mode")
+ }
+ modeInt, err := strconv.Atoi(v)
+ if err != nil {
+ return nil, xerr.NewErrMsg("mode 参数必须是数字 0/1/2")
+ }
+ mode = float64(modeInt)
+ default:
return nil, xerr.NewErrMsg("缺少必填参数 mode")
}
@@ -2198,13 +2314,25 @@ func (s *ToolboxService) processNutrient(
return nil, xerr.NewErrMsg(fmt.Sprintf("营养成分接口异常: %s", resp.Msg))
}
- // 5. 解析 result(数组 or 单对象都兼容)
+ // 5. 解析 result(天行 API 返回格式为 { list: [...] })
var list []map[string]interface{}
+ // 尝试从 result 中提取 list 字段
switch v := resp.Result.(type) {
case map[string]interface{}:
- list = append(list, v)
+ // 天行 API 的标准格式:result.list 是数组
+ if dataList, ok := v["list"].([]interface{}); ok {
+ for _, item := range dataList {
+ if m, ok := item.(map[string]interface{}); ok {
+ list = append(list, m)
+ }
+ }
+ } else {
+ // 兼容单个对象的情况
+ list = append(list, v)
+ }
case []interface{}:
+ // 兼容直接返回数组的情况
for _, item := range v {
if m, ok := item.(map[string]interface{}); ok {
list = append(list, m)
@@ -2214,6 +2342,10 @@ func (s *ToolboxService) processNutrient(
return nil, xerr.NewErrMsg("解析营养成分数据失败")
}
+ if len(list) == 0 {
+ return nil, xerr.NewErrMsg("未查询到相关数据")
+ }
+
// 6. 返回标准化结果
return map[string]interface{}{
"count": len(list),
@@ -2580,9 +2712,10 @@ func (s *ToolboxService) processChengyuJielong(
return nil, xerr.NewErrMsg("参数 word 不能为空,例如:一马当先")
}
+ // 用户ID:如果没有提供,使用默认值(方便单人游戏)
userID, ok := params["userid"].(string)
if !ok || userID == "" {
- return nil, xerr.NewErrMsg("参数 userid 不能为空,建议使用 openid / uuid")
+ userID = "1212" // 默认用户标识,单人游戏模式
}
// 2. 请求参数
@@ -2656,60 +2789,36 @@ func (s *ToolboxService) processWeiboHot(
params map[string]interface{},
) (map[string]interface{}, error) {
- // 1. 请求参数(无需业务参数)
reqParams := map[string]interface{}{}
- // 2. 调用天行 API
resp, err := s.tianxingjuheClient.Get("weibohot/index", reqParams)
if err != nil {
return nil, xerr.NewErrMsg(fmt.Sprintf("请求微博热搜接口失败: %v", err))
}
-
if resp.Code != 200 {
return nil, xerr.NewErrMsg(fmt.Sprintf("微博热搜接口异常: %s", resp.Msg))
}
- // 3. 解析 result
result, ok := resp.Result.(map[string]interface{})
if !ok {
return nil, xerr.NewErrMsg("解析微博热搜数据失败")
}
- // 4. 解析 list
rawList, ok := result["list"].([]interface{})
if !ok {
return nil, xerr.NewErrMsg("热搜列表数据异常")
}
- // 5. 字段白名单
- allowed := map[string]bool{
- "hottag": true,
- "hotword": true,
- "hotwordnum": true,
- }
-
- hotList := make([]map[string]interface{}, 0, len(rawList))
-
+ var hotList []map[string]interface{}
for _, item := range rawList {
- raw, ok := item.(map[string]interface{})
- if !ok {
- continue
- }
-
- clean := map[string]interface{}{}
- for k, v := range raw {
- if allowed[k] {
- clean[k] = v
- }
- }
-
- // 至少要有热搜词
- if clean["hotword"] != nil {
- hotList = append(hotList, clean)
- }
+ info, _ := item.(map[string]interface{})
+ hotList = append(hotList, map[string]interface{}{
+ "keyword": info["hotword"], // 搜索词
+ "brief": info["hottag"], // 简介
+ "index": info["hotwordnum"], // 热度
+ })
}
- // 6. 返回标准化结果
return map[string]interface{}{
"count": len(hotList),
"list": hotList,
@@ -4280,8 +4389,20 @@ func (s *ToolboxService) processRKL(
// 字段白名单
clean := map[string]interface{}{}
if content, ok := raw["content"]; ok && content != nil {
- clean["content"] = content
- list = append(list, clean)
+ // 去除HTML标签
+ if contentStr, ok := content.(string); ok {
+ // 移除所有HTML标签
+ re := regexp.MustCompile(`<[^>]+>`)
+ cleanContent := re.ReplaceAllString(contentStr, "")
+ // 替换
、
等换行标签为换行符
+ cleanContent = regexp.MustCompile(`(?i)
`).ReplaceAllString(cleanContent, "\n")
+ // 移除多余的空行
+ cleanContent = regexp.MustCompile(`\n{3,}`).ReplaceAllString(cleanContent, "\n\n")
+ // 去除首尾空白
+ cleanContent = strings.TrimSpace(cleanContent)
+ clean["content"] = cleanContent
+ list = append(list, clean)
+ }
}
}
@@ -4615,16 +4736,28 @@ func (s *ToolboxService) processChengYu(
// 返回数量(可选)
if num, ok := params["num"].(float64); ok && num > 0 && num <= 50 {
reqParams["num"] = int(num)
+ } else if numStr, ok := params["num"].(string); ok && numStr != "" {
+ if numInt, err := strconv.Atoi(numStr); err == nil && numInt > 0 && numInt <= 50 {
+ reqParams["num"] = numInt
+ }
}
// 搜索模式(可选)
if mode, ok := params["mode"].(float64); ok && mode >= 0 && mode <= 2 {
reqParams["mode"] = int(mode)
+ } else if modeStr, ok := params["mode"].(string); ok && modeStr != "" {
+ if modeInt, err := strconv.Atoi(modeStr); err == nil && modeInt >= 0 && modeInt <= 2 {
+ reqParams["mode"] = modeInt
+ }
}
// 页码(可选)
if page, ok := params["page"].(float64); ok && page > 0 {
reqParams["page"] = int(page)
+ } else if pageStr, ok := params["page"].(string); ok && pageStr != "" {
+ if pageInt, err := strconv.Atoi(pageStr); err == nil && pageInt > 0 {
+ reqParams["page"] = pageInt
+ }
}
// 调用天行 API
@@ -4691,12 +4824,12 @@ func (s *ToolboxService) processNaoWan(
reqParams := map[string]interface{}{}
- // 返回数量(必填)
- num, ok := params["num"].(float64)
- if !ok || num <= 0 {
- num = 5 // 给一个安全默认值
+ // 返回数量(可选,默认5条)
+ if num, ok := params["num"].(float64); ok && num > 0 {
+ reqParams["num"] = int(num)
+ } else {
+ reqParams["num"] = 5 // 默认返回5条
}
- reqParams["num"] = int(num)
// 调用天行 API
resp, err := s.tianxingjuheClient.Get("naowan/index", reqParams)
@@ -4732,8 +4865,8 @@ func (s *ToolboxService) processNaoWan(
if quest, ok := raw["quest"]; ok {
clean["quest"] = quest
}
- if answer, ok := raw["result"]; ok {
- clean["answer"] = answer
+ if result, ok := raw["result"]; ok {
+ clean["result"] = result
}
list = append(list, clean)
@@ -4743,6 +4876,7 @@ func (s *ToolboxService) processNaoWan(
"count": len(list),
"list": list,
}, nil
+
}
// processDOB 生日性格查询
@@ -4753,19 +4887,49 @@ func (s *ToolboxService) processDOB(
reqParams := map[string]interface{}{}
- // 月份(必填)
- m, ok := params["m"].(float64)
- if !ok || m < 1 || m > 12 {
+ // 月份(必填)- 支持字符串和数字类型
+ var m int
+ switch v := params["m"].(type) {
+ case float64:
+ if v < 1 || v > 12 {
+ return nil, xerr.NewErrMsg("生日性格查询缺少必填参数:m(月份 1-12)")
+ }
+ m = int(v)
+ case string:
+ if v == "" {
+ return nil, xerr.NewErrMsg("生日性格查询缺少必填参数:m(月份 1-12)")
+ }
+ mInt, err := strconv.Atoi(v)
+ if err != nil || mInt < 1 || mInt > 12 {
+ return nil, xerr.NewErrMsg("生日性格查询参数 m 必须是 1-12 的数字")
+ }
+ m = mInt
+ default:
return nil, xerr.NewErrMsg("生日性格查询缺少必填参数:m(月份 1-12)")
}
- reqParams["m"] = int(m)
+ reqParams["m"] = m
- // 日期(必填)
- d, ok := params["d"].(float64)
- if !ok || d < 1 || d > 31 {
+ // 日期(必填)- 支持字符串和数字类型
+ var d int
+ switch v := params["d"].(type) {
+ case float64:
+ if v < 1 || v > 31 {
+ return nil, xerr.NewErrMsg("生日性格查询缺少必填参数:d(日期 1-31)")
+ }
+ d = int(v)
+ case string:
+ if v == "" {
+ return nil, xerr.NewErrMsg("生日性格查询缺少必填参数:d(日期 1-31)")
+ }
+ dInt, err := strconv.Atoi(v)
+ if err != nil || dInt < 1 || dInt > 31 {
+ return nil, xerr.NewErrMsg("生日性格查询参数 d 必须是 1-31 的数字")
+ }
+ d = dInt
+ default:
return nil, xerr.NewErrMsg("生日性格查询缺少必填参数:d(日期 1-31)")
}
- reqParams["d"] = int(d)
+ reqParams["d"] = d
// 调用天行 API
resp, err := s.tianxingjuheClient.Get("dob/index", reqParams)
@@ -4783,18 +4947,9 @@ func (s *ToolboxService) processDOB(
return nil, xerr.NewErrMsg("解析生日性格数据失败")
}
- // 字段白名单
- clean := map[string]interface{}{}
- if title, ok := result["title"]; ok {
- clean["title"] = title
- }
- if content, ok := result["content"]; ok {
- clean["content"] = content
- }
-
return map[string]interface{}{
- "count": 1,
- "list": []map[string]interface{}{clean},
+ "title": result["title"],
+ "content": result["content"],
}, nil
}
@@ -5178,12 +5333,25 @@ func (s *ToolboxService) processConstellation(ctx context.Context, params map[st
}
reqParams["astro"] = astro
- // 可选:运势类型 (today/tomorrow/week/month)
+ // 可选:日期 (fortune参数转换为date)
if fortune, ok := params["fortune"].(string); ok && fortune != "" {
- reqParams["fortune"] = fortune
+ now := time.Now()
+ switch fortune {
+ case "tomorrow":
+ date := now.AddDate(0, 0, 1)
+ reqParams["date"] = date.Format("2006-01-02")
+ case "week":
+ // 本周返回当前日期
+ reqParams["date"] = now.Format("2006-01-02")
+ case "month":
+ // 本月返回当前日期
+ reqParams["date"] = now.Format("2006-01-02")
+ default: // today
+ reqParams["date"] = now.Format("2006-01-02")
+ }
}
- resp, err := s.tianxingjuheClient.Get("constellation/index", reqParams)
+ resp, err := s.tianxingjuheClient.Get("star/index", reqParams)
if err != nil {
return nil, xerr.NewErrMsg(fmt.Sprintf("请求星座运势API失败: %v", err))
}
@@ -5197,28 +5365,54 @@ func (s *ToolboxService) processConstellation(ctx context.Context, params map[st
return nil, xerr.NewErrMsg("解析星座运势数据失败")
}
- allowed := map[string]bool{
- "astro": true,
- "fortune": true,
- "summary": true,
- "love": true,
- "work": true,
- "money": true,
- "health": true,
- "number": true,
- "color": true,
- "qfriend": true,
- "date": true,
+ // 解析 list
+ rawList, ok := resultMap["list"].([]interface{})
+ if !ok {
+ return nil, xerr.NewErrMsg("星座运势列表数据异常")
}
- clean := map[string]interface{}{}
- for k, v := range resultMap {
- if allowed[k] {
- clean[k] = v
+ // 将 list 转换为扁平化的 map
+ result := map[string]interface{}{
+ "astro": astro,
+ }
+
+ for _, item := range rawList {
+ raw, ok := item.(map[string]interface{})
+ if !ok {
+ continue
+ }
+
+ typeName, ok := raw["type"].(string)
+ content, hasContent := raw["content"].(string)
+
+ if !ok || !hasContent {
+ continue
+ }
+
+ // 将 type 映射到对应的字段名
+ switch typeName {
+ case "综合指数":
+ result["summary"] = content
+ case "爱情指数":
+ result["love"] = content
+ case "工作指数":
+ result["work"] = content
+ case "财运指数":
+ result["money"] = content
+ case "健康指数":
+ result["health"] = content
+ case "幸运颜色":
+ result["color"] = content
+ case "幸运数字":
+ result["number"] = content
+ case "贵人星座":
+ result["qfriend"] = content
+ case "今日概述":
+ result["today_summary"] = content
}
}
- return clean, nil
+ return result, nil
}
// processFanyi 在线翻译
@@ -5266,23 +5460,35 @@ func (s *ToolboxService) processFanyi(ctx context.Context, params map[string]int
// processHoliday 节假日查询
func (s *ToolboxService) processHoliday(ctx context.Context, params map[string]interface{}) (map[string]interface{}, error) {
+ // 调试日志:打印接收到的所有参数
+ logx.Infof("processHoliday 收到的参数: %+v", params)
+
reqParams := map[string]interface{}{}
- date, ok := params["date"].(string)
- if !ok || date == "" {
- date = time.Now().Format("2006-01-02")
- }
- reqParams["date"] = date
-
- if typ, ok := params["type"].(float64); ok {
- reqParams["type"] = int(typ)
- } else {
- reqParams["type"] = 0
+ // 获取查询方式(1=按年,2=按月),默认按年
+ var queryType int = 1
+ if typ, ok := params["type"]; ok {
+ switch v := typ.(type) {
+ case float64:
+ queryType = int(v)
+ case string:
+ if val, err := strconv.Atoi(v); err == nil {
+ queryType = val
+ }
+ case json.Number:
+ if val, err := strconv.Atoi(v.String()); err == nil {
+ queryType = val
+ }
+ }
}
- if mode, ok := params["mode"].(float64); ok {
- reqParams["mode"] = int(mode)
- }
+ // 将type直接传给天行API
+ reqParams["type"] = queryType
+
+ // 传当前日期
+ reqParams["date"] = time.Now().Format("2006-01-02")
+
+ logx.Infof("调用天行API: type=%d, date=%s", queryType, reqParams["date"])
resp, err := s.tianxingjuheClient.Get("jiejiari/index", reqParams)
if err != nil {
@@ -5627,9 +5833,29 @@ func (s *ToolboxService) processTarga(
return nil, xerr.NewErrMsg("解析扩展名查询数据失败")
}
+ // 清理HTML标签
+ targa := ""
+ notes := ""
+
+ if v, ok := result["targa"].(string); ok {
+ targa = v
+ }
+
+ if v, ok := result["notes"].(string); ok {
+ // 移除HTML标签
+ re := regexp.MustCompile(`<[^>]+>`)
+ notes = re.ReplaceAllString(v, "")
+ // 替换换行标签
+ notes = regexp.MustCompile(`(?i)
`).ReplaceAllString(notes, "\n")
+ // 去除多余空行
+ notes = regexp.MustCompile(`\n{3,}`).ReplaceAllString(notes, "\n\n")
+ // 去除首尾空白
+ notes = strings.TrimSpace(notes)
+ }
+
return map[string]interface{}{
- "targa": result["targa"],
- "notes": result["notes"],
+ "targa": targa,
+ "notes": notes,
}, nil
}
@@ -5815,15 +6041,20 @@ func (s *ToolboxService) processDuoYinZi(
params map[string]interface{},
) (map[string]interface{}, error) {
+ logx.Infof("processDuoYinZi 收到的参数: %+v", params)
+
reqParams := map[string]interface{}{}
// 多音字(必填)
word, ok := params["word"].(string)
+ logx.Infof("word 值: %v, 类型: %T, ok: %v", word, params["word"], ok)
if !ok || word == "" {
return nil, xerr.NewErrMsg("多音字查询缺少必填参数:word")
}
reqParams["word"] = word
+ logx.Infof("调用天行API: word=%s", word)
+
// 调用天行 API
resp, err := s.tianxingjuheClient.Get("duoyinzi/index", reqParams)
if err != nil {
@@ -5831,7 +6062,7 @@ func (s *ToolboxService) processDuoYinZi(
}
if resp.Code != 200 {
- return nil, xerr.NewErrMsg(fmt.Sprintf("多音字接口异常: %s", resp.Msg))
+ return nil, xerr.NewErrMsg(fmt.Sprintf("该字无多音字."))
}
// 解析 result
@@ -5846,6 +6077,7 @@ func (s *ToolboxService) processDuoYinZi(
return nil, xerr.NewErrMsg("多音字列表数据异常")
}
+ // 将多音字信息合并成一个字符串
list := make([]string, 0, len(rawList))
for _, item := range rawList {
if s, ok := item.(string); ok {
@@ -5854,13 +6086,12 @@ func (s *ToolboxService) processDuoYinZi(
}
return map[string]interface{}{
- "hanzi": result["hanzi"],
- "count": len(list),
- "list": list,
+ "word": result["hanzi"],
+ "content": strings.Join(list, "\n"),
}, nil
}
-// processDailyTel 全国常用电话查询
+// processDailyTel 全国常用电话
func (s *ToolboxService) processDailyTel(
ctx context.Context,
params map[string]interface{},
@@ -6015,9 +6246,24 @@ func (s *ToolboxService) processChaiZi(
reqParams["word"] = word
// 查询类型(可选,默认 0)
- if typ, ok := params["type"].(float64); ok {
- reqParams["type"] = int(typ)
+ var queryType int
+ if typ, ok := params["type"]; ok {
+ switch v := typ.(type) {
+ case float64:
+ queryType = int(v)
+ case string:
+ if val, err := strconv.Atoi(v); err == nil {
+ queryType = val
+ }
+ case json.Number:
+ if val, err := strconv.Atoi(v.String()); err == nil {
+ queryType = val
+ }
+ }
}
+ reqParams["type"] = queryType
+
+ logx.Infof("汉字拆解 - type: %d, word: %s", queryType, word)
// 调用天行 API
resp, err := s.tianxingjuheClient.Get("chaizi/index", reqParams)
@@ -6056,9 +6302,20 @@ func (s *ToolboxService) processChaiZi(
list = append(list, clean)
}
+ // 将列表合并成文本格式
+ contentList := make([]string, 0, len(list))
+ for _, item := range list {
+ if texts, ok := item["texts"].(string); ok {
+ contentList = append(contentList, texts)
+ }
+ if words, ok := item["words"].(string); ok {
+ contentList = append(contentList, words)
+ }
+ }
+
return map[string]interface{}{
- "count": len(list),
- "list": list,
+ "word": word,
+ "content": strings.Join(contentList, "\n"),
}, nil
}
@@ -6214,10 +6471,24 @@ func (s *ToolboxService) processFlmj(
return nil, xerr.NewErrMsg("解析分类名句数据失败")
}
+ // 检查是否返回了列表(num > 1 时)
+ if list, hasList := result["list"]; hasList {
+ if listArray, isArray := list.([]interface{}); isArray && len(listArray) > 0 {
+ // 返回第一个结果
+ if firstItem, ok := listArray[0].(map[string]interface{}); ok {
+ return map[string]interface{}{
+ "source": firstItem["source"],
+ "content": firstItem["content"],
+ }, nil
+ }
+ }
+ }
+
return map[string]interface{}{
"source": result["source"],
"content": result["content"],
}, nil
+
}
// processXhZd 新华字典查询
@@ -6265,16 +6536,43 @@ func (s *ToolboxService) processXhZd(
return nil, xerr.NewErrMsg("解析新华字典数据失败")
}
+ logx.Infof("新华字典API返回的result: %+v", result)
+
+ // 解析 list
+ rawList, ok := result["list"].([]interface{})
+ if !ok || len(rawList) == 0 {
+ return nil, xerr.NewErrMsg("新华字典列表数据异常")
+ }
+
+ // 取第一个元素
+ firstItem, ok := rawList[0].(map[string]interface{})
+ if !ok {
+ return nil, xerr.NewErrMsg("新华字典数据格式异常")
+ }
+
+ // 去除HTML标签
+ htmlTagRegex := regexp.MustCompile(`<[^>]+>`)
+
+ content := ""
+ if c, ok := firstItem["content"].(string); ok {
+ content = htmlTagRegex.ReplaceAllString(c, "")
+ }
+
+ explain := ""
+ if e, ok := firstItem["explain"].(string); ok {
+ explain = htmlTagRegex.ReplaceAllString(e, "")
+ }
+
return map[string]interface{}{
- "hanzi": result["name"],
- "py": result["py"],
- "pyyb": result["pyyb"],
- "wubi": result["wubi"],
- "bihua": result["bihua"],
- "bushou": result["bushou"],
- "bishun": result["bishun"],
- "content": result["content"],
- "explain": result["explain"],
+ "word": firstItem["hanzi"],
+ "py": firstItem["py"],
+ "pyyb": firstItem["pyyb"],
+ "wubi": firstItem["wubi"],
+ "bihua": firstItem["bihua"],
+ "bushou": firstItem["bushou"],
+ "bishun": firstItem["bishun"],
+ "content": content,
+ "explain": explain,
}, nil
}
@@ -6868,11 +7166,14 @@ func (s *ToolboxService) processAqi(
reqParams := map[string]interface{}{}
// 地区名称(必填)
- area, ok := params["area"].(string)
- if !ok || area == "" {
+ city, ok := params["city"].(string)
+ logx.Infof("city 值: %v, 类型: %T, ok: %v", city, params["city"], ok)
+ if !ok || city == "" {
return nil, xerr.NewErrMsg("空气质量指数查询缺少必填参数:area")
}
- reqParams["area"] = area
+ reqParams["area"] = city
+
+ logx.Infof("调用天行API: area=%s", city)
// 调用天行 API
resp, err := s.tianxingjuheClient.Get("aqi/index", reqParams)
@@ -6956,28 +7257,27 @@ func (s *ToolboxService) processPet(
reqParams := map[string]interface{}{}
- // 每页返回数量(必填)
- num, ok := params["num"].(float64)
- if !ok || num <= 0 {
- return nil, xerr.NewErrMsg("宠物大全查询缺少必填参数:num")
+ // 每页返回数量(默认10,前端可选)
+ num := 10
+ if v, ok := params["num"].(float64); ok && v > 0 {
+ num = int(v)
}
- reqParams["num"] = int(num)
+ reqParams["num"] = num
- // 翻页(必填)
- page, ok := params["page"].(float64)
- if !ok || page <= 0 {
- return nil, xerr.NewErrMsg("宠物大全查询缺少必填参数:page")
+ // 翻页(默认1,前端可选)
+ page := 1
+ if v, ok := params["page"].(float64); ok && v > 0 {
+ page = int(v)
}
- reqParams["page"] = int(page)
+ reqParams["page"] = page
- // 宠物名称(可选)
+ // 宠物名称(可选,用于搜索)
if name, ok := params["name"].(string); ok && name != "" {
reqParams["name"] = name
}
- // 宠物类型(可选)
- if typ, ok := params["type"].(float64); ok &&
- typ >= 0 && typ <= 4 {
+ // 宠物类型(可选):0猫科、1犬类、2爬行类、3小宠物类、4水族类
+ if typ, ok := params["type"].(float64); ok && typ >= 0 && typ <= 4 {
reqParams["type"] = int(typ)
}
@@ -7002,6 +7302,24 @@ func (s *ToolboxService) processPet(
return nil, xerr.NewErrMsg("宠物大全列表数据异常")
}
+ // 字段白名单
+ allowed := map[string]bool{
+ "name": true,
+ "engName": true,
+ "pettype": true,
+ "nation": true,
+ "life": true,
+ "price": true,
+ "characters": true,
+ "feature": true,
+ "characterFeature": true,
+ "feedPoints": true,
+ "careKnowledge": true,
+ "easyOfDisease": true,
+ "coverURL": true,
+ "desc": true,
+ }
+
list := make([]map[string]interface{}, 0, len(rawList))
for _, item := range rawList {
raw, ok := item.(map[string]interface{})
@@ -7010,50 +7328,20 @@ func (s *ToolboxService) processPet(
}
clean := map[string]interface{}{}
- if v, ok := raw["name"]; ok {
- clean["name"] = v
- }
- if v, ok := raw["engName"]; ok {
- clean["engName"] = v
- }
- if v, ok := raw["pettype"]; ok {
- clean["pettype"] = v
- }
- if v, ok := raw["nation"]; ok {
- clean["nation"] = v
- }
- if v, ok := raw["life"]; ok {
- clean["life"] = v
- }
- if v, ok := raw["price"]; ok {
- clean["price"] = v
- }
- if v, ok := raw["characters"]; ok {
- clean["characters"] = v
- }
- if v, ok := raw["feature"]; ok {
- clean["feature"] = v
- }
- if v, ok := raw["characterFeature"]; ok {
- clean["characterFeature"] = v
- }
- if v, ok := raw["feedPoints"]; ok {
- clean["feedPoints"] = v
- }
- if v, ok := raw["careKnowledge"]; ok {
- clean["careKnowledge"] = v
- }
- if v, ok := raw["easyOfDisease"]; ok {
- clean["easyOfDisease"] = v
- }
- if v, ok := raw["coverURL"]; ok {
- clean["coverURL"] = v
- }
- if v, ok := raw["desc"]; ok {
- clean["desc"] = v
+ for k, v := range raw {
+ if allowed[k] {
+ clean[k] = v
+ }
}
- list = append(list, clean)
+ // 至少要有宠物名称
+ if clean["name"] != nil {
+ list = append(list, clean)
+ }
+ }
+
+ if len(list) == 0 {
+ return nil, xerr.NewErrMsg("未查询到相关宠物信息")
}
return map[string]interface{}{
@@ -7167,6 +7455,18 @@ func (s *ToolboxService) processDouYinHot(
if v, ok := raw["hotindex"]; ok {
clean["hotindex"] = v
}
+ if v, ok := raw["label"]; ok {
+ // 转换label为可读文本
+ labelMap := map[int]string{
+ 0: "普通",
+ 1: "新",
+ 2: "荐",
+ 3: "热",
+ }
+ if labelInt, ok := v.(float64); ok {
+ clean["label_text"] = labelMap[int(labelInt)]
+ }
+ }
list = append(list, clean)
}
@@ -7308,72 +7608,6 @@ func (s *ToolboxService) processAreaData(
}, nil
}
-// processYuanQu 元曲三百首查询
-func (s *ToolboxService) processYuanQu(
- ctx context.Context,
- params map[string]interface{},
-) (map[string]interface{}, error) {
-
- reqParams := map[string]interface{}{
- "num": 1,
- "page": 1,
- }
-
- // 数量
- if num, ok := params["num"].(int); ok && num > 0 {
- reqParams["num"] = num
- }
- // 页码
- if page, ok := params["page"].(int); ok && page > 0 {
- reqParams["page"] = page
- }
- // 关键词搜索
- if word, ok := params["word"].(string); ok && word != "" {
- reqParams["word"] = word
- }
-
- // 请求接口
- resp, err := s.tianxingjuheClient.Get("yuanqu/index", reqParams)
- if err != nil {
- return nil, xerr.NewErrMsg(fmt.Sprintf("请求元曲接口失败: %v", err))
- }
- if resp.Code != 200 {
- return nil, xerr.NewErrMsg(fmt.Sprintf("元曲接口异常: %s", resp.Msg))
- }
-
- result, ok := resp.Result.(map[string]interface{})
- if !ok {
- return nil, xerr.NewErrMsg("解析元曲数据失败")
- }
-
- rawList, ok := result["list"].([]interface{})
- if !ok {
- return nil, xerr.NewErrMsg("元曲列表数据异常")
- }
-
- list := make([]map[string]interface{}, 0, len(rawList))
- for _, item := range rawList {
- raw, ok := item.(map[string]interface{})
- if !ok {
- continue
- }
- info := map[string]interface{}{
- "title": raw["title"],
- "author": raw["author"],
- "chapter": raw["chapter"],
- "content": raw["content"],
- "note": raw["note"],
- "translation": raw["translation"],
- }
- list = append(list, info)
- }
-
- return map[string]interface{}{
- "count": len(list),
- "list": list,
- }, nil
-}
-
// processMgJuZi 获取民国句子
func (s *ToolboxService) processMgJuZi(
ctx context.Context,
@@ -7598,9 +7832,9 @@ func (s *ToolboxService) processQingShi(
}
return map[string]interface{}{
- "author": result["author"],
- "source": result["source"],
- "poem": result["content"],
+ "author": result["author"],
+ "source": result["source"],
+ "content": result["content"],
}, nil
}
@@ -7657,49 +7891,6 @@ func (s *ToolboxService) processChengyuJieLong(
}, nil
}
-// processWeiBoHot 获取微博热搜榜
-func (s *ToolboxService) processWeiBoHot(
- ctx context.Context,
- params map[string]interface{},
-) (map[string]interface{}, error) {
-
- reqParams := map[string]interface{}{}
-
- resp, err := s.tianxingjuheClient.Get("weibohot/index", reqParams)
- if err != nil {
- return nil, xerr.NewErrMsg(fmt.Sprintf("请求微博热搜接口失败: %v", err))
- }
- if resp.Code != 200 {
- return nil, xerr.NewErrMsg(fmt.Sprintf("微博热搜接口异常: %s", resp.Msg))
- }
-
- result, ok := resp.Result.(map[string]interface{})
- if !ok {
- return nil, xerr.NewErrMsg("解析微博热搜数据失败")
- }
-
- rawList, ok := result["list"].([]interface{})
- if !ok {
- return nil, xerr.NewErrMsg("热搜列表数据异常")
- }
-
- var hotList []map[string]interface{}
- for _, item := range rawList {
- info, _ := item.(map[string]interface{})
- hotList = append(hotList, map[string]interface{}{
- "tag": info["hottag"],
- "title": info["hotword"],
- "hotValue": info["hotwordnum"],
- "link": "https://s.weibo.com/weibo?q=" + info["hotword"].(string),
- })
- }
-
- return map[string]interface{}{
- "total": len(hotList),
- "list": hotList,
- }, nil
-}
-
// processLaJiFenLei 垃圾分类查询
func (s *ToolboxService) processLaJiFenLei(
ctx context.Context,
@@ -7947,7 +8138,7 @@ func (s *ToolboxService) ListTools() []ToolInfo {
// ─── 第二批新增工具 ───
{Key: "timezone", Name: "时区查询", Desc: "查询全球各时区的当前时间"},
{Key: "duoyinzi", Name: "多音字查询", Desc: "查询汉字的多音字及不同读音"},
- {Key: "dailytel", Name: "每日一句", Desc: "每日一句励志语录"},
+ {Key: "dailytel", Name: "全国常用电话", Desc: "汇总政府机关、银行、电商、快递、学校等全国常用机构对外联系电话。"},
{Key: "obdcode", Name: "OBD故障码", Desc: "查询汽车OBD故障码含义及解决方案"},
{Key: "chaizi", Name: "汉字拆解", Desc: "查询汉字的拆字结构及含义"},
{Key: "huayu", Name: "华语句子", Desc: "随机返回优美华语句子"},
@@ -7966,9 +8157,8 @@ func (s *ToolboxService) ListTools() []ToolInfo {
{Key: "worldtime", Name: "世界时间", Desc: "查询全球主要城市当前时间"},
{Key: "wxhottopic", Name: "微信热点", Desc: "获取微信实时热点话题"},
{Key: "zmsc", Name: "字明说", Desc: "汉字谐音趣味解读"},
- {Key: "hsjz", Name: "黄氏简码", Desc: "黄氏简码输入法查询"},
+ {Key: "hsjz", Name: "失恋分手句子", Desc: "随机返回失恋分手相关的经典句子"},
{Key: "gjmj", Name: "国际民调", Desc: "国际民调数据查询"},
- {Key: "cnmoney", Name: "人民币", Desc: "人民币面额、图案、防伪特征"},
{Key: "lzmy", Name: "励志名言", Desc: "励志名言警句"},
{Key: "baiketiku", Name: "百科题库", Desc: "百科知识问答题库"},
{Key: "dialogue", Name: "对话生成", Desc: "智能对话内容生成"},
@@ -8010,3 +8200,57 @@ func (s *ToolboxService) RegisterTool(key string, processor ToolProcessor) error
s.processors[key] = processor
return nil
}
+
+// stripHTMLTags 移除HTML标签,保留纯文本
+func stripHTMLTags(html string) string {
+ // 移除所有HTML标签
+ re := regexp.MustCompile(`<[^>]*>`)
+ text := re.ReplaceAllString(html, "")
+
+ // 移除多余的空白字符
+ text = strings.TrimSpace(text)
+ text = regexp.MustCompile(`\s+`).ReplaceAllString(text, " ")
+
+ return text
+}
+
+// cleanHTMLContent 清理HTML内容,智能处理换行
+func cleanHTMLContent(html string) string {
+ if html == "" {
+ return html
+ }
+
+ // 移除`).ReplaceAllString(html, "")
+
+ // 移除`).ReplaceAllString(html, "")
+
+ // 移除所有HTML标签
+ re := regexp.MustCompile(`<[^>]*>`)
+ text := re.ReplaceAllString(html, "")
+
+ // 替换HTML实体
+ entityMap := map[string]string{
+ "<": "<",
+ ">": ">",
+ "&": "&",
+ """: "\"",
+ " ": " ",
+ "'": "'",
+ "”": "”",
+ "“": "“",
+ "…": "…",
+ }
+ for entity, char := range entityMap {
+ text = strings.ReplaceAll(text, entity, char)
+ }
+
+ // 规范化空白字符:将连续空白替换为单个空格
+ text = regexp.MustCompile(`\s+`).ReplaceAllString(text, " ")
+
+ // 清理首尾空白
+ text = strings.TrimSpace(text)
+
+ return text
+}
diff --git a/pkg/lzkit/crypto/ecb_test.go b/pkg/lzkit/crypto/ecb_test.go
index f7cb2f2..6faa812 100644
--- a/pkg/lzkit/crypto/ecb_test.go
+++ b/pkg/lzkit/crypto/ecb_test.go
@@ -9,7 +9,7 @@ import (
func TestAesEcbMobileEncryption(t *testing.T) {
// 测试手机号加密
- mobile := "18653052547"
+ mobile := "15029295957"
key := []byte("ff83609b2b24fc73196aac3d3dfb874f") // 16字节AES-128密钥
keyStr := hex.EncodeToString(key)
@@ -19,7 +19,8 @@ func TestAesEcbMobileEncryption(t *testing.T) {
t.Fatalf("手机号加密失败: %v", err)
}
fmt.Printf("encrypted: %s\n", encrypted)
- jmStr := "m9EEeW9ZBBJmi1hx1k1uIQ=="
+
+ jmStr := "Am8/KpmBnsbXZoZOZq/oVQ=="
// 测试解密
decrypted, err := DecryptMobile(jmStr, keyStr)
if err != nil {