feat(report): add official release event source

This commit is contained in:
phamnazage-jpg
2026-05-13 21:36:18 +08:00
parent b4e28d5be4
commit b9ca312366
2 changed files with 184 additions and 9 deletions

View File

@@ -769,6 +769,12 @@ func loadModelEvents(db *sql.DB, date string) ([]ModelEvent, error) {
}
events = append(events, newModelEvents...)
releaseEvents, err := loadOfficialReleaseEvents(db, date)
if err != nil {
return nil, err
}
events = append(events, releaseEvents...)
priceEvents, err := loadPriceChangeEvents(db, date)
if err != nil {
return nil, err
@@ -785,6 +791,98 @@ func loadModelEvents(db *sql.DB, date string) ([]ModelEvent, error) {
return dedupeModelEvents(events), nil
}
func loadOfficialReleaseEvents(db *sql.DB, date string) ([]ModelEvent, error) {
rows, err := db.Query(`
WITH latest_prices AS (
SELECT
rp.model_id,
COALESCE(o.name, 'Unknown') AS operator_name,
COALESCE(o.type, 'reseller') AS operator_type,
rp.currency,
ROW_NUMBER() OVER (
PARTITION BY rp.model_id
ORDER BY rp.effective_date DESC NULLS LAST, rp.id DESC
) AS rn
FROM region_pricing rp
LEFT JOIN operator o ON rp.operator_id = o.id
)
SELECT
COALESCE(NULLIF(m.name, ''), m.external_id) AS model_name,
COALESCE(mp.name, split_part(m.external_id, '/', 1)) AS provider_name,
COALESCE(lp.operator_name, 'Unknown') AS operator_name,
COALESCE(lp.operator_type, 'reseller') AS operator_type,
COALESCE(m.source_url, '') AS source_url,
COALESCE(mp.country, 'unknown') AS provider_country,
COALESCE(m.release_date, m.created_at::date) AS release_date,
COALESCE(lp.currency, 'USD') AS currency
FROM models m
LEFT JOIN model_provider mp ON m.provider_id = mp.id
LEFT JOIN latest_prices lp ON lp.model_id = m.id AND lp.rn = 1
WHERE m.deleted_at IS NULL
AND m.release_date = $1::date
AND COALESCE(m.source_url, '') <> ''
AND COALESCE(lp.operator_type, 'reseller') IN ('official', 'cloud')
ORDER BY m.release_date DESC, m.id DESC
LIMIT 8
`, date)
if err != nil {
return nil, err
}
defer rows.Close()
var events []ModelEvent
for rows.Next() {
var (
modelName string
providerName string
operatorName string
operatorType string
sourceURL string
providerCountry string
releaseDate time.Time
currency string
)
if err := rows.Scan(
&modelName,
&providerName,
&operatorName,
&operatorType,
&sourceURL,
&providerCountry,
&releaseDate,
&currency,
); err != nil {
return nil, err
}
model := ModelInfo{
Name: modelName,
ProviderName: providerName,
ProviderCountry: providerCountry,
Currency: currency,
OperatorName: operatorName,
OperatorType: operatorType,
}
events = append(events, ModelEvent{
EventType: "official_release",
ModelName: modelName,
ProviderName: providerName,
OperatorName: operatorName,
TrustLabel: buildTrustLabel(model),
SourceKindLabel: "官方发布",
PrimarySource: sourceURL,
UpdatedAt: releaseDate.Format("2006-01-02 15:04"),
EvidenceDetail: "models.release_date = 今日,且 source_url 指向官方发布页",
Baseline: "官方首次发布",
Summary: fmt.Sprintf("%s 官方发布新模型,值得优先复查默认选型。", providerName),
Currency: currency,
Priority: 120,
})
}
return events, rows.Err()
}
func loadNewModelEvents(db *sql.DB, date string) ([]ModelEvent, error) {
rows, err := db.Query(`
WITH latest_prices AS (
@@ -1079,11 +1177,11 @@ func decorateReportV1(r *ReportV3) {
}
}
r.PageMode = buildPageMode(r.DailySignals)
r.ModelEvents = enrichModelEvents(r)
r.PageMode = buildPageModeWithEvents(r.DailySignals, r.ModelEvents)
r.MarketLabels = buildMarketLabels(r)
r.HeroSummary, r.HeroEvidence = buildHeroSummary(r)
r.SceneSections = buildSceneSections(r)
r.ModelEvents = enrichModelEvents(r)
r.ActionItems = buildActionItems(r)
r.HeadlineItems = buildHeadlineItems(r)
r.AppendixLinks = []AppendixLink{
@@ -1193,6 +1291,13 @@ func isVerifiedAggregator(name string) bool {
}
func buildPageMode(signals DailySignals) string {
return buildPageModeWithEvents(signals, nil)
}
func buildPageModeWithEvents(signals DailySignals, events []ModelEvent) string {
if hasEventType(events, "official_release") {
return "hot"
}
if signals.NewModels == 0 && signals.PriceChanges == 0 {
return "calm"
}
@@ -1204,7 +1309,7 @@ func buildPageMode(signals DailySignals) string {
func buildMarketLabels(r *ReportV3) []string {
labels := []string{}
switch r.PageMode {
switch buildPageModeWithEvents(r.DailySignals, r.ModelEvents) {
case "hot":
labels = append(labels, "热点日")
case "calm":
@@ -1212,6 +1317,9 @@ func buildMarketLabels(r *ReportV3) []string {
default:
labels = append(labels, "常规日")
}
if hasEventType(r.ModelEvents, "official_release") {
labels = append(labels, "官方发布")
}
if r.DailySignals.NewModels > 0 {
labels = append(labels, "新模型日")
}
@@ -1229,7 +1337,20 @@ func buildMarketLabels(r *ReportV3) []string {
return labels
}
func hasEventType(events []ModelEvent, eventType string) bool {
for _, event := range events {
if event.EventType == eventType {
return true
}
}
return false
}
func buildHeroSummary(r *ReportV3) (string, string) {
if official := firstEventByType(r.ModelEvents, "official_release"); official != nil {
return fmt.Sprintf("今天最值得关注的是 %s 已出现官方发布信号,优先复查它对默认选型的影响。", official.ModelName),
fmt.Sprintf("主来源:%s", official.PrimarySource)
}
switch r.PageMode {
case "hot":
return fmt.Sprintf(
@@ -1248,6 +1369,15 @@ func buildHeroSummary(r *ReportV3) (string, string) {
}
}
func firstEventByType(events []ModelEvent, eventType string) *ModelEvent {
for i := range events {
if events[i].EventType == eventType {
return &events[i]
}
}
return nil
}
func buildHeadlineItems(r *ReportV3) []HeadlineItem {
if items := buildHeadlineItemsFromEvents(r.ModelEvents); len(items) > 0 {
return items
@@ -1345,6 +1475,10 @@ func headlineItemFromModelEvent(event ModelEvent) HeadlineItem {
}
switch event.EventType {
case "official_release":
item.Label = "官方发布"
item.Title = fmt.Sprintf("%s 官方发布", event.ModelName)
item.Tone = "info"
case "new_model":
item.Label = "新模型"
item.Title = fmt.Sprintf("%s 进入今日情报池", event.ModelName)