types.go RawHistoryFolder
1// Package parser provides URL parsing and fuzzy finding functionality for dumber.
2package parser
3
4import (
5 "time"
6
7 "github.com/bnema/dumber/internal/config"
8 "github.com/bnema/dumber/internal/db"
9)
10
11// InputType represents the type of user input detected.
12type InputType int
13
14const (
15 // InputTypeDirectURL represents a direct URL input (e.g., "reddit.com", "https://example.com")
16 InputTypeDirectURL InputType = iota
17 // InputTypeSearchShortcut represents a search shortcut (e.g., "g: golang tutorial")
18 InputTypeSearchShortcut
19 // InputTypeHistorySearch represents a history search query
20 InputTypeHistorySearch
21 // InputTypeFallbackSearch represents a fallback web search
22 InputTypeFallbackSearch
23)
24
25// ParseResult represents the result of parsing user input.
26type ParseResult struct {
27 // Type indicates the detected input type
28 Type InputType `json:"type"`
29 // URL is the final URL to navigate to
30 URL string `json:"url"`
31 // Query is the original user query
32 Query string `json:"query"`
33 // Confidence is the confidence score of the parsing (0.0-1.0)
34 Confidence float64 `json:"confidence"`
35 // FuzzyMatches contains fuzzy search results if applicable
36 FuzzyMatches []FuzzyMatch `json:"fuzzy_matches,omitempty"`
37 // Shortcut contains the detected shortcut information
38 Shortcut *DetectedShortcut `json:"shortcut,omitempty"`
39 // ProcessingTime is the time taken to process the input
40 ProcessingTime time.Duration `json:"processing_time"`
41}
42
43// DetectedShortcut represents a detected search shortcut.
44type DetectedShortcut struct {
45 // Key is the shortcut key (e.g., "g", "gh")
46 Key string `json:"key"`
47 // Query is the search query part
48 Query string `json:"query"`
49 // URL is the constructed URL
50 URL string `json:"url"`
51 // Description is the shortcut description
52 Description string `json:"description"`
53}
54
55// FuzzyMatch represents a fuzzy search match from history.
56type FuzzyMatch struct {
57 // HistoryEntry is the matched history entry
58 HistoryEntry *db.History `json:"history_entry"`
59 // Score is the similarity score (0.0-1.0, higher is better)
60 Score float64 `json:"score"`
61 // URLScore is the URL similarity score
62 URLScore float64 `json:"url_score"`
63 // TitleScore is the title similarity score
64 TitleScore float64 `json:"title_score"`
65 // RecencyScore is the recency score based on last visit
66 RecencyScore float64 `json:"recency_score"`
67 // VisitScore is the score based on visit count
68 VisitScore float64 `json:"visit_score"`
69 // MatchedField indicates which field matched (url, title, or both)
70 MatchedField string `json:"matched_field"`
71}
72
73// HistoryProvider defines the interface for history data access.
74type HistoryProvider interface {
75 // GetRecentHistory returns recent history entries limited by count
76 GetRecentHistory(limit int) ([]*db.History, error)
77 // GetAllHistory returns all history entries for fuzzy search
78 GetAllHistory() ([]*db.History, error)
79 // SearchHistory performs a basic text search in history
80 SearchHistory(query string, limit int) ([]*db.History, error)
81 // GetHistoryByURL retrieves history entry by exact URL match
82 GetHistoryByURL(url string) (*db.History, error)
83}
84
85// FuzzyConfig holds configuration for fuzzy matching algorithms.
86type FuzzyConfig struct {
87 // MinSimilarityThreshold is the minimum similarity score to consider a match (0.0-1.0)
88 MinSimilarityThreshold float64 `json:"min_similarity_threshold"`
89 // MaxResults is the maximum number of fuzzy results to return
90 MaxResults int `json:"max_results"`
91 // URLWeight is the weight for URL similarity in scoring
92 URLWeight float64 `json:"url_weight"`
93 // TitleWeight is the weight for title similarity in scoring
94 TitleWeight float64 `json:"title_weight"`
95 // RecencyWeight is the weight for recency in scoring
96 RecencyWeight float64 `json:"recency_weight"`
97 // VisitWeight is the weight for visit count in scoring
98 VisitWeight float64 `json:"visit_weight"`
99 // RecencyDecayDays is the number of days for recency score decay
100 RecencyDecayDays int `json:"recency_decay_days"`
101}
102
103// Parser handles URL parsing and fuzzy finding operations.
104type Parser struct {
105 config *config.Config
106 fuzzyConfig *FuzzyConfig
107 historyProvider HistoryProvider
108}
109
110// ParserOption is a functional option for configuring the Parser.
111type ParserOption func(*Parser)
112
113// NewParser creates a new Parser instance with the given configuration.
114func NewParser(cfg *config.Config, historyProvider HistoryProvider, opts ...ParserOption) *Parser {
115 p := &Parser{
116 config: cfg,
117 historyProvider: historyProvider,
118 fuzzyConfig: DefaultFuzzyConfig(),
119 }
120
121 for _, opt := range opts {
122 opt(p)
123 }
124
125 return p
126}
127
128// WithFuzzyConfig sets custom fuzzy matching configuration.
129func WithFuzzyConfig(fuzzyConfig *FuzzyConfig) ParserOption {
130 return func(p *Parser) {
131 p.fuzzyConfig = fuzzyConfig
132 }
133}
134
135// DefaultFuzzyConfig returns default fuzzy matching configuration.
136func DefaultFuzzyConfig() *FuzzyConfig {
137 return &FuzzyConfig{
138 MinSimilarityThreshold: 0.3,
139 MaxResults: 10,
140 URLWeight: 0.4,
141 TitleWeight: 0.3,
142 RecencyWeight: 0.2,
143 VisitWeight: 0.1,
144 RecencyDecayDays: 30,
145 }
146}
147
148// String returns a string representation of InputType.
149func (t InputType) String() string {
150 switch t {
151 case InputTypeDirectURL:
152 return "direct_url"
153 case InputTypeSearchShortcut:
154 return "search_shortcut"
155 case InputTypeHistorySearch:
156 return "history_search"
157 case InputTypeFallbackSearch:
158 return "fallback_search"
159 default:
160 return "unknown"
161 }
162}
163
164// IsValid returns true if the FuzzyConfig has valid values.
165func (fc *FuzzyConfig) IsValid() bool {
166 return fc.MinSimilarityThreshold >= 0.0 && fc.MinSimilarityThreshold <= 1.0 &&
167 fc.MaxResults > 0 &&
168 fc.URLWeight >= 0.0 && fc.TitleWeight >= 0.0 &&
169 fc.RecencyWeight >= 0.0 && fc.VisitWeight >= 0.0 &&
170 fc.RecencyDecayDays > 0
171}