feat(llm): improve summary and grouping, and increase timeout #44
No files matched your search
@@ -23,7 +23,7 @@ const (
|
||||
)
|
||||
|
||||
const (
|
||||
LLMTimeout = 2 * time.Minute
|
||||
LLMTimeout = 5 * time.Minute
|
||||
DayGroupLayout = "2006-01-02"
|
||||
DayGroupTitleLayout = "Jan 2, 2006"
|
||||
)
|
||||
@@ -171,7 +171,9 @@ type llmEntry struct {
|
||||
FeedTitle string `json:"feed_title"`
|
||||
}
|
||||
|
||||
const llmPrompt = `You are an expert news editor with a talent for identifying the most important and interesting information from a large volume of content. Your primary goal is to save the user time by providing a high-level, insightful overview of their news feeds.
|
||||
const llmPrompt = `You are an expert content curator with a talent for identifying the most important and interesting information from a large volume of content. Your primary goal is to save the user time by providing a high-level, insightful overview of their content feeds.
|
||||
|
||||
The content can come from a variety of sources, including news sites, blogs, forums like Reddit, and social media like Bluesky. Your tone should be that of a helpful assistant, not a news editor.
|
||||
|
||||
Given the following list of entries, your task is to perform two distinct functions:
|
||||
|
||||
@@ -185,6 +187,7 @@ Given the following list of entries, your task is to perform two distinct functi
|
||||
* The number of groups should be driven by the content itself. **Do not create a group for a single entry unless it represents a major, unique event.** The ideal number of groups is one that best helps a user skim the content. A group can contain many entries if they are all highly related.
|
||||
* Group titles should be short, descriptive, and useful for skimming (e.g., "AI Industry News," "Project Updates," "Global Politics").
|
||||
* Within each group, you must rank the 'entries' by importance, with the most significant or actionable item appearing first.
|
||||
* The goal of grouping is to help with reading, so if a few entries are about some similar topic, those are worth grouping because the user can just read one and skim the rest.
|
||||
|
||||
Return the response as a JSON object according to the desired responseSchema.
|
||||
|
||||
@@ -304,5 +307,12 @@ func (g *LLMGrouper) GroupEntries(entries *miniflux.Entries) ([]*models.EntryGro
|
||||
}
|
||||
}
|
||||
|
||||
return entryGroups, response.Summary
|
||||
feedIDs := make(map[int64]bool)
|
||||
for _, entry := range *entries {
|
||||
feedIDs[entry.FeedID] = true
|
||||
}
|
||||
|
||||
statsSummary := fmt.Sprintf("You have %d entries from %d feeds.", len(*entries), len(feedIDs))
|
||||
|
||||
return entryGroups, fmt.Sprintf("%s\n\n%s", response.Summary, statsSummary)
|
||||
}
|
||||
@@ -34,29 +34,33 @@ func (m *mockLLMService) GenerateContent(ctx context.Context, prompt string, sch
|
||||
func createDayGrouperMockEntries() *miniflux.Entries {
|
||||
return &miniflux.Entries{
|
||||
{
|
||||
ID: 1,
|
||||
Title: "Entry 1 - Jan 2",
|
||||
Date: time.Date(2024, time.January, 2, 10, 0, 0, 0, time.UTC),
|
||||
Feed: &miniflux.Feed{ID: 100, Title: "Feed A"},
|
||||
ID: 1,
|
||||
Title: "Entry 1 - Jan 2",
|
||||
Date: time.Date(2024, time.January, 2, 10, 0, 0, 0, time.UTC),
|
||||
FeedID: 100,
|
||||
Feed: &miniflux.Feed{ID: 100, Title: "Feed A"},
|
||||
},
|
||||
{
|
||||
ID: 2,
|
||||
Title: "Entry 2 - Jan 1",
|
||||
Date: time.Date(2024, time.January, 1, 10, 0, 0, 0, time.UTC),
|
||||
Feed: &miniflux.Feed{ID: 200, Title: "Feed B"},
|
||||
ID: 2,
|
||||
Title: "Entry 2 - Jan 1",
|
||||
Date: time.Date(2024, time.January, 1, 10, 0, 0, 0, time.UTC),
|
||||
FeedID: 200,
|
||||
Feed: &miniflux.Feed{ID: 200, Title: "Feed B"},
|
||||
},
|
||||
{
|
||||
ID: 3,
|
||||
Title: "Entry 3 - Jan 2",
|
||||
Date: time.Date(2024, time.January, 2, 11, 0, 0, 0, time.UTC),
|
||||
Feed: &miniflux.Feed{ID: 100, Title: "Feed A"},
|
||||
ID: 3,
|
||||
Title: "Entry 3 - Jan 2",
|
||||
Date: time.Date(2024, time.January, 2, 11, 0, 0, 0, time.UTC),
|
||||
FeedID: 100,
|
||||
Feed: &miniflux.Feed{ID: 100, Title: "Feed A"},
|
||||
},
|
||||
{
|
||||
ID: 4,
|
||||
Title: "Entry 4 - Jan 1",
|
||||
ID: 4,
|
||||
Title: "Entry 4 - Jan 1",
|
||||
Content: "Content of entry 4 about Go concurrency.",
|
||||
Date: time.Date(2024, time.January, 1, 12, 0, 0, 0, time.UTC),
|
||||
Feed: &miniflux.Feed{ID: 200, Title: "Feed B"},
|
||||
Date: time.Date(2024, time.January, 1, 12, 0, 0, 0, time.UTC),
|
||||
FeedID: 200,
|
||||
Feed: &miniflux.Feed{ID: 200, Title: "Feed B"},
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -199,8 +203,9 @@ func TestLLMGrouper_GroupEntries(t *testing.T) {
|
||||
grouper := &LLMGrouper{LLMService: mockLLM}
|
||||
groups, summary := grouper.GroupEntries(entries)
|
||||
|
||||
if summary != "This is a summary of all entries." {
|
||||
t.Errorf("Expected summary \"This is a summary of all entries.\", got \"%s\"", summary)
|
||||
expectedSummary := "This is a summary of all entries.\n\nYou have 4 entries from 2 feeds."
|
||||
if summary != expectedSummary {
|
||||
t.Errorf("Expected summary \"%s\", got \"%s\"", expectedSummary, summary)
|
||||
}
|
||||
|
||||
if len(groups) != 2 {
|
||||
@@ -287,8 +292,9 @@ func TestLLMGrouper_GroupEntries_WithDuplicateEntries(t *testing.T) {
|
||||
grouper := &LLMGrouper{LLMService: mockLLM}
|
||||
groups, summary := grouper.GroupEntries(entries)
|
||||
|
||||
if summary != "This is a summary of all entries." {
|
||||
t.Errorf("Expected summary \"This is a summary of all entries.\", got \"%s\"", summary)
|
||||
expectedSummary := "This is a summary of all entries.\n\nYou have 4 entries from 2 feeds."
|
||||
if summary != expectedSummary {
|
||||
t.Errorf("Expected summary \"%s\", got \"%s\"", expectedSummary, summary)
|
||||
}
|
||||
|
||||
if len(groups) != 2 {
|
||||
|
||||
Reference in new issue
Block a user