feat(report): ship daily report v1 experience
This commit is contained in:
@@ -9,44 +9,249 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGenerateMarkdownV3IncludesTencentSubscriptionSection(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "daily_report.md")
|
||||
report := &ReportV3{
|
||||
func sampleReportForV1() *ReportV3 {
|
||||
return &ReportV3{
|
||||
Date: "2026-05-13",
|
||||
TotalModels: 502,
|
||||
QualitySummary: DataQualitySummary{
|
||||
Total: 502,
|
||||
Fresh: 490,
|
||||
CNY: 126,
|
||||
USD: 376,
|
||||
GeneratedAt: "2026-05-13T09:30:00+08:00",
|
||||
TotalModels: 504,
|
||||
AllModels: []ModelInfo{
|
||||
{
|
||||
Name: "DeepSeek-V4-Flash",
|
||||
ProviderName: "DeepSeek",
|
||||
ProviderCountry:"CN",
|
||||
ContextLength: 262144,
|
||||
InputPrice: 0.30,
|
||||
OutputPrice: 1.20,
|
||||
Currency: "USD",
|
||||
OperatorName: "OpenRouter",
|
||||
OperatorType: "reseller",
|
||||
Region: "global",
|
||||
SceneTags: []SceneTag{SceneCode, SceneReasoning},
|
||||
},
|
||||
{
|
||||
Name: "glm-5",
|
||||
ProviderName: "Zhipu",
|
||||
ProviderCountry:"CN",
|
||||
ContextLength: 131072,
|
||||
InputPrice: 0,
|
||||
OutputPrice: 0,
|
||||
Currency: "CNY",
|
||||
IsFree: true,
|
||||
OperatorName: "Zhipu",
|
||||
OperatorType: "official",
|
||||
Region: "cn",
|
||||
SceneTags: []SceneTag{SceneWriting, SceneChat},
|
||||
},
|
||||
{
|
||||
Name: "claude-3.7-sonnet",
|
||||
ProviderName: "Anthropic",
|
||||
ProviderCountry:"US",
|
||||
ContextLength: 200000,
|
||||
InputPrice: 3.0,
|
||||
OutputPrice: 15.0,
|
||||
Currency: "USD",
|
||||
OperatorName: "Anthropic",
|
||||
OperatorType: "official",
|
||||
Region: "global",
|
||||
SceneTags: []SceneTag{SceneWriting, SceneChat},
|
||||
},
|
||||
{
|
||||
Name: "qwen-vl-max",
|
||||
ProviderName: "Alibaba",
|
||||
ProviderCountry:"CN",
|
||||
ContextLength: 65536,
|
||||
InputPrice: 0.8,
|
||||
OutputPrice: 2.4,
|
||||
Currency: "CNY",
|
||||
OperatorName: "DashScope",
|
||||
OperatorType: "cloud",
|
||||
Region: "cn",
|
||||
SceneTags: []SceneTag{SceneVision},
|
||||
},
|
||||
},
|
||||
TencentSubscriptionPlans: []SubscriptionPlanInfo{
|
||||
FreeModels: []ModelInfo{
|
||||
{
|
||||
PlanName: "通用 Token Plan Lite",
|
||||
PlanFamily: "token_plan",
|
||||
Tier: "Lite",
|
||||
Name: "glm-5",
|
||||
ProviderName: "Zhipu",
|
||||
ProviderCountry:"CN",
|
||||
ContextLength: 131072,
|
||||
Currency: "CNY",
|
||||
ListPrice: 39,
|
||||
QuotaValue: 35000000,
|
||||
QuotaUnit: "tokens/month",
|
||||
ContextWindow: 0,
|
||||
ModelCount: 10,
|
||||
ModelPreview: "tc-code-latest, glm-5, glm-5.1",
|
||||
IsFree: true,
|
||||
OperatorName: "Zhipu",
|
||||
OperatorType: "official",
|
||||
Region: "cn",
|
||||
SceneTags: []SceneTag{SceneWriting, SceneChat},
|
||||
},
|
||||
{
|
||||
PlanName: "Hy Token Plan Max",
|
||||
PlanFamily: "token_plan",
|
||||
Tier: "Max",
|
||||
Currency: "CNY",
|
||||
ListPrice: 468,
|
||||
QuotaValue: 650000000,
|
||||
QuotaUnit: "tokens/month",
|
||||
ContextWindow: 262144,
|
||||
ModelCount: 1,
|
||||
ModelPreview: "hy3-preview",
|
||||
Name: "DeepSeek-V4-Flash",
|
||||
ProviderName: "DeepSeek",
|
||||
ProviderCountry:"CN",
|
||||
ContextLength: 262144,
|
||||
Currency: "USD",
|
||||
IsFree: true,
|
||||
OperatorName: "OpenRouter",
|
||||
OperatorType: "reseller",
|
||||
Region: "global",
|
||||
SceneTags: []SceneTag{SceneCode, SceneReasoning},
|
||||
},
|
||||
{
|
||||
Name: "mystery-free-model",
|
||||
ProviderName: "Unknown",
|
||||
ProviderCountry:"unknown",
|
||||
ContextLength: 65536,
|
||||
Currency: "USD",
|
||||
IsFree: true,
|
||||
OperatorName: "Unknown Gateway",
|
||||
OperatorType: "self_hosted_gateway",
|
||||
Region: "global",
|
||||
SceneTags: []SceneTag{SceneChat},
|
||||
},
|
||||
},
|
||||
FreeTop20: []ModelInfo{
|
||||
{
|
||||
Name: "glm-5",
|
||||
ProviderName: "Zhipu",
|
||||
ProviderCountry:"CN",
|
||||
ContextLength: 131072,
|
||||
Currency: "CNY",
|
||||
IsFree: true,
|
||||
OperatorName: "Zhipu",
|
||||
OperatorType: "official",
|
||||
Region: "cn",
|
||||
},
|
||||
},
|
||||
IntlTop5: []ModelInfo{
|
||||
{
|
||||
Name: "DeepSeek-V4-Flash",
|
||||
ProviderName: "DeepSeek",
|
||||
ProviderCountry:"CN",
|
||||
ContextLength: 262144,
|
||||
InputPrice: 0.30,
|
||||
OutputPrice: 1.20,
|
||||
Currency: "USD",
|
||||
OperatorName: "OpenRouter",
|
||||
OperatorType: "reseller",
|
||||
Region: "global",
|
||||
SceneTags: []SceneTag{SceneCode, SceneReasoning},
|
||||
},
|
||||
},
|
||||
DomesticTop10: []ModelInfo{
|
||||
{
|
||||
Name: "qwen-vl-max",
|
||||
ProviderName: "Alibaba",
|
||||
ProviderCountry:"CN",
|
||||
ContextLength: 65536,
|
||||
InputPrice: 0.8,
|
||||
OutputPrice: 2.4,
|
||||
Currency: "CNY",
|
||||
OperatorName: "DashScope",
|
||||
OperatorType: "cloud",
|
||||
Region: "cn",
|
||||
SceneTags: []SceneTag{SceneVision},
|
||||
},
|
||||
},
|
||||
DailySignals: DailySignals{
|
||||
NewModels: 2,
|
||||
PriceChanges: 1,
|
||||
OfficialFree: 1,
|
||||
AggregatorFree:1,
|
||||
UnknownFree: 1,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildFreeSourceBreakdown(t *testing.T) {
|
||||
report := sampleReportForV1()
|
||||
|
||||
breakdown := buildFreeSourceBreakdown(report.FreeModels)
|
||||
|
||||
if len(breakdown) != 3 {
|
||||
t.Fatalf("expected 3 free source groups, got %d", len(breakdown))
|
||||
}
|
||||
|
||||
if breakdown[0].Label != "官方免费" || breakdown[0].Count != 1 {
|
||||
t.Fatalf("unexpected official free breakdown: %+v", breakdown[0])
|
||||
}
|
||||
if breakdown[1].Label != "聚合免费" || breakdown[1].Count != 1 {
|
||||
t.Fatalf("unexpected aggregator free breakdown: %+v", breakdown[1])
|
||||
}
|
||||
if breakdown[2].Label != "待确认" || breakdown[2].Count != 1 {
|
||||
t.Fatalf("unexpected unknown free breakdown: %+v", breakdown[2])
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecorateReportV1BuildsHotDaySummary(t *testing.T) {
|
||||
report := sampleReportForV1()
|
||||
|
||||
decorateReportV1(report)
|
||||
|
||||
if report.PageMode != "hot" {
|
||||
t.Fatalf("expected hot page mode, got %q", report.PageMode)
|
||||
}
|
||||
if !strings.Contains(report.HeroSummary, "2 个新模型") {
|
||||
t.Fatalf("hero summary missing new model signal: %s", report.HeroSummary)
|
||||
}
|
||||
if len(report.ActionItems) != 3 {
|
||||
t.Fatalf("expected 3 action items, got %d", len(report.ActionItems))
|
||||
}
|
||||
if len(report.HeadlineItems) == 0 {
|
||||
t.Fatalf("expected headline items to be built")
|
||||
}
|
||||
if report.ActionItems[0].Evidence == "" {
|
||||
t.Fatalf("expected action item evidence to be populated")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecorateReportV1BuildsCalmDaySummary(t *testing.T) {
|
||||
report := sampleReportForV1()
|
||||
report.DailySignals = DailySignals{}
|
||||
|
||||
decorateReportV1(report)
|
||||
|
||||
if report.PageMode != "calm" {
|
||||
t.Fatalf("expected calm page mode, got %q", report.PageMode)
|
||||
}
|
||||
if !strings.Contains(report.HeroSummary, "稳定") {
|
||||
t.Fatalf("expected calm day summary to emphasize stability, got %s", report.HeroSummary)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateMarkdownV3IncludesTencentSubscriptionSection(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "daily_report.md")
|
||||
report := sampleReportForV1()
|
||||
report.QualitySummary = DataQualitySummary{
|
||||
Total: 502,
|
||||
Fresh: 490,
|
||||
CNY: 126,
|
||||
USD: 376,
|
||||
}
|
||||
report.TencentSubscriptionPlans = []SubscriptionPlanInfo{
|
||||
{
|
||||
PlanName: "通用 Token Plan Lite",
|
||||
PlanFamily: "token_plan",
|
||||
Tier: "Lite",
|
||||
Currency: "CNY",
|
||||
ListPrice: 39,
|
||||
QuotaValue: 35000000,
|
||||
QuotaUnit: "tokens/month",
|
||||
ContextWindow: 0,
|
||||
ModelCount: 10,
|
||||
ModelPreview: "tc-code-latest, glm-5, glm-5.1",
|
||||
},
|
||||
{
|
||||
PlanName: "Hy Token Plan Max",
|
||||
PlanFamily: "token_plan",
|
||||
Tier: "Max",
|
||||
Currency: "CNY",
|
||||
ListPrice: 468,
|
||||
QuotaValue: 650000000,
|
||||
QuotaUnit: "tokens/month",
|
||||
ContextWindow: 262144,
|
||||
ModelCount: 1,
|
||||
ModelPreview: "hy3-preview",
|
||||
},
|
||||
}
|
||||
decorateReportV1(report)
|
||||
|
||||
if err := generateMarkdownV3(report, path); err != nil {
|
||||
t.Fatalf("generateMarkdownV3 returned error: %v", err)
|
||||
@@ -59,6 +264,11 @@ func TestGenerateMarkdownV3IncludesTencentSubscriptionSection(t *testing.T) {
|
||||
|
||||
content := string(body)
|
||||
for _, want := range []string{
|
||||
"## 今日结论",
|
||||
"## 今日行动建议",
|
||||
"## 今日变化",
|
||||
"## 场景推荐",
|
||||
"## 完整数据附录",
|
||||
"## 💳 腾讯云套餐订阅价",
|
||||
"通用 Token Plan Lite",
|
||||
"Hy Token Plan Max",
|
||||
@@ -74,23 +284,21 @@ func TestGenerateMarkdownV3IncludesTencentSubscriptionSection(t *testing.T) {
|
||||
|
||||
func TestGenerateHTMLV3IncludesTencentSubscriptionSection(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "daily_report.html")
|
||||
report := &ReportV3{
|
||||
Date: "2026-05-13",
|
||||
TotalModels: 502,
|
||||
TencentSubscriptionPlans: []SubscriptionPlanInfo{
|
||||
{
|
||||
PlanName: "通用 Token Plan Lite",
|
||||
PlanFamily: "token_plan",
|
||||
Tier: "Lite",
|
||||
Currency: "CNY",
|
||||
ListPrice: 39,
|
||||
QuotaValue: 35000000,
|
||||
QuotaUnit: "tokens/month",
|
||||
ModelCount: 10,
|
||||
ModelPreview: "tc-code-latest, glm-5, glm-5.1",
|
||||
},
|
||||
report := sampleReportForV1()
|
||||
report.TencentSubscriptionPlans = []SubscriptionPlanInfo{
|
||||
{
|
||||
PlanName: "通用 Token Plan Lite",
|
||||
PlanFamily: "token_plan",
|
||||
Tier: "Lite",
|
||||
Currency: "CNY",
|
||||
ListPrice: 39,
|
||||
QuotaValue: 35000000,
|
||||
QuotaUnit: "tokens/month",
|
||||
ModelCount: 10,
|
||||
ModelPreview: "tc-code-latest, glm-5, glm-5.1",
|
||||
},
|
||||
}
|
||||
decorateReportV1(report)
|
||||
|
||||
if err := generateHTMLV3(report, path); err != nil {
|
||||
t.Fatalf("generateHTMLV3 returned error: %v", err)
|
||||
@@ -103,10 +311,15 @@ func TestGenerateHTMLV3IncludesTencentSubscriptionSection(t *testing.T) {
|
||||
|
||||
content := string(body)
|
||||
for _, want := range []string{
|
||||
"今日一句话结论",
|
||||
"三条行动建议",
|
||||
"今日头条",
|
||||
"场景推荐",
|
||||
"完整数据附录",
|
||||
"官方免费",
|
||||
"聚合免费",
|
||||
"待确认",
|
||||
"💳 腾讯云套餐订阅价",
|
||||
"通用 Token Plan Lite",
|
||||
"¥39.00/月",
|
||||
"3500万 Tokens/月",
|
||||
} {
|
||||
if !strings.Contains(content, want) {
|
||||
t.Fatalf("html missing %q\n%s", want, content)
|
||||
|
||||
Reference in New Issue
Block a user