models

package
v0.8.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 25, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Index

Constants

View Source
const (
	GlossaryCategoryCountry = "country"
	GlossaryCategoryCVE     = "cve"
)

GlossaryCategoryCountry and GlossaryCategoryCVE mark candidates that are deliberately excluded from the glossary (countries and CVE identifiers are not glossary-worthy named entities).

View Source
const GlossaryCategoryOther = "other"

GlossaryCategoryOther is the fallback category for unknown/empty values.

View Source
const GlossaryDifficultyDefault = "intermediate"

GlossaryDifficultyDefault is the fallback difficulty for unknown/empty values.

Variables

View Source
var KnownPromptTaskNames = map[string]bool{
	"categorize":         true,
	"tldr":               true,
	"plain_words":        true,
	"key_points":         true,
	"insights":           true,
	"referenced_reports": true,
	"summaries":          true,
	"glossary":           true,
	"rubric":             true,
	"importance":         true,
}

KnownPromptTaskNames is the set of analysis task names a profile may override via PromptOverrides.Tasks. "rubric" is the scoring task in default mode; "importance" is its legacy replacement, only run under vibe_score: true.

Functions

func GlossaryDifficultyTier added in v0.4.0

func GlossaryDifficultyTier(s string) int

GlossaryDifficultyTier maps a difficulty to the numeric tier used by the page's help-level filter: advanced=1 (shown first), intermediate=2, beginner=3 (shown only at the highest level). A term is shown when the selected help level >= its tier. Unknown/empty → 2.

func NormalizeGlossaryCategory added in v0.4.0

func NormalizeGlossaryCategory(s string) string

NormalizeGlossaryCategory lowercases/trims the value and returns it if it is in the fixed taxonomy, otherwise "other".

func NormalizeGlossaryDifficulty added in v0.4.0

func NormalizeGlossaryDifficulty(s string) string

NormalizeGlossaryDifficulty lowercases/trims the value and returns it if it is in the fixed taxonomy, otherwise the default ("intermediate").

func NormalizeGlossaryKey added in v0.4.0

func NormalizeGlossaryKey(term string) string

NormalizeGlossaryKey produces the dedup/lookup identity for a term.

Types

type AnalysisConfig

type AnalysisConfig struct {
	Provider     string            `json:"provider,omitempty"`      // Name of the configured provider to use for analysis
	Persona      string            `json:"persona,omitempty"`       // Additional prompt prefix to customize the AI instructions
	WritingStyle string            `json:"writing_style,omitempty"` // Writing style guide injected into digest summary prompt
	WorkerPool   *WorkerPoolConfig `json:"worker_pool,omitempty"`   // Configuration for the analysis worker pool
	AutoAnalyze  bool              `json:"auto_analyze,omitempty"`  // Automatically enqueue articles for analysis after each feed refresh
	VibeScore    bool              `json:"vibe_score,omitempty"`    // Use the legacy single-number LLM importance prompt instead of the rubric scoring system
	Glossary     bool              `json:"glossary,omitempty"`      // Generate glossary-mode content (plain-language explanation + jargon glossary) as an extra analysis task

	StandardSynthesis      bool `json:"standard_synthesis,omitempty"`      // Generate the Standard article summary (brief overview is always generated)
	ComprehensiveSynthesis bool `json:"comprehensive_synthesis,omitempty"` // Generate the Full (comprehensive) article summary

	ExecutiveSummary bool `json:"executive_summary,omitempty"` // Generate the digest-level executive summary (title + thematic overview)

	StepProviders map[string]StepProviderOverride `json:"step_providers,omitempty"` // Per-step provider/model overrides (step name -> override config)
}

AnalysisConfig represents the configuration for the analysis features

type AnthropicModelsResponse

type AnthropicModelsResponse struct {
	Data []struct {
		Type           string `json:"type"`
		Id             string `json:"id"`
		DisplayName    string `json:"display_name"`
		CreatedAt      string `json:"created_at"`
		MaxInputTokens int    `json:"max_input_tokens"`
		MaxTokens      int    `json:"max_tokens"`
	} `json:"data"`
	HasMore bool   `json:"has_more"`
	FirstId string `json:"first_id"`
	LastId  string `json:"last_id"`
}

AnthropicModelsResponse represents the response from Anthropic's models endpoint

type AnthropicRequest

type AnthropicRequest struct {
	Model       string    `json:"model"`
	Messages    []Message `json:"messages"`
	Temperature float64   `json:"temperature,omitempty"`
	MaxTokens   int       `json:"max_tokens,omitempty"`
}

AnthropicRequest represents a request to the Anthropic API

type AnthropicResponse

type AnthropicResponse struct {
	Id      string `json:"id"`
	Type    string `json:"type"`
	Model   string `json:"model"`
	Content []struct {
		Type string `json:"type"`
		Text string `json:"text"`
	} `json:"content"`
}

AnthropicResponse represents a response from the Anthropic API

type Article

type Article struct {
	Id              string           `gorm:"primaryKey" json:"id"`
	FeedId          string           `gorm:"index" json:"feed_id"`
	Title           string           `json:"title"`
	Content         string           `gorm:"type:text" json:"content"`
	Link            string           `json:"link"`
	PublishedAt     time.Time        `gorm:"index" json:"published_at"`
	FetchedAt       time.Time        `json:"fetched_at"`
	Read            *bool            `gorm:"default:false" json:"read"`
	Tags            []Tag            `gorm:"many2many:article_tags;" json:"tags"`
	CategoryName    *string          `gorm:"index" json:"category_name,omitempty"`
	Category        *Category        `gorm:"foreignKey:CategoryName;references:Name" json:"category,omitempty"`
	HeroImage       string           `json:"hero_image,omitempty"`
	Bookmarked      *bool            `gorm:"default:false" json:"bookmarked"`
	RelatedArticles []RelatedArticle `gorm:"-" json:"related_articles,omitempty"` // Handled separately
	// LatestImportanceScore is populated only by ListArticles (via JOIN on the latest analysis).
	// Not persisted on the Article row.
	LatestImportanceScore *int32 `gorm:"-" json:"latest_importance_score,omitempty"`
}

Article represents an article from a feed

func (*Article) BeforeCreate

func (a *Article) BeforeCreate(_ *gorm.DB) error

BeforeCreate ensures Id is set before creating a record

func (Article) TableName

func (Article) TableName() string

TableName specifies the table name for Article

type ArticleAnalysis

type ArticleAnalysis struct {
	Id                     string              `gorm:"primaryKey" json:"id"`
	ArticleId              string              `gorm:"index:idx_analysis_article_profile" json:"article_id"`
	ProfileId              string              `gorm:"index:idx_analysis_article_profile;index" json:"profile_id"`
	ProviderType           string              `json:"provider_type"`
	ModelName              string              `json:"model_name"`
	ImportanceScore        int                 `json:"importance_score"`
	ScoreDimensionsJson    string              `gorm:"column:score_dimensions;type:text" json:"-"`
	ScoreDimensions        *scoring.Dimensions `gorm:"-" json:"score_dimensions,omitempty"`
	KeyPointsJson          string              `gorm:"column:key_points;type:text" json:"-"`
	InsightsJson           string              `gorm:"column:insights;type:text" json:"-"`
	ReferencedReportsJson  string              `gorm:"column:referenced_reports;type:text" json:"-"`
	VendorsJson            string              `gorm:"column:vendors;type:text" json:"-"`
	TechnologiesJson       string              `gorm:"column:technologies;type:text" json:"-"`
	ProductsJson           string              `gorm:"column:products;type:text" json:"-"`
	KeyPoints              []string            `gorm:"-" json:"key_points"`
	Insights               []string            `gorm:"-" json:"insights"`
	Vendors                []string            `gorm:"-" json:"vendors"`
	Technologies           []string            `gorm:"-" json:"technologies"`
	Products               []string            `gorm:"-" json:"products"`
	ReferencedReports      []ReferencedReport  `gorm:"-" json:"referenced_reports"`
	Tldr                   string              `gorm:"type:text" json:"tldr"`
	PlainWords             string              `gorm:"type:text" json:"plain_words"`
	Justification          string              `gorm:"type:text" json:"justification"`
	BriefOverview          string              `gorm:"serializer:zstd;type:blob" json:"brief_overview"`
	StandardSynthesis      string              `gorm:"serializer:zstd;type:blob" json:"standard_synthesis"`
	ComprehensiveSynthesis string              `gorm:"serializer:zstd;type:blob" json:"comprehensive_synthesis"`
	GlossaryTermsJson      string              `gorm:"column:glossary_terms;type:text" json:"-"`
	GlossaryTerms          []GlossaryTerm      `gorm:"-" json:"glossary_terms"`
	ThinkingProcess        string              `gorm:"serializer:zstd;type:blob" json:"thinking_process,omitempty"`
	RawResponse            string              `gorm:"serializer:zstd;type:blob" json:"raw_response"`
	CreatedAt              time.Time           `gorm:"index" json:"created_at"`
	Article                *Article            `gorm:"foreignKey:ArticleId;references:Id" json:"-"`
}

ArticleAnalysis represents an analysis result from an LLM provider for an article

func (*ArticleAnalysis) AfterFind

func (a *ArticleAnalysis) AfterFind(tx *gorm.DB) error

AfterFind converts JSON strings back to slices after querying

func (*ArticleAnalysis) BeforeCreate

func (a *ArticleAnalysis) BeforeCreate(tx *gorm.DB) error

BeforeCreate ensures Id is set before creating a record

func (ArticleAnalysis) TableName

func (ArticleAnalysis) TableName() string

TableName specifies the table name for ArticleAnalysis

type ArticleCounts

type ArticleCounts struct {
	AllUnreadCount  int64            `json:"all_unread_count"`
	BookmarkedCount int64            `json:"bookmarked_count"`
	UnreadByFeed    map[string]int64 `json:"unread_by_feed"`
}

type ArticleFilter

type ArticleFilter struct {
	UnreadOnly     bool       `json:"unread_only"`
	CategoryName   string     `json:"category_name"`
	TagId          string     `json:"tag_id"`
	BookmarkedOnly bool       `json:"bookmarked_only"`
	RelatedToId    string     `json:"related_to_id"`
	StartDate      *time.Time `json:"start_date,omitempty"`
	EndDate        *time.Time `json:"end_date,omitempty"`
	FeedId         string     `json:"feed_id"`
	// ProfileId, when set, restricts results to the feeds in that profile's pool
	// and scopes LatestImportanceScore to that profile's analyses. Empty means no
	// profile restriction (latest analysis across all profiles), preserving the
	// historical single-tenant behavior.
	ProfileId       string `json:"profile_id,omitempty"`
	ExcludeDigested bool   `json:"exclude_digested,omitempty"`
	Offset          int    `json:"offset,omitempty"`
	Limit           int    `json:"limit,omitempty"`
	Query           string `json:"query,omitempty"`
	// Unbounded returns every matching row, bypassing the default page cap.
	// Used by digest generation, which needs the full window, not a UI page.
	Unbounded bool `json:"unbounded,omitempty"`
}

ArticleFilter represents filtering options for listing articles

type ArticleInspection added in v0.2.0

type ArticleInspection struct {
	ModeUsed        string `json:"mode_used"`
	RawHTMLLen      int    `json:"raw_html_len"`
	HTML            string `json:"html"`             // page HTML (capped) for selector inspection
	Extracted       string `json:"extracted"`        // extracted markdown when selectors supplied
	ExtractedLen    int    `json:"extracted_len"`    // rune count of Extracted
	SelectorMatched bool   `json:"selector_matched"` // the article selector matched an element
	Error           string `json:"error"`
	DurationMs      int64  `json:"duration_ms"`
}

ArticleInspection is the result of scraping a single article URL in a given mode, used by the feed-config builder to inspect page HTML and test selectors.

type ArticleUpdate

type ArticleUpdate struct {
	Read            *bool             `json:"read,omitempty"`
	TagIds          *[]string         `json:"tag_ids,omitempty"`
	CategoryName    *string           `json:"category_name,omitempty"`
	HeroImage       *string           `json:"hero_image,omitempty"`
	Bookmarked      *bool             `json:"bookmarked,omitempty"`
	RelatedArticles *[]RelatedArticle `json:"related_articles,omitempty"`
}

ArticleUpdate represents fields that can be updated for an article

type Category

type Category struct {
	Name     string    `gorm:"uniqueIndex,primaryKey" json:"name"`
	Color    string    `json:"color"`                                            // For UI display
	Icon     string    `json:"icon"`                                             // For UI display
	Articles []Article `gorm:"foreignKey:CategoryName;references:Name" json:"-"` // One-to-many relationship with articles
}

Category represents an article category

func (Category) TableName

func (Category) TableName() string

TableName specifies the table name for Category

type CategoryDef added in v0.4.0

type CategoryDef struct {
	Name        string `json:"name" yaml:"name"`
	Description string `json:"description,omitempty" yaml:"description,omitempty"`
}

CategoryDef is one allowed category for a profile, with a short description the LLM is shown when classifying.

type CodexCredential

type CodexCredential struct {
	Id               string     `json:"id"`       // short random ID
	Label            string     `json:"label"`    // email or fallback
	Priority         int        `json:"priority"` // lower = preferred
	AccessToken      string     `json:"access_token"`
	RefreshToken     string     `json:"refresh_token"`
	LastRefresh      time.Time  `json:"last_refresh"`
	AuthMode         string     `json:"auth_mode"`             // "chatgpt" | "claude"
	Source           string     `json:"source"`                // "manual:device_code" | "manual:pkce"
	ExpiresAt        *time.Time `json:"expires_at,omitempty"`  // OAuth absolute expiry (non-JWT tokens, e.g. claude-code)
	LastStatus       string     `json:"last_status,omitempty"` // "ok" | "auth_failed" | "rate_limited"
	LastStatusAt     *time.Time `json:"last_status_at,omitempty"`
	LastErrorReason  string     `json:"last_error_reason,omitempty"`
	LastErrorResetAt *time.Time `json:"last_error_reset_at,omitempty"` // when rate_limited expires
}

CodexCredential holds OAuth state for a single ChatGPT/Codex account.

type Digest

type Digest struct {
	Id                  string                 `gorm:"primaryKey" json:"id"`
	ProfileId           string                 `gorm:"index" json:"profile_id"`
	CreatedAt           time.Time              `gorm:"index" json:"created_at"`
	Title               string                 `gorm:"type:text" json:"title,omitempty"`
	ArticleCount        *int                   `gorm:"default:0" json:"article_count"`
	TimeWindow          time.Duration          `json:"time_window"`
	RawGroupingResponse string                 `gorm:"type:text" json:"raw_grouping_response,omitempty"`
	DigestSummary       string                 `gorm:"type:text" json:"digest_summary,omitempty"`
	ProviderResults     []DigestProviderResult `gorm:"-" json:"provider_results"`          // Handled through separate table
	DigestAnalyses      []DigestAnalysis       `gorm:"-" json:"digest_analyses,omitempty"` // Handled through separate table
	DigestGlossary      []DigestGlossary       `gorm:"-" json:"digest_glossary,omitempty"` // Handled through separate table
	Articles            []Article              `gorm:"many2many:digest_articles;" json:"-"`
	AnalysisErrors      map[string]string      `gorm:"-" json:"-"` // transient: articleId → classified error, not persisted
}

Digest represents a generated digest of articles

func (Digest) TableName

func (Digest) TableName() string

TableName specifies the table name for Digest

type DigestAnalysis

type DigestAnalysis struct {
	DigestId            string           `gorm:"primaryKey;index" json:"digest_id"`
	AnalysisId          string           `gorm:"primaryKey" json:"analysis_id"`
	ArticleId           string           `gorm:"index" json:"article_id"`
	DuplicateGroup      string           `json:"duplicate_group,omitempty"`
	IsMostComprehensive bool             `gorm:"default:false" json:"is_most_comprehensive"`
	Analysis            *ArticleAnalysis `gorm:"foreignKey:AnalysisId;references:Id" json:"analysis,omitempty"`
}

DigestAnalysis links an ArticleAnalysis to a Digest with duplicate-group metadata.

func (DigestAnalysis) TableName

func (DigestAnalysis) TableName() string

type DigestArticle

type DigestArticle struct {
	DigestId  string `json:"digest_id"`
	ArticleId string `json:"article_id"`
}

DigestArticle represents an article included in a digest

type DigestGlossary added in v0.4.0

type DigestGlossary struct {
	DigestId string         `gorm:"primaryKey;index" json:"digest_id"`
	EntryId  string         `gorm:"primaryKey" json:"entry_id"`
	Entry    *GlossaryEntry `gorm:"foreignKey:EntryId;references:Id" json:"entry,omitempty"`
}

DigestGlossary records which global glossary entries a digest references.

func (DigestGlossary) TableName added in v0.4.0

func (DigestGlossary) TableName() string

type DigestProviderResult

type DigestProviderResult struct {
	Id                     string    `gorm:"primaryKey" json:"id"`
	DigestId               string    `gorm:"index" json:"digest_id"`
	ProviderType           string    `json:"provider_type"`
	ModelName              string    `json:"model_name"`
	BriefOverview          string    `gorm:"type:text" json:"brief_overview"`
	StandardSynthesis      string    `gorm:"type:text" json:"standard_synthesis"`
	ComprehensiveSynthesis string    `gorm:"type:text" json:"comprehensive_synthesis"`
	ProcessingTime         float64   `json:"processing_time"`
	Error                  string    `json:"error"`
	CreatedAt              time.Time `gorm:"index" json:"created_at"`
	Digest                 *Digest   `gorm:"foreignKey:DigestId" json:"-"`
}

DigestProviderResult represents a provider's result for a digest

func (*DigestProviderResult) BeforeCreate

func (d *DigestProviderResult) BeforeCreate(tx *gorm.DB) error

BeforeCreate ensures Id is set before creating a record

func (DigestProviderResult) TableName

func (DigestProviderResult) TableName() string

TableName specifies the table name for DigestProviderResult

type DiscordNotificationConfig

type DiscordNotificationConfig struct {
	Enabled    bool   `json:"enabled"`
	WebhookURL string `json:"webhook_url"`
}

DiscordNotificationConfig holds Discord-specific notification settings

type Feed

type Feed struct {
	Id        string    `gorm:"primaryKey" json:"id"`
	URL       string    `gorm:"index" json:"url"`
	Type      string    `json:"type"`
	Title     string    `json:"title"`
	LastFetch time.Time `json:"last_fetch"`
	// Scraper   map[string]any `gorm:"-" json:"scraper,omitempty"` // In-memory representation
	Scraper  datatypes.JSONMap `json:"scraper,omitempty"` // In-memory representation
	Enabled  *bool             `gorm:"default:true" json:"enabled"`
	GroupId  *string           `gorm:"default:'default'" json:"group_id"`
	Articles []Article         `gorm:"foreignKey:FeedId" json:"-"` // One-to-many relationship with articles
	// Topics are the feed's labels (profiles select feeds by topic). Stored in the
	// feed_topics table, not on this row; populated by ListFeeds for read paths.
	Topics []string `gorm:"-" json:"topics,omitempty"`
}

Feed represents a feed with its metadata

func (*Feed) BeforeCreate

func (f *Feed) BeforeCreate(_ *gorm.DB) error

BeforeCreate ensures Id is set and properly converts Params before creating a record

func (Feed) TableName

func (Feed) TableName() string

TableName specifies the table name for Feed

type FeedConfig

type FeedConfig struct {
	URL     string        `json:"url" yaml:"url"`
	Title   string        `json:"title,omitempty" yaml:"title,omitempty"`
	Note    string        `json:"note,omitempty" yaml:"note,omitempty"`
	Enabled bool          `json:"enabled" yaml:"enabled"`
	Topics  []string      `json:"topics,omitempty" yaml:"topics,omitempty"` // labels profiles select feeds by
	Scraper ScraperConfig `json:"scraper" yaml:"scraper"`
}

FeedConfig represents the configuration for a feed. Everything scraping-related lives under the nested Scraper block; only identity fields stay at the top level.

func (FeedConfig) Validate added in v0.4.0

func (fc FeedConfig) Validate() error

Validate enforces the hard requirements every feed config must meet before it can be registered: a non-empty title, and — for the html scraper — a date_selector.

type FeedDiagnosis added in v0.2.0

type FeedDiagnosis struct {
	URL             string `json:"url"`
	FinalURL        string `json:"final_url"`         // after redirects
	HTTPStatus      int    `json:"http_status"`       // 0 when the request never completed
	ContentType     string `json:"content_type"`      // raw Content-Type header
	ContentLength   int    `json:"content_length"`    // bytes actually read
	FeedTypeGuess   string `json:"feed_type_guess"`   // rss | atom | json-feed | html | empty | unknown
	DeclaredCharset string `json:"declared_charset"`  // from XML prolog or Content-Type, when present
	ItemCount       int    `json:"item_count"`        // parsed items when the feed is valid
	ParseError      string `json:"parse_error"`       // gofeed parse error, empty when valid
	InvalidUTF8At   *int   `json:"invalid_utf8_at"`   // byte offset of first invalid UTF-8 byte, nil when valid
	Verdict         string `json:"verdict"`           // one-line human summary
	BodySnippet     string `json:"body_snippet"`      // first printable bytes of the body
	HexDump         string `json:"hex_dump"`          // bytes around InvalidUTF8At, when relevant
	RawBodyPath     string `json:"raw_body_path"`     // on-disk path to the saved raw body
	FetchDurationMs int64  `json:"fetch_duration_ms"` // wall time of the fetch

	// DiscoveredFeeds holds validated RSS/Atom/JSON feed URLs found on an HTML
	// page (via <link> autodiscovery, anchor keywords, or common-path probing).
	// Populated only when the fetched URL is itself an HTML page, so a caller can
	// redirect autoconfig at the real feed instead of the landing page.
	DiscoveredFeeds []string `json:"discovered_feeds,omitempty"`
}

FeedDiagnosis is the structured result of inspecting a single feed's raw HTTP response. It captures what actually came back over the wire so the two common failure modes — an unrecognizable body ("Failed to detect feed type") and raw non-UTF-8 bytes ("invalid utf-8 syntax") — can be diagnosed without re-running the server at trace log level.

type FeedGroup

type FeedGroup struct {
	Id        string `gorm:"primaryKey" json:"id"`
	Name      string `gorm:"uniqueIndex" json:"name"`
	Icon      string `json:"icon"`
	SortOrder *int   `gorm:"default:0" json:"sort_order"`
	Feeds     []Feed `gorm:"foreignKey:GroupId" json:"-"` // One-to-many relationship with feeds
}

FeedGroup represents a group of feeds

func (FeedGroup) TableName

func (FeedGroup) TableName() string

TableName specifies the table name for FeedGroup

type FeedItem

type FeedItem struct {
	Id          string
	Title       string
	Content     string
	Link        string
	PublishedAt time.Time
	Tags        []string
	Category    string
	HeroImage   string // New field for hero image URL
}

FeedItem represents a generic feed item returned by a scraper

type FeedRefreshResult added in v0.4.0

type FeedRefreshResult struct {
	Id           string    `gorm:"primaryKey" json:"id"`
	RunId        string    `gorm:"index" json:"run_id"`
	FeedId       string    `gorm:"index" json:"feed_id"`
	FeedTitle    string    `json:"feed_title"` // denormalized: the feed may be deleted later
	FeedURL      string    `json:"feed_url"`
	Success      bool      `json:"success"` // top-level fetch err == nil
	TotalFetched int       `json:"total_fetched"`
	Stored       int       `json:"stored"`
	Skipped      int       `json:"skipped"`
	ErrorCount   int       `json:"error_count"`   // number of item-level errors
	WarningCount int       `json:"warning_count"` // number of non-fatal notices (e.g. sanitized content)
	FetchError   string    `gorm:"column:fetch_error;type:text" json:"fetch_error,omitempty"`
	ErrorLog     []byte    `gorm:"type:blob" json:"-"` // gzip of joined item-level errors
	WarningLog   []byte    `gorm:"type:blob" json:"-"` // gzip of joined item-level warnings
	RawBody      []byte    `gorm:"type:blob" json:"-"` // gzip of the raw fetched feed body
	RawStatus    int       `json:"raw_status,omitempty"`
	RawType      string    `json:"raw_type,omitempty"` // raw response Content-Type
	DurationMs   int64     `json:"duration_ms"`
	CreatedAt    time.Time `gorm:"index" json:"created_at"`
}

FeedRefreshResult is the outcome of refreshing one feed during a run. Success reflects the top-level fetch (FetchError empty); item-level scrape/store failures are counted in ErrorCount and kept verbatim in ErrorLog. Non-fatal notices (e.g. content sanitized for invalid UTF-8, the article still stored) are counted in WarningCount and kept in WarningLog. Both logs are stored gzip-compressed (the store layer owns the codec).

func (FeedRefreshResult) TableName added in v0.4.0

func (FeedRefreshResult) TableName() string

type FeedRefreshRun added in v0.4.0

type FeedRefreshRun struct {
	Id         string     `gorm:"primaryKey" json:"id"`
	Trigger    string     `json:"trigger"` // "startup" | "manual-all" | "manual-single"
	StartedAt  time.Time  `gorm:"index" json:"started_at"`
	FinishedAt *time.Time `json:"finished_at,omitempty"`
}

FeedRefreshRun is one feed-refresh cycle: a single feed refresh, a refresh of all feeds, or the startup refresh. Each enabled feed processed during the cycle has a child FeedRefreshResult correlated by the run Id.

func (FeedRefreshRun) TableName added in v0.4.0

func (FeedRefreshRun) TableName() string

type FeedResult

type FeedResult struct {
	Feed        Feed
	Items       []FeedItem
	Error       error
	FetchResult FetchResult
}

FeedResult represents the result of fetching a feed

type FeedTopic added in v0.4.0

type FeedTopic struct {
	FeedId string `gorm:"primaryKey" json:"feed_id"`
	Topic  string `gorm:"primaryKey;index" json:"topic"`
}

FeedTopic is one (feed, topic) membership row. Topics are operator-assigned labels; a profile selects feeds by topic (see ProfileSelection). Distinct from the LLM-generated article entity tags (see Tag).

func (FeedTopic) TableName added in v0.4.0

func (FeedTopic) TableName() string

TableName specifies the table name for FeedTopic.

type FeedsFile

type FeedsFile struct {
	DefaultSelectors *Selectors   `yaml:"default_selectors,omitempty"`
	Feeds            []FeedConfig `yaml:"feeds"`
}

FeedsFile is the top-level structure of feeds.yml

type FetchResult

type FetchResult struct {
	TotalFetched     int
	Stored           int
	Skipped          int
	Errors           []string
	Warnings         []string // non-fatal notices (e.g. content sanitized); the article was still stored
	StoredArticleIDs []string // IDs of articles successfully stored in this fetch

	// Raw feed response captured for the refresh monitor, so the exact bytes a
	// refresh saw (or failed to parse) stay inspectable. RawBody is nil when
	// nothing was fetched (e.g. a network-level error before any response).
	RawBody        []byte
	RawStatus      int
	RawContentType string
}

FetchResult holds statistics from a single feed fetch operation

type GenericLLMRequest

type GenericLLMRequest struct {
	Model       string    `json:"model,omitempty"`       // Model name
	Messages    []Message `json:"messages,omitempty"`    // For chat-based APIs (OpenAI, Anthropic)
	Prompt      string    `json:"prompt,omitempty"`      // For completion-based APIs (Ollama)
	Temperature float64   `json:"temperature,omitempty"` // Optional
	MaxTokens   int       `json:"max_tokens,omitempty"`  // Optional
}

GenericLLMRequest represents a generic request to an LLM provider

type GitHubPagesNotificationConfig

type GitHubPagesNotificationConfig struct {
	Enabled           bool   `json:"enabled"`
	RepoURL           string `json:"repo_url"`            // e.g. https://github.com/user/user.github.io.git
	Branch            string `json:"branch"`              // default "main"
	ConfigurePages    bool   `json:"configure_pages"`     // configure GitHub Pages source to this branch
	Token             string `json:"token"`               // GitHub PAT; prefer env DOWNLINK_GH_PAGES_TOKEN
	OutputDir         string `json:"output_dir"`          // subdirectory inside repo (empty = repo root)
	Layout            string `json:"layout"`              // layout (template set) for published pages; empty = "default"
	BaseURL           string `json:"base_url"`            // public URL, e.g. https://user.github.io
	CommitAuthor      string `json:"commit_author"`       // default "downlink-bot"
	CommitEmail       string `json:"commit_email"`        // default "downlink-bot@users.noreply.github.com"
	CloneDir          string `json:"clone_dir"`           // local working clone; default: os.TempDir()/downlink-ghpages
	DiscordWebhookURL string `json:"discord_webhook_url"` // optional: notify this webhook when a page is published
	PublishWindowDays int    `json:"publish_window_days"` // days to retain in manifest/feeds; 0 = default (30)
	SelfContained     bool   `json:"self_contained"`      // inline CSS into every page instead of linking external .css files (default: external)
}

GitHubPagesNotificationConfig holds GitHub Pages publishing settings

type GlossaryEntry added in v0.4.0

type GlossaryEntry struct {
	Id                string       `gorm:"primaryKey" json:"id"`
	NormalizedKey     string       `gorm:"uniqueIndex" json:"normalized_key"`   // dedup identity
	Term              string       `json:"term"`                                // display form (first-seen)
	Kind              GlossaryKind `gorm:"index" json:"kind"`                   // provenance: jargon vs entity
	Category          string       `gorm:"index" json:"category"`               // semantic type (see NormalizeGlossaryCategory)
	Difficulty        string       `gorm:"index" json:"difficulty"`             // help tier (see NormalizeGlossaryDifficulty)
	Definition        string       `gorm:"type:text" json:"definition"`         // LLM-generated, current best
	CuratedDefinition string       `gorm:"type:text" json:"curated_definition"` // manual override text
	ManualOverride    bool         `gorm:"default:false;index" json:"manual_override"`
	TagId             string       `gorm:"index" json:"tag_id,omitempty"` // set when Kind==entity; == Tag.Id (slug)
	Source            string       `json:"source"`                        // provenance
	DefinitionModel   string       `json:"definition_model,omitempty"`    // provider/model that produced Definition
	CreatedAt         time.Time    `gorm:"index" json:"created_at"`
	UpdatedAt         time.Time    `json:"updated_at"`
}

GlossaryEntry is one deduplicated term in the persistent global glossary. Identity is the normalized key; definitions are reused across digests and never re-queried once present. A manual override, once set, wins forever and is never overwritten by regeneration.

func (*GlossaryEntry) BeforeCreate added in v0.4.0

func (e *GlossaryEntry) BeforeCreate(tx *gorm.DB) error

BeforeCreate ensures Id is set before creating a record

func (*GlossaryEntry) EffectiveDefinition added in v0.4.0

func (e *GlossaryEntry) EffectiveDefinition() string

EffectiveDefinition returns the curated override when present, else the generated one.

func (GlossaryEntry) TableName added in v0.4.0

func (GlossaryEntry) TableName() string

TableName specifies the table name for GlossaryEntry

type GlossaryKind added in v0.4.0

type GlossaryKind string

GlossaryKind distinguishes the two provenance sources of a glossary entry.

const (
	GlossaryKindJargon GlossaryKind = "jargon" // from ArticleAnalysis.GlossaryTerms
	GlossaryKindEntity GlossaryKind = "entity" // from a Tag (threat actor, malware, CVE, …)
)

type GlossaryTerm added in v0.3.0

type GlossaryTerm struct {
	Term       string   `json:"term"`
	Aliases    []string `json:"aliases,omitempty"`
	Type       string   `json:"type"`
	Definition string   `json:"definition"`
	Context    string   `json:"context"`
}

GlossaryTerm is a single jargon term and its plain-language definition, produced by the glossary-mode analysis task to help newcomers familiarize themselves with the terminology used in an article. Type is the semantic category (see the GlossaryCategory* constants); Context is a one-sentence explanation of why the term matters in this specific article (per-occurrence, not global). Aliases are other surface forms the article uses for the same thing (variant phrasings, abbreviations, expansions) so each resolves to the one definition when highlighted.

type HostTriggers

type HostTriggers = smodels.HostTriggers

type LLMCall added in v0.4.0

type LLMCall struct {
	Id               string    `gorm:"primaryKey" json:"id"`
	RunId            string    `gorm:"index" json:"run_id"`
	Label            string    `gorm:"index" json:"label"`
	ProviderType     string    `json:"provider_type"`
	ModelName        string    `json:"model_name"`
	Prompt           []byte    `gorm:"type:blob" json:"-"` // gzip-compressed UTF-8
	Response         []byte    `gorm:"type:blob" json:"-"` // gzip-compressed UTF-8
	PromptTokens     int       `json:"prompt_tokens"`
	CompletionTokens int       `json:"completion_tokens"`
	TotalTokens      int       `json:"total_tokens"`
	TokensKnown      bool      `json:"tokens_known"`
	DurationMs       int64     `json:"duration_ms"`
	Err              string    `gorm:"column:error;type:text" json:"error,omitempty"`
	CreatedAt        time.Time `gorm:"index" json:"created_at"`
}

LLMCall is one prompt/response that passed through the gateway during a run. Prompt and Response are stored gzip-compressed (the store layer owns the codec); token counts are zero with TokensKnown=false for backends that do not report usage (e.g. OAuth subscription providers).

func (LLMCall) TableName added in v0.4.0

func (LLMCall) TableName() string

type LLMRun added in v0.4.0

type LLMRun struct {
	Id         string     `gorm:"primaryKey" json:"id"`
	ProfileId  string     `gorm:"index" json:"profile_id,omitempty"`
	DigestId   string     `gorm:"index" json:"digest_id,omitempty"`
	Title      string     `json:"title,omitempty"`
	StartedAt  time.Time  `gorm:"index" json:"started_at"`
	FinishedAt *time.Time `json:"finished_at,omitempty"`
}

LLMRun is one digest-generation run. Every LLM call made while generating a digest is correlated to a run via its Id (propagated through the call context by the gateway). DigestId/Title are filled in once the digest is created.

func (LLMRun) TableName added in v0.4.0

func (LLMRun) TableName() string

type LinkListCandidate added in v0.4.0

type LinkListCandidate struct {
	LinksSelector string   `json:"links_selector"`
	Count         int      `json:"count"`                   // anchors the selector matched
	SampleHrefs   []string `json:"sample_hrefs"`            // a few resolved post URLs
	DateSelector  string   `json:"date_selector,omitempty"` // relative selector for the block's date
	DateSample    string   `json:"date_sample,omitempty"`   // raw text/attr of one matched date
	URLFilter     string   `json:"url_filter,omitempty"`    // shared path segment of the post URLs
}

LinkListCandidate is a ranked guess at the repeating post-link structure on an HTML index page: a links_selector scoping the post anchors, plus the relative date_selector and url_filter inferred from the repeating block. Mirrors scrapers.LinkListCandidate.

type LlamaCppModelsResponse

type LlamaCppModelsResponse struct {
	Object string `json:"object"`
	// OpenAI-compatible data array (preferred)
	Data []struct {
		Id      string `json:"id"`
		Object  string `json:"object"`
		Created int64  `json:"created"`
		OwnedBy string `json:"owned_by"`
	} `json:"data"`
	// llama.cpp native models array (fallback)
	Models []struct {
		Name  string `json:"name"`
		Model string `json:"model"`
	} `json:"models"`
}

LlamaCppModelsResponse handles the hybrid response format from llama.cpp /models endpoint, which includes both a custom "models" array and an OpenAI-compatible "data" array.

type Message

type Message struct {
	Role    string `json:"role"`    // "system", "user", "assistant"
	Content string `json:"content"` // Message content
}

Message represents a message in a chat-based LLM request

type ModelInfo

type ModelInfo struct {
	Id           string `json:"id"`
	Name         string `json:"name"`
	DisplayName  string `json:"display_name,omitempty"`
	Description  string `json:"description,omitempty"`
	ProviderType string `json:"provider_type"`
}

ModelInfo represents generic model information

type ModelsResponse

type ModelsResponse struct {
	Models []ModelInfo `json:"models"`
	Error  string      `json:"error,omitempty"`
}

ModelsResponse represents the response structure for GetAvailableModels

type NotificationsConfig

type NotificationsConfig struct {
	Discord     DiscordNotificationConfig     `json:"discord"`
	GitHubPages GitHubPagesNotificationConfig `json:"github_pages"`
}

NotificationsConfig holds notification platform configurations

type OllamaModelDetails

type OllamaModelDetails struct {
	ParentModel       string   `json:"parent_model"`
	Format            string   `json:"format"`
	Family            string   `json:"family"`
	Families          []string `json:"families"`
	ParameterSize     string   `json:"parameter_size"`
	QuantizationLevel string   `json:"quantization_level"`
}

OllamaModelDetails represents the details of an Ollama model

type OllamaModelsResponse

type OllamaModelsResponse struct {
	Models []struct {
		Name       string             `json:"name"`
		Model      string             `json:"model"`
		ModifiedAt string             `json:"modified_at"`
		Size       int64              `json:"size"`
		Digest     string             `json:"digest"`
		Details    OllamaModelDetails `json:"details"`
	} `json:"models"`
}

OllamaModelsResponse represents the response from Ollama's models endpoint

type OllamaRequest

type OllamaRequest struct {
	Model  string `json:"model"`
	Prompt string `json:"prompt"`
	Stream bool   `json:"stream"`
}

OllamaRequest represents the request to the Ollama API

type OllamaResponse

type OllamaResponse struct {
	Model     string `json:"model"`
	Response  string `json:"response"`
	CreatedAt string `json:"created_at"`
}

OllamaResponse represents the response from the Ollama API

type OpenAIModelsResponse

type OpenAIModelsResponse struct {
	Object string `json:"object"`
	Data   []struct {
		Id      string `json:"id"`
		Object  string `json:"object"`
		Created int64  `json:"created"`
		OwnedBy string `json:"owned_by"`
	} `json:"data"`
}

OpenAIModelsResponse represents the response from OpenAI's models endpoint

type OpenAIRequest

type OpenAIRequest struct {
	Model       string    `json:"model"`
	Messages    []Message `json:"messages"`
	Temperature float64   `json:"temperature,omitempty"`
	MaxTokens   int       `json:"max_tokens,omitempty"`
}

OpenAIRequest represents a request to the OpenAI API

type OpenAIResponse

type OpenAIResponse struct {
	Id      string `json:"id"`
	Object  string `json:"object"`
	Created int64  `json:"created"`
	Model   string `json:"model"`
	Choices []struct {
		Index        int     `json:"index"`
		Message      Message `json:"message"`
		FinishReason string  `json:"finish_reason"`
	} `json:"choices"`
}

OpenAIResponse represents a response from the OpenAI API

type Profile added in v0.4.0

type Profile struct {
	Id           string `gorm:"primaryKey" json:"id"` // slug, e.g. "infosec"
	Name         string `gorm:"uniqueIndex" json:"name"`
	Description  string `json:"description,omitempty"`
	Icon         string `json:"icon,omitempty"`
	Layout       string `json:"layout,omitempty"` // digestlayouts template set; empty = "default"
	Theme        string `json:"theme,omitempty"`  // digestthemes palette; empty = template default
	Enabled      *bool  `gorm:"default:true" json:"enabled"`
	SortOrder    *int   `gorm:"default:0" json:"sort_order"`
	OutputSubdir string `json:"output_subdir,omitempty"` // GitHub Pages subdir; empty = slug

	// Editorial is hydrated from EditorialJson on read and serialized back on
	// save (same JSON-column pattern as ArticleAnalysis). A nil field inside it
	// means "inherit the global/default behavior".
	EditorialJson string            `gorm:"column:editorial;type:text" json:"-"`
	Editorial     *ProfileEditorial `gorm:"-" json:"editorial,omitempty"`

	// Selection is the feed-membership rule (topics + explicit overrides),
	// persisted so feed-catalog changes can re-resolve profile_feeds without
	// re-reading profiles.yml. The resolved membership lives in profile_feeds.
	SelectionJson string            `gorm:"column:selection;type:text" json:"-"`
	Selection     *ProfileSelection `gorm:"-" json:"selection,omitempty"`

	Feeds []Feed `gorm:"many2many:profile_feeds;" json:"-"`
}

Profile is one curated, public view of the shared article pool. A profile selects a subset of feeds (many-to-many via profile_feeds, so pools may overlap between profiles), carries its own editorial config (how its articles are analyzed), and picks its own presentation (layout template set + default theme palette). Articles and feeds stay global; analyses and digests are scoped to a profile via their ProfileId.

func (*Profile) AfterFind added in v0.4.0

func (p *Profile) AfterFind(_ *gorm.DB) error

AfterFind hydrates Editorial and Selection from their JSON columns after a query.

func (*Profile) BeforeSave added in v0.4.0

func (p *Profile) BeforeSave(_ *gorm.DB) error

BeforeSave serializes Editorial and Selection into their JSON columns before persisting.

func (Profile) TableName added in v0.4.0

func (Profile) TableName() string

TableName specifies the table name for Profile.

type ProfileConfig added in v0.4.0

type ProfileConfig struct {
	Slug         string            `yaml:"slug"`
	Name         string            `yaml:"name"`
	Description  string            `yaml:"description,omitempty"`
	Icon         string            `yaml:"icon,omitempty"`
	Layout       string            `yaml:"layout,omitempty"`
	Theme        string            `yaml:"theme,omitempty"`
	Enabled      *bool             `yaml:"enabled,omitempty"`
	SortOrder    *int              `yaml:"sort_order,omitempty"`
	OutputSubdir string            `yaml:"output_subdir,omitempty"`
	Topics       []string          `yaml:"topics,omitempty"`        // feeds with ANY of these topics
	Feeds        []string          `yaml:"feeds,omitempty"`         // explicit include feed URLs
	ExcludeFeeds []string          `yaml:"exclude_feeds,omitempty"` // explicit exclude feed URLs
	Editorial    *ProfileEditorial `yaml:"editorial,omitempty"`
}

ProfileConfig is one profile definition in profiles.yml. Feeds are referenced by URL and resolved to feed ids at apply time.

type ProfileEditorial added in v0.4.0

type ProfileEditorial struct {
	Provider     string `json:"provider,omitempty" yaml:"provider,omitempty"`           // configured provider name
	Model        string `json:"model,omitempty" yaml:"model,omitempty"`                 // optional model override
	Persona      string `json:"persona,omitempty" yaml:"persona,omitempty"`             // analysis system-message prefix
	WritingStyle string `json:"writing_style,omitempty" yaml:"writing_style,omitempty"` // digest-summary style guide
	Audience     string `json:"audience,omitempty" yaml:"audience,omitempty"`           // target reader, injected into prompts

	Glossary               *bool `json:"glossary,omitempty" yaml:"glossary,omitempty"`
	VibeScore              *bool `json:"vibe_score,omitempty" yaml:"vibe_score,omitempty"` // legacy single-number scoring instead of the rubric
	StandardSynthesis      *bool `json:"standard_synthesis,omitempty" yaml:"standard_synthesis,omitempty"`
	ComprehensiveSynthesis *bool `json:"comprehensive_synthesis,omitempty" yaml:"comprehensive_synthesis,omitempty"`
	ExecutiveSummary       *bool `json:"executive_summary,omitempty" yaml:"executive_summary,omitempty"`

	Categories []CategoryDef    `json:"categories,omitempty" yaml:"categories,omitempty"` // nil/empty = default category set
	Rubric     *RubricConfig    `json:"rubric,omitempty" yaml:"rubric,omitempty"`         // nil = default weights/thresholds
	Prompts    *PromptOverrides `json:"prompts,omitempty" yaml:"prompts,omitempty"`       // nil = built-in task instructions
}

ProfileEditorial is a profile's editorial brain. Every field is optional; an empty/nil value inherits from the global AnalysisConfig + package defaults (resolved in services.ResolveEditorial). It mirrors AnalysisConfig and adds per-profile taxonomy, rubric, and raw prompt overrides.

type ProfileSelection added in v0.4.0

type ProfileSelection struct {
	Topics         []string `json:"topics,omitempty"`
	IncludeFeedIds []string `json:"include_feed_ids,omitempty"`
	ExcludeFeedIds []string `json:"exclude_feed_ids,omitempty"`
}

ProfileSelection is how a profile chooses its feeds. Membership is the feeds whose topics intersect Topics, plus IncludeFeedIds, minus ExcludeFeedIds, restricted to enabled feeds. An empty selection (no topics, no includes) means "all enabled feeds". Include/exclude are stored as feed ids (resolved at apply time) so re-resolution does not need the original URLs.

type ProfilesFile added in v0.4.0

type ProfilesFile struct {
	Profiles []ProfileConfig `yaml:"profiles"`
}

ProfilesFile is the YAML catalog of profiles (profiles.yml), mirroring FeedsFile. It is applied to the database at server startup: each entry is upserted and its feed pool (referenced by URL) is reconciled.

type PromptOverrides added in v0.4.0

type PromptOverrides struct {
	Tasks         map[string]string `json:"tasks,omitempty" yaml:"tasks,omitempty"`
	DigestSummary string            `json:"digest_summary,omitempty" yaml:"digest_summary,omitempty"`
	Dedupe        string            `json:"dedupe,omitempty" yaml:"dedupe,omitempty"`
}

PromptOverrides lets a profile replace task instructions verbatim. Tasks is keyed by analysis task name (see KnownPromptTaskNames; the scoring task is "rubric" in default mode, "importance" only under vibe_score: true). Output schema and required keys are NOT overridable, so validation still applies.

type ProviderConfig

type ProviderConfig struct {
	Name           string            `json:"name"` // User-defined name for this provider configuration (required)
	ProviderType   string            `json:"provider_type"`
	ModelName      string            `json:"model_name"`
	Enabled        bool              `json:"enabled"`
	BaseURL        string            `json:"base_url,omitempty"`        // Used for Ollama and other local providers
	MaxRetries     *int              `json:"max_retries,omitempty"`     // Using pointer type for zero values (GORM best practice)
	TimeoutMinutes *int              `json:"timeout_minutes,omitempty"` // Using pointer type for zero values (GORM best practice)
	APIKey         string            `json:"api_key,omitempty"`         // Per-provider API key; overrides the global key when set
	Credentials    []CodexCredential `json:"credentials,omitempty"`     // openai-codex OAuth credential pool
}

ProviderConfig represents configuration for a specific LLM provider used for digest generation

type ReferencedReport

type ReferencedReport struct {
	Title     string `json:"title"`
	URL       string `json:"url"`
	Publisher string `json:"publisher"`
	Context   string `json:"context"`
	Category  string `json:"category"`
	Primary   bool   `json:"primary"`
}

ReferencedReport is an explicit third-party report, research item, advisory, whitepaper, or technical analysis linked from an article.

type RelatedArticle

type RelatedArticle struct {
	ArticleId        string  `gorm:"primaryKey;column:article_id" json:"article_id"`
	RelatedArticleId string  `gorm:"primaryKey;column:related_article_id" json:"related_article_id"`
	RelationType     string  `gorm:"column:relation_type" json:"relation_type"` // e.g., "similar", "continuation", "response"
	SimilarityScore  float64 `gorm:"column:similarity_score" json:"similarity_score"`
}

RelatedArticle represents a relationship between two articles

func (RelatedArticle) TableName

func (RelatedArticle) TableName() string

TableName specifies the table name for RelatedArticle

type RubricConfig added in v0.4.0

type RubricConfig struct {
	Weights         map[string]float64 `json:"weights,omitempty" yaml:"weights,omitempty"`
	Tiers           *TierThresholds    `json:"tiers,omitempty" yaml:"tiers,omitempty"`
	AggregatorScore *int               `json:"aggregator_score,omitempty" yaml:"aggregator_score,omitempty"`
	EvergreenCap    *int               `json:"evergreen_cap,omitempty" yaml:"evergreen_cap,omitempty"`
	PromoCap        *int               `json:"promo_cap,omitempty" yaml:"promo_cap,omitempty"`
}

RubricConfig overrides the importance model for a profile. Weights keys are the six rubric dimensions (specificity, severity, breadth, novelty, actionability, credibility); nil sub-fields fall back to scoring.DefaultConfig().

type ScraperConfig added in v0.4.0

type ScraperConfig struct {
	Type      string            `json:"type" yaml:"type"`
	Scraping  string            `json:"scraping,omitempty" yaml:"scraping,omitempty"` // "dynamic", "full_browser", "none" (use feed content, no fetch), or "" (static)
	Selectors *Selectors        `json:"selectors,omitempty" yaml:"selectors,omitempty"`
	Headers   map[string]string `json:"headers,omitempty" yaml:"headers,omitempty"` // custom HTTP headers applied to all requests for this feed
	Triggers  *HostTriggers     `json:"triggers,omitempty" yaml:"triggers,omitempty"`
	Options   map[string]any    `json:"-" yaml:",inline"` // type-specific flat keys (links_selector, url_filter, ...)
}

ScraperConfig holds all scraping configuration for a feed: the scraper type, render mode, content selectors, custom headers, full_browser triggers, and any type-specific options. Type-specific keys (e.g. the html scraper's links_selector / url_filter) are captured by the inline Options map so adding a new scraper type needs no struct change here.

type SelectorCandidate added in v0.2.0

type SelectorCandidate struct {
	Selector    string  `json:"selector"`
	Chars       int     `json:"chars"`
	LinkDensity float64 `json:"link_density"`
	Snippet     string  `json:"snippet"`
}

SelectorCandidate is a ranked guess at the CSS selector wrapping an article body, produced by inspecting a scraped page. Mirrors scrapers.SelectorCandidate.

type Selectors

type Selectors struct {
	Article   string `json:"article,omitempty" yaml:"article,omitempty"`     // Selector to find the article content
	Cutoff    string `json:"cutoff,omitempty" yaml:"cutoff,omitempty"`       // Selector to mark where to cutoff the article
	Blacklist string `json:"blacklist,omitempty" yaml:"blacklist,omitempty"` // Elements to exclude from the article
}

Selectors defines CSS selectors for content extraction

func GetEffectiveSelectors

func GetEffectiveSelectors(feed *Feed, configDefaults *Selectors) *Selectors

GetEffectiveSelectors returns the effective selectors to use for a feed It prioritizes feed-specific selectors, then falls back to config defaults, then to system defaults

type ServerConfig

type ServerConfig struct {
	Feeds            []FeedConfig        `json:"feeds"`
	DbPath           string              `json:"db_path"`
	Providers        []ProviderConfig    `json:"providers"`
	Analysis         AnalysisConfig      `json:"analysis"`
	Notifications    NotificationsConfig `json:"notifications"`
	DefaultSelectors *Selectors          `json:"-" yaml:"-"` // Loaded from feeds.yml, not config.json
	SolimenAddr      string              `json:"solimen_addr"`
}

ServerConfig represents application configuration

type StepProviderOverride added in v0.4.0

type StepProviderOverride struct {
	Provider string `json:"provider,omitempty"` // Name of configured provider to use for this step
	Model    string `json:"model,omitempty"`    // Model name override for this step (uses provider's model if empty)
}

StepProviderOverride specifies a provider and/or model override for a single pipeline step

type Tag

type Tag struct {
	Id       string    `gorm:"primaryKey" json:"id"`
	Name     string    `gorm:"uniqueIndex" json:"name"`
	Color    string    `json:"color"`
	Articles []Article `gorm:"many2many:article_tags;" json:"-"` // Many-to-many relationship with articles
}

Tag represents an article tag

func (Tag) TableName

func (Tag) TableName() string

TableName specifies the table name for Tag

type TierThresholds added in v0.4.0

type TierThresholds struct {
	Must   int `json:"must" yaml:"must"`
	Should int `json:"should" yaml:"should"`
	May    int `json:"may" yaml:"may"`
}

TierThresholds are the inclusive lower bounds for the read tiers on a 0-100 score.

type WorkerPoolConfig

type WorkerPoolConfig struct {
	MaxWorkers *int `json:"max_workers,omitempty"` // Maximum number of concurrent workers (default: 3)
}

WorkerPoolConfig contains the configuration for the worker pool

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL