-
Notifications
You must be signed in to change notification settings - Fork 0
feat: Add Sentiment-Based Summaries to PostGroup and Store in Redis #13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
6f026b8
1f7b516
092e9b5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,6 +1,6 @@ | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
import cron from 'node-cron'; | ||||||||||||||||||||||||||||||||||||||
import { generateTitleForPost } from './generateTitle'; | ||||||||||||||||||||||||||||||||||||||
import { generateTitleForPost, generateSentimentSummariesForGroup, type SentimentSummaries } from './generateTitle'; | ||||||||||||||||||||||||||||||||||||||
import { initRedis, getRedisClient } from './redisClient'; | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
export type Post = { | ||||||||||||||||||||||||||||||||||||||
|
@@ -19,6 +19,9 @@ export type PostGroup = { | |||||||||||||||||||||||||||||||||||||
id: string; | ||||||||||||||||||||||||||||||||||||||
posts: Post[]; | ||||||||||||||||||||||||||||||||||||||
title?: string; | ||||||||||||||||||||||||||||||||||||||
bullishSummary?: string; | ||||||||||||||||||||||||||||||||||||||
bearishSummary?: string; | ||||||||||||||||||||||||||||||||||||||
neutralSummary?: string; | ||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
// Generate a title for a PostGroup by aggregating its posts' content | ||||||||||||||||||||||||||||||||||||||
|
@@ -27,6 +30,11 @@ export async function generateTitleForPostGroup(postGroup: PostGroup): Promise<s | |||||||||||||||||||||||||||||||||||||
return await generateTitleForPost(combinedContent); | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
// Generate sentiment summaries for a PostGroup based on its posts | ||||||||||||||||||||||||||||||||||||||
export async function generateSentimentSummariesForPostGroup(postGroup: PostGroup): Promise<SentimentSummaries> { | ||||||||||||||||||||||||||||||||||||||
return await generateSentimentSummariesForGroup(postGroup.posts); | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
// Fetch all PostGroups from Redis (expects a key 'PostGroup' with a JSON array, or adapt as needed) | ||||||||||||||||||||||||||||||||||||||
export async function fetchPostGroupsFromRedis(): Promise<PostGroup[]> { | ||||||||||||||||||||||||||||||||||||||
|
@@ -45,50 +53,51 @@ export async function fetchPostGroupsFromRedis(): Promise<PostGroup[]> { | |||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
// Reusable function to generate and log the title for all PostGroups from Redis | ||||||||||||||||||||||||||||||||||||||
// Reusable function to generate and log the title and sentiment summaries for all PostGroups from Redis | ||||||||||||||||||||||||||||||||||||||
export async function logTitlesForAllPostGroups(context: 'CRON' | 'MANUAL' = 'MANUAL') { | ||||||||||||||||||||||||||||||||||||||
const postGroups = await fetchPostGroupsFromRedis(); | ||||||||||||||||||||||||||||||||||||||
if (!postGroups.length) { | ||||||||||||||||||||||||||||||||||||||
console.log('No PostGroups found in Redis.'); | ||||||||||||||||||||||||||||||||||||||
return; | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
let updated = false; | ||||||||||||||||||||||||||||||||||||||
const postGroupsWithOrderedKeys = []; | ||||||||||||||||||||||||||||||||||||||
for (const group of postGroups) { | ||||||||||||||||||||||||||||||||||||||
let title = group.title; | ||||||||||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||||||||||
title = await generateTitleForPostGroup(group); | ||||||||||||||||||||||||||||||||||||||
if (group.title !== title) { | ||||||||||||||||||||||||||||||||||||||
updated = true; | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
// Always generate and update title | ||||||||||||||||||||||||||||||||||||||
const title = await generateTitleForPostGroup(group); | ||||||||||||||||||||||||||||||||||||||
// Always generate and update sentiment summaries | ||||||||||||||||||||||||||||||||||||||
const summaries = await generateSentimentSummariesForPostGroup(group); | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
if (context === 'CRON') { | ||||||||||||||||||||||||||||||||||||||
console.log(`[CRON] Generated Title for PostGroup (id: ${group.id}) at ${new Date().toISOString()}:`, title); | ||||||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||||||
console.log(`Title for PostGroup (id: ${group.id}):`, title); | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
postGroupsWithOrderedKeys.push({ | ||||||||||||||||||||||||||||||||||||||
id: group.id, | ||||||||||||||||||||||||||||||||||||||
title, | ||||||||||||||||||||||||||||||||||||||
bullishSummary: summaries.bullishSummary, | ||||||||||||||||||||||||||||||||||||||
bearishSummary: summaries.bearishSummary, | ||||||||||||||||||||||||||||||||||||||
neutralSummary: summaries.neutralSummary, | ||||||||||||||||||||||||||||||||||||||
posts: group.posts | ||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||
Comment on lines
+77
to
+84
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Preserve all existing group fields when saving. Current push constructs a new object and may drop unmodeled fields. Merge into the original to avoid data loss. - postGroupsWithOrderedKeys.push({
- id: group.id,
- title,
- bullishSummary: summaries.bullishSummary,
- bearishSummary: summaries.bearishSummary,
- neutralSummary: summaries.neutralSummary,
- posts: group.posts
- });
+ const updatedGroup: PostGroup = {
+ ...group,
+ title,
+ ...summaries
+ };
+ postGroupsWithOrderedKeys.push(updatedGroup); 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
|
||||||||||||||||||||||||||||||||||||||
} catch (e) { | ||||||||||||||||||||||||||||||||||||||
if (context === 'CRON') { | ||||||||||||||||||||||||||||||||||||||
console.error(`[CRON] Error generating title for PostGroup (id: ${group.id}):`, e); | ||||||||||||||||||||||||||||||||||||||
console.error(`[CRON] Error generating title/summaries for PostGroup (id: ${group.id}):`, e); | ||||||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||||||
console.error(`Error generating title for PostGroup (id: ${group.id}):`, e); | ||||||||||||||||||||||||||||||||||||||
console.error(`Error generating title/summaries for PostGroup (id: ${group.id}):`, e); | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
Comment on lines
85
to
91
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do not drop groups on generation failure. On error, the group is omitted from the saved array, effectively deleting it from Redis. } catch (e) {
if (context === 'CRON') {
console.error(`[CRON] Error generating title/summaries for PostGroup (id: ${group.id}):`, e);
} else {
console.error(`Error generating title/summaries for PostGroup (id: ${group.id}):`, e);
}
+ // Preserve existing group to avoid data loss
+ postGroupsWithOrderedKeys.push(group);
} 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
|
||||||||||||||||||||||||||||||||||||||
postGroupsWithOrderedKeys.push({ | ||||||||||||||||||||||||||||||||||||||
id: group.id, | ||||||||||||||||||||||||||||||||||||||
title, | ||||||||||||||||||||||||||||||||||||||
posts: group.posts | ||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
// Save updated PostGroups with titles back to Redis | ||||||||||||||||||||||||||||||||||||||
if (updated) { | ||||||||||||||||||||||||||||||||||||||
await initRedis(); | ||||||||||||||||||||||||||||||||||||||
const redis = getRedisClient(); | ||||||||||||||||||||||||||||||||||||||
await redis.set('post-groups', JSON.stringify(postGroupsWithOrderedKeys)); | ||||||||||||||||||||||||||||||||||||||
if (context === 'CRON') { | ||||||||||||||||||||||||||||||||||||||
console.log('[CRON] Updated post-groups with titles saved to Redis.'); | ||||||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||||||
console.log('Updated post-groups with titles saved to Redis.'); | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
// Always save updated PostGroups with titles and summaries back to Redis | ||||||||||||||||||||||||||||||||||||||
await initRedis(); | ||||||||||||||||||||||||||||||||||||||
const redis = getRedisClient(); | ||||||||||||||||||||||||||||||||||||||
await redis.set('post-groups', JSON.stringify(postGroupsWithOrderedKeys)); | ||||||||||||||||||||||||||||||||||||||
if (context === 'CRON') { | ||||||||||||||||||||||||||||||||||||||
console.log('[CRON] Updated post-groups with titles and sentiment summaries saved to Redis.'); | ||||||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||||||
console.log('Updated post-groups with titles and sentiment summaries saved to Redis.'); | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Send only the minimum data needed to the LLM.
Reduce payload to content + sentiment to lower cost/PII exposure.
📝 Committable suggestion
🤖 Prompt for AI Agents