Initial commit
This commit is contained in:
110
internal/classifier/prompts.go
Normal file
110
internal/classifier/prompts.go
Normal file
@@ -0,0 +1,110 @@
|
||||
package classifier
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"pete/internal/ingestion"
|
||||
"pete/internal/storage"
|
||||
)
|
||||
|
||||
// BuildTier1Prompt builds the routing-only prompt for Tier 1 stories.
|
||||
func BuildTier1Prompt(item *ingestion.FeedItem, recent []storage.RecentHeadline) string {
|
||||
return fmt.Sprintf(`You are a news router for a community discussion platform with three channels: tech, politics, and gaming.
|
||||
|
||||
This story comes from a curated Tier 1 source. It will be posted. Your only job is to decide which channel it belongs in.
|
||||
|
||||
Choose exactly one channel:
|
||||
- tech: technology products, software, hardware, industry — where technology itself is the primary subject
|
||||
- gaming: games, gaming platforms, gaming industry, esports
|
||||
- politics: everything else — political, policy, current events, public interest, significant world events
|
||||
|
||||
Politics is the default. When in doubt, choose politics.
|
||||
|
||||
Routing guidance:
|
||||
- GPU launch, software release, hardware review → tech
|
||||
- Game release, platform announcement, studio news → gaming
|
||||
- Election, legislation, court ruling → politics
|
||||
- AI regulation, antitrust action, surveillance policy → politics (policy is the story, not the technology)
|
||||
- Death of a public figure → politics
|
||||
- Violent crime, assassination attempt, arrest of public figure → politics
|
||||
- Natural disaster, humanitarian crisis → politics
|
||||
- Celebrity gossip, lifestyle with no broader significance → politics (still gets posted, still needs a home)
|
||||
|
||||
For gaming stories only: identify which platforms are relevant from this list:
|
||||
nintendo-switch, playstation, xbox, pc, retro, mobile, multi
|
||||
Return an empty array if no specific platform applies.
|
||||
|
||||
Also check: does this story cover the same underlying event as any story in the recent window? Different outlets covering the same event counts as a duplicate. If yes, set duplicate_of to that story's GUID. If no match, set duplicate_of to null.
|
||||
|
||||
Respond ONLY with valid JSON. No preamble, no explanation outside the JSON:
|
||||
{
|
||||
"channel": "tech|politics|gaming",
|
||||
"platforms": [string],
|
||||
"duplicate_of": string | null,
|
||||
"rationale": "one sentence max, for logging only"
|
||||
}
|
||||
|
||||
INCOMING STORY:
|
||||
Source: %s
|
||||
Tier: %d
|
||||
Feed hint: %s
|
||||
Headline: %s
|
||||
Lede: %s
|
||||
|
||||
RECENT STORIES (last 24hr):
|
||||
%s`, item.Source, item.Tier, item.FeedHint, item.Headline, item.Lede, formatRecentStories(recent))
|
||||
}
|
||||
|
||||
// BuildTier2Prompt builds the gating + routing prompt for Tier 2 stories.
|
||||
func BuildTier2Prompt(item *ingestion.FeedItem, recent []storage.RecentHeadline) string {
|
||||
return fmt.Sprintf(`You are a news classifier for a community discussion platform with three channels: tech, politics, and gaming.
|
||||
|
||||
This story comes from a wire service. Unlike curated sources, wire feeds publish everything — not all stories warrant posting. First decide if this story is worth posting, then decide where.
|
||||
|
||||
Step 1 — Should this be posted?
|
||||
Post if the story has clear public significance: major world events, policy decisions, significant deaths, natural disasters, major technology developments. Do not post: local news with no broader relevance, routine financial filings, minor sports results, entertainment fluff.
|
||||
|
||||
Step 2 — If posting, choose exactly one channel:
|
||||
- tech: technology products, software, hardware, industry
|
||||
- gaming: games, gaming platforms, gaming industry
|
||||
- politics: everything else — the default
|
||||
|
||||
Politics is the default when in doubt.
|
||||
|
||||
For gaming stories only: identify relevant platforms from: nintendo-switch, playstation, xbox, pc, retro, mobile, multi
|
||||
|
||||
Also check for duplicates against the recent window. If this story covers the same underlying event as a recent story, set duplicate_of to that story's GUID.
|
||||
|
||||
Respond ONLY with valid JSON:
|
||||
{
|
||||
"post": true|false,
|
||||
"channel": "tech|politics|gaming",
|
||||
"platforms": [string],
|
||||
"duplicate_of": string | null,
|
||||
"rationale": "one sentence max, for logging only"
|
||||
}
|
||||
|
||||
If post is false, channel may be omitted.
|
||||
|
||||
INCOMING STORY:
|
||||
Source: %s
|
||||
Tier: %d
|
||||
Feed hint: %s
|
||||
Headline: %s
|
||||
Lede: %s
|
||||
|
||||
RECENT STORIES (last 24hr):
|
||||
%s`, item.Source, item.Tier, item.FeedHint, item.Headline, item.Lede, formatRecentStories(recent))
|
||||
}
|
||||
|
||||
func formatRecentStories(recent []storage.RecentHeadline) string {
|
||||
if len(recent) == 0 {
|
||||
return "(none)"
|
||||
}
|
||||
var sb strings.Builder
|
||||
for _, h := range recent {
|
||||
fmt.Fprintf(&sb, "[%s] %s — %s\n", h.GUID, h.Headline, h.Source)
|
||||
}
|
||||
return sb.String()
|
||||
}
|
||||
Reference in New Issue
Block a user