Skip to main content

Overview

The Social Media Agent analyzes your Twitter writing style, stores it in Memori, generates new tweets that sound exactly like you using Nebius AI, and posts them automatically using Composioโ€™s Twitter integration.

Key Features

  • Twitter Style Analysis: Scrapes and analyzes your tweeting patterns, tone, and personality
  • Smart Web Scraping: Uses ScrapeGraph to extract your latest tweets automatically
  • Memory Integration: Stores your tweeting style profile using Memori
  • AI-Powered Generation: Creates tweets matching your social media personality
  • One-Click Posting: Direct Twitter integration via Composio
  • Style Persistence: Maintains your style across sessions

Architecture

Technology Stack

# Memori for memory persistence
from memori import Memori, create_memory_tool

# Nebius AI for style analysis and generation
from langchain_nebius import ChatNebius

# ScrapeGraph for tweet scraping
from langchain_scrapegraph.tools import SmartScraperTool

# Composio for Twitter posting
from composio import Composio

Memori Integration

def initialize_memori():
    """Initialize Memori memory system for Twitter style."""
    memory_system = Memori(
        database_connect="sqlite:///tmp/twitter_style_memory.db",
        auto_ingest=True,
        conscious_ingest=True,
        verbose=False,
        namespace="twitter_tweeting_style",  # Isolated namespace
    )
    memory_system.enable()
    return memory_system

Implementation

Tweet Scraping with ScrapeGraph

from langchain_scrapegraph.tools import SmartScraperTool
import os

def scrape_user_tweets(twitter_handle: str) -> dict:
    """Scrape user's tweets using ScrapeGraph."""
    # Remove @ if present
    if twitter_handle.startswith("@"):
        twitter_handle = twitter_handle[1:]
    
    twitter_url = f"https://x.com/{twitter_handle}"
    
    # Initialize scraper
    scraper_tool = SmartScraperTool(api_key=os.getenv("SGAI_API_KEY"))
    
    result = scraper_tool.invoke({
        "website_url": twitter_url,
        "user_prompt": (
            "Extract the following information for this Twitter handle: "
            "- Username (display name)\n"
            "- Profile image URL\n"
            "- Handle (e.g., @username)\n"
            "- The latest 10 top tweets (original tweets only, not replies or retweets)\n"
            "For each tweet, include: tweet text, timestamp, and media URLs if available."
        ),
    })
    
    return {
        "username": result.get("username"),
        "profile_image_url": result.get("profile_image_url"),
        "handle": result.get("handle"),
        "tweets": result.get("latest_tweets") or result.get("tweets"),
    }

Tweet Style Analysis

from langchain_nebius import ChatNebius
import json

nebius_chat = ChatNebius(
    api_key=os.getenv("NEBIUS_API_KEY"),
    model="zai-org/GLM-4.5-Air",
    temperature=0.6,
    top_p=0.95,
)

def analyze_tweeting_style(tweets: list) -> dict:
    """Analyze tweeting style using Nebius LLM."""
    # Prepare tweets for analysis
    tweets_text = ""
    for i, tweet in enumerate(tweets, 1):
        tweets_text += f"Tweet {i}: {tweet.get('description', 'N/A')}\n"
    
    prompt = f"""
    Analyze the following tweets and extract the author's tweeting style characteristics. 
    Focus on:
    1. Tone (casual, professional, humorous, serious, etc.)
    2. Language style (formal, informal, slang, technical, etc.)
    3. Common hashtags and their themes
    4. Emoji usage patterns
    5. Tweet structure and length preferences
    6. Topics and interests they tweet about
    7. Writing personality and voice
    8. Common phrases or expressions they use
    
    Tweets to analyze:
    {tweets_text}
    
    Provide your analysis in JSON format with these keys:
    - tone: string describing the tone
    - language_style: string describing language formality and style
    - hashtag_patterns: list of common hashtags and themes
    - emoji_usage: string describing emoji patterns
    - tweet_structure: string describing tweet length and structure preferences
    - common_topics: list of topics they tweet about
    - personality: string describing overall personality
    - common_phrases: list of phrases or expressions they use
    - writing_habits: list of specific tweeting habits or patterns
    """
    
    response = nebius_chat.invoke(prompt)
    analysis_text = response.content
    
    # Extract JSON from response
    if "```json" in analysis_text:
        json_start = analysis_text.find("```json") + 7
        json_end = analysis_text.find("```", json_start)
        json_content = analysis_text[json_start:json_end].strip()
    else:
        json_start = analysis_text.find("{")
        json_end = analysis_text.rfind("}") + 1
        json_content = analysis_text[json_start:json_end]
    
    return json.loads(json_content)

Storing Style in Memori

def store_tweeting_style_in_memori(
    memory_system,
    style_analysis: dict,
    twitter_handle: str,
    profile_image_url: str,
    handle: str,
    username: str,
):
    """Store tweeting style analysis in Memori."""
    # Create a conversation about the tweeting style
    user_input = f"""
    Hi AI, here is my Twitter style from @{twitter_handle}: 
    {style_analysis.get('tone', 'N/A')} tone, 
    {style_analysis.get('personality', 'N/A')} personality, 
    {style_analysis.get('language_style', 'N/A')} language style.
    """
    
    ai_response = f"""
    I understand your Twitter style! You tweet with a 
    {style_analysis.get('tone', 'N/A')} tone and 
    {style_analysis.get('personality', 'N/A')} personality. 
    Your language is {style_analysis.get('language_style', 'N/A')}. 
    I'll use this to generate tweets that sound exactly like you.
    """
    
    # Record in Memori with metadata
    memory_system.record_conversation(
        user_input=user_input,
        ai_output=ai_response,
        model="nebius-glm-4.5-air",
        metadata={
            "type": "twitter_style_profile",
            "twitter_handle": twitter_handle,
            "style_data": style_analysis,
            "analysis_timestamp": "now",
            "profile_image_url": profile_image_url,
            "username": username,
            "handle": handle,
        },
    )
    
    return ai_response

Generating Tweets with Style

def generate_tweet_with_style(memory_tool, topic: str) -> str:
    """Generate tweet using stored tweeting style from memory."""
    # Get tweeting style context from memory
    writing_style_context = ""
    try:
        context_result = memory_tool.execute(query="twitter style tone personality")
        if context_result and "No relevant memories found" not in str(context_result):
            writing_style_context = str(context_result)[:300]
    except Exception:
        pass
    
    # Create prompt based on whether we have style
    if writing_style_context:
        prompt = f"Write a tweet about '{topic}' in this exact style: {writing_style_context}. Keep it casual, under 275 characters. NO quotes. Just the tweet."
    else:
        prompt = f"Write a casual tweet about '{topic}'. Under 275 characters. NO quotes. Just the tweet."
    
    response = nebius_chat.invoke(prompt)
    tweet_content = response.content.strip()
    
    # Clean up formatting
    if tweet_content.startswith('"') and tweet_content.endswith('"'):
        tweet_content = tweet_content[1:-1]
    
    # Ensure character limit
    if len(tweet_content) > 275:
        tweet_content = tweet_content[:275] + "..."
    
    return tweet_content

Posting to Twitter with Composio

from composio import Composio
import os

def post_tweet_via_composio(tweet_text: str) -> bool:
    """Post tweet using Composio Twitter toolkit."""
    try:
        composio = Composio()
        
        # Get Twitter toolkit
        toolkit = composio.get_tools(
            apps=["twitter"],
            auth_config_id=os.getenv("TWITTER_AUTH_CONFIG_ID"),
            user_id=os.getenv("USER_ID")
        )
        
        # Post tweet
        result = toolkit.actions.TWITTER_CREATE_TWEET(
            text=tweet_text
        )
        
        return result.success
    except Exception as e:
        print(f"Error posting tweet: {e}")
        return False

Streamlit Application

import streamlit as st

st.title("๐Ÿฆ Social Media Agent")

# Sidebar: Style Analysis Agent
with st.sidebar:
    st.header("๐Ÿ” Style Analysis Agent")
    
    twitter_handle = st.text_input("Enter Twitter Handle", placeholder="@yourusername")
    
    if st.button("๐Ÿ” Analyze Tweeting Style"):
        with st.spinner("Scraping and analyzing tweets..."):
            # Scrape tweets
            tweet_data = scrape_user_tweets(twitter_handle)
            
            # Analyze style
            style_analysis = analyze_tweeting_style(tweet_data["tweets"])
            
            # Store in Memori
            memory_system = initialize_memori()
            store_tweeting_style_in_memori(
                memory_system,
                style_analysis,
                twitter_handle,
                tweet_data["profile_image_url"],
                tweet_data["handle"],
                tweet_data["username"]
            )
            
            st.success("โœ… Tweeting style analyzed and stored!")
            st.json(style_analysis)

# Main area: Tweet Generation Agent
st.header("โœ๏ธ Tweet Generation Agent")
topic = st.chat_input("What would you like to tweet about?")

if topic:
    with st.spinner("Generating tweet..."):
        memory_system = initialize_memori()
        memory_tool = create_memory_tool(memory_system)
        
        # Generate tweet
        tweet_content = generate_tweet_with_style(memory_tool, topic)
        st.markdown(f"**Generated Tweet:** {tweet_content}")
        
        # Post to Twitter
        if st.button("๐Ÿฆ Post to Twitter"):
            if post_tweet_via_composio(tweet_content):
                st.success("โœ… Tweet posted successfully!")
            else:
                st.error("โŒ Failed to post tweet")

Tweet Style Dimensions

Tone

Casual, professional, humorous, serious, sarcastic, inspirational

Personality

Friendly, authoritative, tech-savvy, creative, analytical

Language Style

Formal, informal, slang, technical jargon, conversational

Emoji Usage

Frequency, placement, types of emojis used

Tweet Structure

Length preferences, formatting patterns, thread usage

Hashtag Patterns

Common themes, frequency, placement, trending topics

Installation

git clone https://github.com/Arindam200/awesome-ai-apps.git
cd memory_agents/social_media_agent
uv sync

Environment Setup

Create a .env file:
# Nebius AI Configuration
NEBIUS_API_KEY=your_nebius_api_key

# ScrapeGraph Configuration
SGAI_API_KEY=your_scrapegraph_api_key

# Composio Twitter Integration
COMPOSIO_API_KEY=your_composio_api_key
TWITTER_AUTH_CONFIG_ID=your_twitter_auth_config_id
USER_ID=your_unique_user_identifier

# Optional: OpenAI (for fallback)
OPENAI_API_KEY=your_openai_api_key

Running the Application

uv run streamlit run app.py

Workflow

1

Enter Twitter Handle

Input your Twitter handle (e.g., @yourusername)
2

Analyze Style

Click โ€๐Ÿ” Analyze Tweeting Styleโ€ to scrape and analyze your tweets
3

Generate Tweets

Use the chat input to request new tweets about any topic
4

Post to Twitter

Click โ€๐Ÿฆ Post to Twitterโ€ to publish directly via Composio

Use Cases

Personal Branding

Maintain consistent voice across all your social media posts

Content Automation

Generate and schedule tweets while preserving authenticity

Team Management

Allow team members to tweet in the brandโ€™s voice

A/B Testing

Test different tweeting styles while maintaining core personality

Best Practices

1

Analyze Your Own Account

Start by analyzing your personal Twitter account for the most authentic style
2

Use Recent Tweets

The scraper gets your latest 10 tweets for current style representation
3

Review Before Posting

Always review generated tweets before posting to ensure quality
4

Update Style Regularly

Re-analyze your tweets periodically as your style evolves

API Configuration

Nebius AI

model
string
default:"zai-org/GLM-4.5-Air"
Nebius model for tweet generation and style analysis
temperature
float
default:"0.6"
Controls creativity - higher values = more creative tweets

ScrapeGraph

api_key
string
required
ScrapeGraph AI API key for Twitter data extraction

Composio Twitter

auth_config_id
string
required
Composio Twitter authentication config ID from dashboard
user_id
string
required
Unique user identifier for Composio

Memori Documentation

Official Memori memory system documentation

Composio Platform

Composio integration platform for Twitter API

ScrapeGraph AI

ScrapeGraph AI for intelligent web scraping

Nebius AI

Nebius AI model provider

Build docs developers (and LLMs) love