Skip to content

Commit

Permalink
Merge pull request #89 from autonomys/feat/kol-top-tweet
Browse files Browse the repository at this point in the history
Feat/kol top tweet
  • Loading branch information
jfrank-summit authored Jan 1, 2025
2 parents c0ae497 + c0e424c commit e2d0ae1
Show file tree
Hide file tree
Showing 16 changed files with 449 additions and 1,705 deletions.
17 changes: 11 additions & 6 deletions auto-kol/agent/.env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ TWITTER_USERNAME=your_twitter_username
TWITTER_PASSWORD=your_twitter_password

# LLM Configuration
LLM_MODEL=gpt-4o-mini
SMALL_LLM_MODEL=gpt-4o-mini
LARGE_LLM_MODEL=gpt-4o
OPENAI_API_KEY=your_openai_api_key

CHECK_INTERVAL_MINUTES=15
Expand All @@ -20,7 +21,6 @@ CHROMA_URL=http://localhost:8000
# AutoDrive Configuration
DSN_API_KEY=your_dsn_api_key
DSN_UPLOAD=true
DSN_SKIP_UPLOAD=false
DSN_ENCRYPTION_PASSWORD=

# CORS Configuration
Expand All @@ -32,10 +32,12 @@ CONTRACT_ADDRESS=0xc5d3caed3e3600ff42b9f423d4cf281e92d7f008
PRIVATE_KEY=<Private Key>
WALLET_ADDRESS=your_wallet_address


ACCOUNTS_PER_BATCH=<Number>
MAX_SEARCH_TWEETS=<Number>

# Tweet search configuration
ACCOUNTS_PER_BATCH=5
MAX_SEARCH_TWEETS=20
MAX_TIMELINE_TWEETS=60
MAX_MENTIONS=5
MAX_THREAD_LENGTH=20
# BATCH CONFIG
ENGAGEMENT_BATCH_SIZE=15

Expand All @@ -44,3 +46,6 @@ RETRY_LIMIT=2

# POSTING TWEETS PERMISSION
POST_TWEETS=true

# TOP LEVEL TWEET CONFIG
TOP_LEVEL_TWEET_INTERVAL_HOURS=24
10 changes: 10 additions & 0 deletions auto-kol/agent/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"semi": true,
"trailingComma": "all",
"singleQuote": true,
"quoteProps": "as-needed",
"jsxSingleQuote": true,
"printWidth": 100,
"tabWidth": 2,
"arrowParens": "avoid"
}
8 changes: 0 additions & 8 deletions auto-kol/agent/.prettierrc.js

This file was deleted.

9 changes: 8 additions & 1 deletion auto-kol/agent/src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ export const config = {
TWITTER_PASSWORD: process.env.TWITTER_PASSWORD,

// LLM Configuration
LLM_MODEL: process.env.LLM_MODEL || 'gpt-4o-mini',
LARGE_LLM_MODEL: process.env.LARGE_LLM_MODEL || 'gpt-4o',
SMALL_LLM_MODEL: process.env.SMALL_LLM_MODEL || 'gpt-4o-mini',
OPENAI_API_KEY: process.env.OPENAI_API_KEY,
TEMPERATURE: 0.7,

Expand Down Expand Up @@ -51,6 +52,9 @@ export const config = {
// Tweet Search/Fetch Configuration
ACCOUNTS_PER_BATCH: Number(process.env.ACCOUNTS_PER_BATCH) || 10,
MAX_SEARCH_TWEETS: Number(process.env.MAX_SEARCH_TWEETS) || 20,
MAX_MENTIONS: Number(process.env.MAX_MENTIONS) || 5,
MAX_THREAD_LENGTH: Number(process.env.MAX_THREAD_LENGTH) || 20,

// BATCH CONFIG
ENGAGEMENT_BATCH_SIZE: process.env.ENGAGEMENT_BATCH_SIZE || 15,

Expand All @@ -59,4 +63,7 @@ export const config = {

// POSTING TWEETS PERMISSION
POST_TWEETS: process.env.POST_TWEETS === 'true',

// TOP LEVEL TWEET CONFIG
TOP_LEVEL_TWEET_INTERVAL_MINUTES: Number(process.env.TOP_LEVEL_TWEET_INTERVAL_MINUTES) || 120,
};
97 changes: 96 additions & 1 deletion auto-kol/agent/src/database/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ export async function initializeSchema() {
'tweets',
'responses',
'skipped_tweets',
'dsn'
'dsn',
'trends',
'top_level_tweets'
)
`);

Expand Down Expand Up @@ -473,3 +475,96 @@ export async function getLatestMentionId(): Promise<string> {
const mention = await db?.get(`SELECT latest_id FROM mentions ORDER BY updated_at DESC LIMIT 1`);
return mention?.latest_id || '';
}

///////////TREND///////////
export async function addTrend(trend: { id: string; content: string }) {
const db = await initializeDatabase();
try {
await db.run(
`
INSERT INTO trends (id, content)
VALUES (?, ?)
`,
[trend.id, trend.content],
);

logger.info(`Added trend: ${trend.id}`);
} catch (error) {
logger.error('Failed to add trend:', error);
throw error;
}
}

export async function getAllTrends() {
const db = await initializeDatabase();
try {
const trends = await db.all(`
SELECT id, content, created_at
FROM trends
ORDER BY created_at DESC
`);

return trends.map(trend => ({
id: trend.id,
content: trend.content,
created_at: new Date(trend.created_at + 'Z'),
}));
} catch (error) {
logger.error('Failed to get trends:', error);
throw error;
}
}

export async function wipeTrendsTable() {
const db = await initializeDatabase();
try {
await db.run('DELETE FROM trends');
logger.info('Wiped trends table');
} catch (error) {
logger.error('Failed to wipe trends table:', error);
throw error;
}
}

///////////TOP LEVEL TWEETS///////////
export async function addTopLevelTweet(tweet: { id: string; content: string }) {
const db = await initializeDatabase();
try {
await db.run(
`
INSERT INTO top_level_tweets (id, content)
VALUES (?, ?)
`,
[tweet.id, tweet.content],
);

logger.info(`Added top level tweet: ${tweet.id}`);
} catch (error) {
logger.error('Failed to add top level tweet:', error);
throw error;
}
}

export async function getLatestTopLevelTweets(limit: number = 10) {
const db = await initializeDatabase();
try {
const tweets = await db.all(
`
SELECT id, content, created_at
FROM top_level_tweets
ORDER BY created_at DESC
LIMIT ?
`,
[limit],
);

return tweets.map(tweet => ({
id: tweet.id,
content: tweet.content,
created_at: new Date(tweet.created_at + 'Z'),
}));
} catch (error) {
logger.error('Failed to get latest top level tweets:', error);
throw error;
}
}
12 changes: 12 additions & 0 deletions auto-kol/agent/src/database/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,18 @@ CREATE TABLE IF NOT EXISTS mentions (
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE IF NOT EXISTS trends (
id TEXT PRIMARY KEY,
content TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE IF NOT EXISTS top_level_tweets (
id TEXT PRIMARY KEY,
content TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_kol_accounts_username ON kol_accounts(username);
CREATE INDEX idx_tweets_created_at ON tweets(created_at);
CREATE INDEX idx_responses_status ON responses(status);
Expand Down
16 changes: 16 additions & 0 deletions auto-kol/agent/src/schemas/workflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,19 @@ export const autoApprovalSchema = z.object({
confidence: z.number().min(0).max(1),
suggestedChanges: z.string().optional(),
});

export const trendSchema = z.object({
trends: z.array(
z.object({
topic: z.string(),
description: z.string(),
confidence: z.number().min(0).max(1),
}),
),
summary: z.string(),
});

export const trendTweetSchema = z.object({
tweet: z.string().max(280),
reasoning: z.string(),
});
6 changes: 3 additions & 3 deletions auto-kol/agent/src/services/agents/nodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { createSearchNode } from './nodes/searchNode.js';
import { createEngagementNode } from './nodes/engagementNode.js';
import { createToneAnalysisNode } from './nodes/toneAnalysisNode.js';
import { createResponseGenerationNode } from './nodes/responseGenerationNode.js';
import { createRecheckSkippedNode } from './nodes/recheckSkippedNode.js';
import { createTopLevelTweetNode } from './nodes/topLevelTweetNode.js';
import { createTimelineNode } from './nodes/timelineNode.js';
import { createMentionNode } from './nodes/mentionNode.js';
import { createAutoApprovalNode } from './nodes/autoApprovalNode.js';
Expand All @@ -28,7 +28,7 @@ export const createNodes = async (config: WorkflowConfig) => {
const responseGenerationNode = createResponseGenerationNode(config);

///////////RECHECK SKIPPED///////////
const recheckSkippedNode = createRecheckSkippedNode(config);
const topLevelTweetNode = createTopLevelTweetNode(config);

///////////AUTO APPROVAL///////////
const autoApprovalNode = createAutoApprovalNode(config);
Expand All @@ -40,7 +40,7 @@ export const createNodes = async (config: WorkflowConfig) => {
engagementNode,
toneAnalysisNode,
responseGenerationNode,
recheckSkippedNode,
topLevelTweetNode,
autoApprovalNode,
};
};
5 changes: 4 additions & 1 deletion auto-kol/agent/src/services/agents/nodes/engagementNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ import { config as globalConfig } from '../../../config/index.js';
import { ResponseStatus } from '../../../types/queue.js';

const handleSkippedTweet = async (tweet: any, decision: any, config: any) => {
logger.info('Skipping engagement for tweet', { tweetId: tweet.id, reason: decision.reason });
logger.info('Skipping engagement for tweet', {
tweetId: tweet.id,
reason: decision.reason,
});
await config.toolNode.invoke({
messages: [
new AIMessage({
Expand Down
17 changes: 17 additions & 0 deletions auto-kol/agent/src/services/agents/nodes/timelineNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import { logger } from '../workflow.js';
import { State } from '../workflow.js';
import { tweetSearchSchema } from '../../../schemas/workflow.js';
import * as db from '../../database/index.js';
import { addTrend } from '../../../database/index.js';
import { trendParser, trendPrompt } from '../prompts.js';
import { v4 as generateID } from 'uuid';

export const createTimelineNode = (config: WorkflowConfig) => {
return async (state: typeof State.State) => {
Expand Down Expand Up @@ -39,6 +42,20 @@ export const createTimelineNode = (config: WorkflowConfig) => {

const parsedTweets = tweetSearchSchema.parse(parsedContent);

const trendAnalysis = await trendPrompt
.pipe(config.llms.decision)
.pipe(trendParser)
.invoke({
tweets: parsedTweets.tweets.map(t => t.text).join('\n\n'),
});

logger.info('Trend analysis:', trendAnalysis);

await addTrend({
id: generateID(),
content: trendAnalysis.summary,
});

const newTweets = [...existingTweets];
for (const tweet of parsedTweets.tweets) {
if (await db.isTweetExists(tweet.id)) {
Expand Down
Loading

0 comments on commit e2d0ae1

Please sign in to comment.