Skip to content

Instantly share code, notes, and snippets.

@idontcalculate
Created November 23, 2025 12:53
Show Gist options
  • Select an option

  • Save idontcalculate/767c22841132299109f2c7360476eedf to your computer and use it in GitHub Desktop.

Select an option

Save idontcalculate/767c22841132299109f2c7360476eedf to your computer and use it in GitHub Desktop.
use anyhow::{Context, Result};
use clap::Parser;
use dotenvy::dotenv;
use std::fs;
use tokio;
mod utils;
mod generator;
mod publisher;
mod listener;
#[derive(Parser)]
#[command(
name = "web3_ai_agent",
about = "Generate + publish AI-enhanced articles using Ethereum signals"
)]
struct Args {
/// Path to input markdown article
#[arg(default_value = "article.md")]
input: String,
/// Publish to Buttondown after generation
#[arg(long)]
publish: bool,
/// Path for HTML preview output
#[arg(long, default_value = "preview.html")]
preview: String,
/// Run Ethereum listener
#[arg(long)]
listen: bool,
}
#[tokio::main]
async fn main() -> Result<()> {
dotenv().ok();
let args = Args::parse();
// Handle Ethereum listener first
if args.listen {
println!("Starting Ethereum listener...");
return listener::start_listener().await;
}
// Load required API keys
let openai_key = std::env::var("OPENAI_API_KEY")
.context("Missing OPENAI_API_KEY in environment")?;
let buttondown_key = std::env::var("BUTTONDOWN_KEY")
.context("Missing BUTTONDOWN_KEY in environment")?;
// Read markdown file
let markdown = fs::read_to_string(&args.input)
.with_context(|| format!("Failed to read {}", args.input))?;
// Convert MD → HTML for preview
let html_preview = utils::md_to_html(&markdown);
fs::write(&args.preview, html_preview)
.with_context(|| format!("Failed to write {}", args.preview))?;
println!("✓ HTML preview saved to {}", args.preview);
// Generate subject & summary using OpenAI
println!("Generating newsletter subject and summary with OpenAI…");
let (subject, summary) =
generator::generate_subject_and_summary(&openai_key, &markdown)
.await
.context("Failed to generate AI summary")?;
println!("✓ Subject generated: {}", subject);
let final_body = format!(
"{}\n\n---\n\n{}",
summary.trim(),
markdown.trim()
);
if args.publish {
println!("Publishing to Buttondown…");
publisher::publish_to_buttondown(
&buttondown_key,
&subject,
&final_body,
false,
)
.await
.context("Failed to publish to Buttondown")?;
println!("✓ Article successfully published!");
} else {
println!("Preview generated. Use --publish to send to Buttondown.");
}
Ok(())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment