gcli2api / internal /upstream /blackcat.go
a3216's picture
chore: 同步到上游 1.12.0-panel + 凭证同步/独立启动器/保活
6d60378 verified
Raw History Blame Contribute Delete
4.19 kB
// blackcat.go 夜猫子任务(black_cat)+ 新手礼包/补偿 API。
//
// 判据(WorkBuddy-Daily 项目实测口径 + 本网关验证):black_cat 要求在
// **23:00–08:00(本地时区)窗口内**完成 3 次 glm-5.2 对话并上报 chat 事件链;
// 窗口外行为不计分。真实对话走网关既有 ChatStream(glm-5.2),事件链用
// ReportChatActivityModel(chat_5 同款上报形状)。
package upstream
import (
"encoding/json"
"fmt"
"io"
"net/http"
"time"
"github.com/linguo2625469/workbuddy2api-panel/internal/auth"
)
// InNightWindow 当前是否处于夜猫子计数窗口(23:00–08:00 本地时区)。
func InNightWindow(now time.Time) bool {
h := now.Hour()
return h >= 23 || h < 8
}
// BlackcatNeed 查 black_cat 任务剩余差额(需要再完成几次对话)。
// 任务不存在返回 0(无可做);拉取失败返回错误。
func (c *Client) BlackcatNeed(a *auth.Auth) (int64, error) {
tasks, err := c.ListTasks(a)
if err != nil {
return 0, err
}
for _, t := range tasks {
if t.TaskCode == "black_cat" {
if t.Claimed || t.Current >= t.Target {
return 0, nil
}
return t.Target - t.Current, nil
}
}
return 0, nil
}
// RunNightChats 夜猫子:发 need 次 glm-5.2 真实对话(读干流)并上报事件链。
// 返回成功次数。对话内容极短(1+1),消耗可忽略。
func (c *Client) RunNightChats(a *auth.Auth, need int) (int64, error) {
var ok int64
for i := 0; i < need; i++ {
body, _ := json.Marshal(map[string]any{
"model": "glm-5.2",
"messages": []map[string]any{{"role": "user", "content": "1+1等于几?直接回答。"}},
"stream": true,
})
rc, status, respBody, err := c.ChatStream(a, body, "", ChatMeta{})
if err != nil || status >= 400 {
if rc != nil {
rc.Close()
}
return ok, fmt.Errorf("第 %d 次对话失败: http=%d err=%v body=%.120s", i+1, status, err, respBody)
}
_, _ = io.Copy(io.Discard, io.LimitReader(rc, 1<<20))
rc.Close()
if err := c.ReportChatActivityModel(a, fmt.Sprintf("wb2api-night-%d-%d", time.Now().UnixMilli(), i), "", "glm-5.2", "GLM-5.2"); err != nil {
return ok, fmt.Errorf("第 %d 次上报失败: %w", i+1, err)
}
ok++
time.Sleep(4 * time.Second)
}
return ok, nil
}
// ClaimGift 领取新手礼包(每号一次,已领返回业务错误)。
func (c *Client) ClaimGift(a *auth.Auth) (int64, error) {
data, err := c.billingJSON(a, http.MethodPost, "/billing/meter/claim-gift", map[string]any{})
if err != nil {
return 0, err
}
var resp struct {
Credit int64 `json:"credit"`
}
_ = json.Unmarshal(data, &resp)
return resp.Credit, nil
}
// ClaimCompensation 领取活动补偿(有则领,无则业务错误)。
func (c *Client) ClaimCompensation(a *auth.Auth) (int64, error) {
data, err := c.billingJSON(a, http.MethodPost, "/billing/meter/claim-compensation", map[string]any{})
if err != nil {
return 0, err
}
var resp struct {
Credit int64 `json:"credit"`
}
_ = json.Unmarshal(data, &resp)
return resp.Credit, nil
}
// HeatmapYesterdayMissed 检查昨日是否漏签(heatmap cell score==0)。
func (c *Client) HeatmapYesterdayMissed(a *auth.Auth) (bool, error) {
yesterday := time.Now().AddDate(0, 0, -1).Format("2006-01-02")
data, err := c.growthJSON(a, http.MethodGet, "/activity/growth/heatmap", nil)
if err != nil {
return false, err
}
var resp struct {
Cells []struct {
Date string `json:"date"`
Score int `json:"score"`
} `json:"cells"`
}
if err := json.Unmarshal(data, &resp); err != nil {
return false, err
}
for _, cell := range resp.Cells {
if len(cell.Date) >= 10 && cell.Date[:10] == yesterday {
return cell.Score == 0, nil
}
}
return false, nil
}
// UseMakeupCard 对指定日期使用补签卡(保住连登连续天数;无卡返回业务错误)。
func (c *Client) UseMakeupCard(a *auth.Auth, date string) error {
_, err := c.growthJSON(a, http.MethodPost, "/activity/growth/makeup-cards/use",
map[string]any{"target_date": date})
return err
}