模块介绍 / 今日规划 / 下班日报 / 团队摘要 生成成功后没有上报,也几乎不写「AI」日志。

流结束时的 usage 用了非阻塞发送,通道一满就被丢掉;很多服务商默认还不在流里带 usage。
现在每次真正打到模型的调用都会:

在本地日志(分类 AI,消息 AI 调用完成)写下 scene / prompt / completion / cached
登录后同步上报到后台日汇总
This commit is contained in:
李琦
2026-08-17 14:00:47 +08:00
parent 83e69317d4
commit e71ce451ff
23 changed files with 1363 additions and 93 deletions

261
holidays.go Normal file
View File

@@ -0,0 +1,261 @@
package main
// holidays.go 给 AI 任务拆解提供「本月 + 未来几个月」节假日公历对照。
// 农历节日每年换算不同,法定放假以国务院已公布年份为准;未公布年份只给节日当天。
import (
"fmt"
"sort"
"strings"
"time"
)
type holidayItem struct {
day time.Time
offStart time.Time // 放假开始;零值表示仅节日当天
offEnd time.Time // 放假结束(含)
work []time.Time
zh, en string
aka string
}
// upcomingHolidays 从本月 1 日到未来 months 个月月末(默认 6的节日按日期排序。
func upcomingHolidays(now time.Time, months int) []holidayItem {
if months <= 0 {
months = 6
}
loc := now.Location()
start := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, loc)
end := start.AddDate(0, months+1, 0) // 不含:覆盖「未来几个月」整月
var out []holidayItem
for y := start.Year(); y <= end.Year(); y++ {
for _, h := range yearHolidays(y, loc) {
if !h.day.Before(start) && h.day.Before(end) {
out = append(out, h)
}
}
}
sort.Slice(out, func(i, j int) bool { return out[i].day.Before(out[j].day) })
return out
}
func formatHolidayBlock(now time.Time, en bool) string {
list := upcomingHolidays(now, 6)
if len(list) == 0 {
return ""
}
var b strings.Builder
if en {
b.WriteString("Holidays this month and the next 6 months (use these exact dates; do not guess):\n")
} else {
b.WriteString("本月及未来 6 个月节假日对照(必须用表中公历,禁止自己换算农历):\n")
}
for _, h := range list {
name := h.zh
if en {
name = h.en
if h.aka != "" {
name += " / " + h.aka
} else if h.zh != "" {
name += " / " + h.zh
}
} else if h.aka != "" {
name += " / " + h.aka
}
line := fmt.Sprintf("- %s%s", name, h.day.Format("2006-01-02"))
if !h.offStart.IsZero() && !h.offEnd.IsZero() {
line += fmt.Sprintf("(放假 %s%s", h.offStart.Format("2006-01-02"), h.offEnd.Format("2006-01-02"))
if len(h.work) > 0 {
ws := make([]string, len(h.work))
for i, w := range h.work {
ws[i] = w.Format("2006-01-02")
}
line += ";调休上班 " + strings.Join(ws, "、")
}
line += ""
}
b.WriteString(line + "\n")
}
if en {
b.WriteString("Phrases: “before X” → day before the festival; “during X” → official holiday span if listed, else the festival day; “after X” → day after the holiday ends.\n")
} else {
b.WriteString("说法对照「X前 / X之前」= 节日前一天「X期间 / X放假」= 表中放假区间没有区间就用当天「X后 / X之后」= 假期结束后一天。国庆可说十一,春节可说过年,元旦可说新年(公历)。\n")
}
return b.String()
}
func yearHolidays(year int, loc *time.Location) []holidayItem {
d := func(m, day int) time.Time {
return time.Date(year, time.Month(m), day, 0, 0, 0, 0, loc)
}
items := []holidayItem{
{day: d(1, 1), zh: "元旦", en: "New Year's Day", aka: "新年"},
{day: d(2, 14), zh: "情人节", en: "Valentine's Day"},
{day: d(3, 8), zh: "妇女节", en: "Women's Day"},
{day: d(3, 12), zh: "植树节", en: "Arbor Day (CN)"},
{day: d(4, 1), zh: "愚人节", en: "April Fools' Day"},
{day: d(5, 1), zh: "劳动节", en: "Labor Day", aka: "五一"},
{day: d(5, 4), zh: "青年节", en: "Youth Day"},
{day: nthWeekday(year, time.May, time.Sunday, 2, loc), zh: "母亲节", en: "Mother's Day"},
{day: d(6, 1), zh: "儿童节", en: "Children's Day"},
{day: nthWeekday(year, time.June, time.Sunday, 3, loc), zh: "父亲节", en: "Father's Day"},
{day: d(7, 1), zh: "建党节", en: "CPC Founding Day"},
{day: d(8, 1), zh: "建军节", en: "PLA Day"},
{day: d(9, 10), zh: "教师节", en: "Teachers' Day"},
{day: d(10, 1), zh: "国庆节", en: "National Day", aka: "十一、国庆黄金周"},
{day: d(10, 24), zh: "程序员节", en: "Programmer's Day"},
{day: d(10, 31), zh: "万圣节", en: "Halloween"},
{day: nthWeekday(year, time.November, time.Thursday, 4, loc), zh: "感恩节", en: "Thanksgiving"},
{day: d(11, 11), zh: "双十一", en: "Singles' Day", aka: "光棍节"},
{day: d(12, 12), zh: "双十二", en: "Double 12"},
{day: d(12, 24), zh: "平安夜", en: "Christmas Eve"},
{day: d(12, 25), zh: "圣诞节", en: "Christmas"},
}
// 黑色星期五 = 感恩节次日
for i := range items {
if items[i].zh == "感恩节" {
bf := items[i].day.AddDate(0, 0, 1)
items = append(items, holidayItem{day: bf, zh: "黑色星期五", en: "Black Friday"})
break
}
}
items = append(items, lunarHolidays(year, loc)...)
items = append(items, solarTermHolidays(year, loc)...)
applyOfficialOff(year, loc, items)
return items
}
func nthWeekday(year int, month time.Month, wd time.Weekday, n int, loc *time.Location) time.Time {
d := time.Date(year, month, 1, 0, 0, 0, 0, loc)
delta := int(wd - d.Weekday())
if delta < 0 {
delta += 7
}
return d.AddDate(0, 0, delta+7*(n-1))
}
// lunarHolidays 农历节日的公历对照20252029。春节 day=正月初一。
func lunarHolidays(year int, loc *time.Location) []holidayItem {
type row struct{ m, d int }
// key → 公历月日
table := map[int]map[string]row{
2025: {
"除夕": {1, 28}, "春节": {1, 29}, "元宵": {2, 12}, "端午": {5, 31},
"七夕": {8, 29}, "中元": {9, 6}, "中秋": {10, 6}, "重阳": {10, 29},
},
2026: {
"除夕": {2, 16}, "春节": {2, 17}, "元宵": {3, 3}, "端午": {6, 19},
"七夕": {8, 19}, "中元": {8, 27}, "中秋": {9, 25}, "重阳": {10, 18},
},
2027: {
"除夕": {2, 5}, "春节": {2, 6}, "元宵": {2, 20}, "端午": {6, 9},
"七夕": {8, 8}, "中元": {8, 16}, "中秋": {9, 15}, "重阳": {10, 8},
},
2028: {
"除夕": {1, 25}, "春节": {1, 26}, "元宵": {2, 9}, "端午": {5, 28},
"七夕": {8, 26}, "中元": {9, 3}, "中秋": {10, 3}, "重阳": {10, 26},
},
2029: {
"除夕": {2, 12}, "春节": {2, 13}, "元宵": {2, 27}, "端午": {6, 16},
"七夕": {8, 16}, "中元": {8, 24}, "中秋": {9, 22}, "重阳": {10, 16},
},
}
names := map[string][2]string{
"除夕": {"除夕", "Lunar New Year's Eve"},
"春节": {"春节", "Spring Festival"},
"元宵": {"元宵节", "Lantern Festival"},
"端午": {"端午节", "Dragon Boat Festival"},
"七夕": {"七夕", "Qixi Festival"},
"中元": {"中元节", "Ghost Festival"},
"中秋": {"中秋节", "Mid-Autumn Festival"},
"重阳": {"重阳节", "Double Ninth Festival"},
}
aka := map[string]string{
"春节": "过年、农历新年、正月初一",
"端午": "端阳",
"中秋": "八月十五",
"除夕": "年三十",
}
m, ok := table[year]
if !ok {
return nil
}
var out []holidayItem
for k, r := range m {
n := names[k]
out = append(out, holidayItem{
day: time.Date(year, time.Month(r.m), r.d, 0, 0, 0, 0, loc),
zh: n[0], en: n[1], aka: aka[k],
})
}
return out
}
// solarTermHolidays 常用节气(用户会当日期说)。
func solarTermHolidays(year int, loc *time.Location) []holidayItem {
type row struct {
m, d int
zh, en string
}
table := map[int][]row{
2025: {{2, 3, "立春", "Start of Spring"}, {4, 4, "清明", "Qingming"}, {6, 21, "夏至", "Summer Solstice"}, {12, 21, "冬至", "Winter Solstice"}},
2026: {{2, 4, "立春", "Start of Spring"}, {4, 5, "清明", "Qingming"}, {6, 21, "夏至", "Summer Solstice"}, {12, 22, "冬至", "Winter Solstice"}},
2027: {{2, 4, "立春", "Start of Spring"}, {4, 5, "清明", "Qingming"}, {6, 21, "夏至", "Summer Solstice"}, {12, 22, "冬至", "Winter Solstice"}},
2028: {{2, 4, "立春", "Start of Spring"}, {4, 4, "清明", "Qingming"}, {6, 21, "夏至", "Summer Solstice"}, {12, 21, "冬至", "Winter Solstice"}},
2029: {{2, 3, "立春", "Start of Spring"}, {4, 4, "清明", "Qingming"}, {6, 21, "夏至", "Summer Solstice"}, {12, 22, "冬至", "Winter Solstice"}},
}
var out []holidayItem
for _, r := range table[year] {
aka := ""
if r.zh == "清明" {
aka = "清明节"
}
out = append(out, holidayItem{
day: time.Date(year, time.Month(r.m), r.d, 0, 0, 0, 0, loc),
zh: r.zh, en: r.en, aka: aka,
})
}
return out
}
type offSpan struct {
offStart [2]int // month, day可能早于节日当天如春节
offEnd [2]int
work [][2]int
}
// applyOfficialOff 套上已公布的国务院放假调休2026
func applyOfficialOff(year int, loc *time.Location, items []holidayItem) {
spans, ok := officialOff[year]
if !ok {
return
}
md := func(p [2]int) time.Time {
return time.Date(year, time.Month(p[0]), p[1], 0, 0, 0, 0, loc)
}
for i := range items {
sp, hit := spans[items[i].zh]
if !hit {
continue
}
items[i].offStart = md(sp.offStart)
items[i].offEnd = md(sp.offEnd)
for _, w := range sp.work {
items[i].work = append(items[i].work, md(w))
}
}
}
// officialOff 国务院已公布年份。2026国办发2025通知。
var officialOff = map[int]map[string]offSpan{
2026: {
"元旦": {offStart: [2]int{1, 1}, offEnd: [2]int{1, 3}, work: [][2]int{{1, 4}}},
"春节": {offStart: [2]int{2, 15}, offEnd: [2]int{2, 23}, work: [][2]int{{2, 14}, {2, 28}}},
"清明": {offStart: [2]int{4, 4}, offEnd: [2]int{4, 6}},
"清明节": {offStart: [2]int{4, 4}, offEnd: [2]int{4, 6}},
"劳动节": {offStart: [2]int{5, 1}, offEnd: [2]int{5, 5}, work: [][2]int{{5, 9}}},
"端午节": {offStart: [2]int{6, 19}, offEnd: [2]int{6, 21}},
"中秋节": {offStart: [2]int{9, 25}, offEnd: [2]int{9, 27}},
"国庆节": {offStart: [2]int{10, 1}, offEnd: [2]int{10, 7}, work: [][2]int{{9, 20}, {10, 10}}},
},
}