Skip to content

Commit

Permalink
fix: tweets (#90)
Browse files Browse the repository at this point in the history
  • Loading branch information
glucrypto authored Dec 29, 2024
1 parent 33f2a0b commit ad064e6
Show file tree
Hide file tree
Showing 3 changed files with 185 additions and 3 deletions.
7 changes: 6 additions & 1 deletion src/agent/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ const instance = await ai.initialize({
posts: [
{
type: "image",
schedule: "0 */2 * * *", // Every 4 hours
schedule: "0 */2 * * *", // Every 2 hours
enabled: true,
},
{
Expand All @@ -97,6 +97,11 @@ const instance = await ai.initialize({
schedule: "20 */4 * * *", // Every 4 hours and 10 minutes
enabled: true,
},
{
type: "glu_updates",
schedule: "0 */1 * * *", // Every 1 hour
enabled: true,
},
],
debug: false,
runOnStartup: false,
Expand Down
100 changes: 99 additions & 1 deletion src/core/managers/llm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,104 @@ Return only a number between 0 and 1.`;
return flattened;
}

async generateGluUpdates(context?: ScheduledPostContext): Promise<{
tweetText: string;
}> {
try {
const character = await this.characterManager.getCharacter();
if (!character) throw new Error("Character not found");

// Get quantum personality if available
let personalitySettings: QuantumPersonalitySettings | undefined;
if (this.quantumPersonalityMapper) {
personalitySettings =
await this.quantumPersonalityMapper.mapQuantumToPersonality();
}

// Construct timeline context if available
const timelinePrompt = context?.timelineContext
? `
Recent activity from 0xglu:
${context.timelineContext.recentTweets
.map(
(tweet) =>
`- ${tweet.text} (${new Date(tweet.createdAt).toLocaleString()})`
)
.join("\n")}
Token metrics and market data:
${JSON.stringify(context.timelineContext.tokenMetrics, null, 2)}
Use this context to inform the tone and content of the tweet.
`
: "";

// Construct prompt using character style and quantum mood
const moodModifiers = personalitySettings?.styleModifiers.tone || [];
const prompt = `${
character.identity?.imageDescription
} with ${moodModifiers.join(" and ")} mood and ${
character.identity?.imageStyle
} with ${character.responseStyles.platforms.twitter?.styles.tweet_reply?.guidelines.join(
", "
)}
${timelinePrompt}`.trim();

// Generate image using FLUX
const response = await this.openai.images.generate({
prompt,
model: this.config.imageGeneration?.model,
n: 1,
});
if (!response.data[0]?.url) {
throw new Error("Failed to generate image");
}

// Generate tweet with matching quantum personality and timeline context
const tweetPrompt = await this.openai.chat.completions.create({
model: this.config.llm.model,
temperature:
personalitySettings?.temperature || this.config.llm.temperature,
messages: [
{
role: "system",
content: `You are ${character.name}. ${character.bio}
Personality: ${
personalitySettings?.personalityTraits.join(", ") ||
character.personalityTraits.join(", ")
}
Mood: ${moodModifiers.join(", ")}
Guidelines: ${character.responseStyles.platforms.twitter?.styles.tweet_reply?.guidelines.join(
", "
)}
${timelinePrompt}
Write a short, engaging tweet.
Consider the recent timeline context and token metrics in your response.
Follow Twitter style guidelines.
Match the current mood and market context in your response. RULES: NO QUOTES around the description just the description`,
},
],
});

const tweetText = `🦆 $DUCKAI Updates 🦆 \n\n
${tweetPrompt.choices[0]?.message?.content}`;
if (!tweetText) throw new Error("Failed to generate tweet text");

return {
tweetText,
};
} catch (error) {
console.error("Error generating scheduled image post:", error);
throw error;
}
}

async generateScheduledImagePost(context?: ScheduledPostContext): Promise<{
imageUrl: string;
tweetText: string;
Expand Down Expand Up @@ -753,7 +851,7 @@ Write a summary of the recent market news and token metrics.
Follow Twitter style guidelines.
If refering to marketcap use millions or billions.
You do not have to respond to every news story, if major news stories are mentioned, definitely include those.
Preferece the analysis with 🦆 DUCKY MARKET UPDATE 🦆
Preferece the analysis with 📰 News and Market Updates 📰
Stick to your character
Be verbose.
Use line breaks (two lines breaks) these do not count towards the character limit.
Expand Down
81 changes: 80 additions & 1 deletion src/core/managers/scheduler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@ import type { TwitterClient } from "../platform/twitter/api/src/client";
import { log } from "../utils/logger";

export interface ScheduledPostConfig {
type: "image" | "market_update" | "movers_alpha" | "market_cap_movers";
type:
| "image"
| "market_update"
| "movers_alpha"
| "market_cap_movers"
| "glu_updates";
schedule: string;
enabled: boolean;
maxPerDay?: number;
Expand Down Expand Up @@ -107,6 +112,9 @@ export class ScheduledPostManager {
case "market_cap_movers":
await this.handleMarketCapMoversPost(correlationId);
break;
case "glu_updates":
await this.handleGluUpdates(correlationId);
break;
default:
throw new Error(`Unsupported post type: ${config.type}`);
}
Expand Down Expand Up @@ -166,6 +174,77 @@ export class ScheduledPostManager {
return await response.buffer();
}

private async handleGluUpdates(correlationId: string) {
try {
// Get timeline context before generating content
const timelineContext = await this.analyzeTimeline();

// Generate image post content with timeline context
const { tweetText } = await this.ai.llmManager.generateGluUpdates({
timelineContext: timelineContext || undefined,
});

// Track content generation
await this.ai.eventService.createInteractionEvent("interaction.started", {
input: tweetText,
responseType: "glu_updates",
platform: "twitter",
timestamp: new Date().toISOString(),
messageId: "",
replyTo: "",
hasMention: false,
/* imageGeneration: {
url: imageUrl,
}, */
user: {
id: "",
metadata: { correlationId },
},
});

// Post to Twitter
if (this.debug) {
log.info("Debug mode enabled, skipping Twitter post");
log.info("Tweet text:", tweetText);
return;
}

if (this.twitterClient) {
const tweet = await this.twitterClient.sendTweet(tweetText);

await this.ai.eventService.createInteractionEvent(
"interaction.completed",
{
input: tweetText,
response: tweet.id,
responseType: "glu_updates",
platform: "twitter",
processingTime: 0,
timestamp: new Date().toISOString(),
messageId: "",
replyTo: "",
user: {
id: "",
metadata: { correlationId },
},
}
);
}
} catch (error) {
await this.ai.eventService.createInteractionEvent("interaction.failed", {
input: "",
error: error instanceof Error ? error.message : "Unknown error",
timestamp: new Date().toISOString(),
messageId: "",
user: {
id: "",
metadata: { correlationId },
},
});
throw error;
}
}

private async handleImagePost(correlationId: string) {
try {
// Get timeline context before generating content
Expand Down

0 comments on commit ad064e6

Please sign in to comment.