A production-ready web application for posting content to multiple social media platforms (Threads, Instagram, Twitter/X, LinkedIn) using intelligent content transformation and DroidRun mobile automation.
- Real-time Progress Streaming: Server-Sent Events (SSE) for live agent updates
- Terminal-Style Output: Watch agent thinking and actions in real-time
- Multi-Platform Support: Post to Threads, Instagram, Twitter/X, and LinkedIn
- AI Content Transformation: Google Gemini optimizes content per platform
- Natural Language Media Selection: "Gallery recent 5 images" or "Screenshots from today"
- Link Crawling: Automatically extracts content from provided URLs
- Stop Button: Abort posting workflow mid-execution
- Responsive Design: Dark theme with green accents
- Platform-Specific Content: AI adapts text, hashtags, and tone for each platform
- Media Strategy Reuse: Same media selection across platforms for consistency
- Sequential Posting: Posts to platforms one at a time to avoid conflicts
- Error Handling: Comprehensive logging and graceful failure recovery
- Share Sheet Fallback: Instagram Feed → Reels → plain Instagram hierarchy
- Python 3.8+
- DroidRun framework installed (
pip install droidrun) - Android device with USB debugging enabled
- Google API key for content transformation
-
Install dependencies
pip install -r requirements.txt
-
Configure environment
export GOOGLE_API_KEY="your-google-api-key-here"
-
Set up DroidRun
# Copy example config cp config/droidrun_config.yaml.example config/droidrun_config.yaml # Edit config/droidrun_config.yaml and add your LLM API keys # See https://docs.droidrun.ai for configuration details
-
Connect Android device
a. Connect phone via USB cable
b. Enable USB debugging on phone:
- Settings → About Phone
- Tap "Build Number" 7 times
- Settings → Developer Options
- Enable "USB Debugging"
c. Accept permission prompt on phone
d. Run setup:
droidrun setup
e. Verify connection:
droidrun ping
python web/app.pyOpen browser to http://localhost:5001
-
Write Description (optional)
- Your main post content
- Will be transformed for each platform
-
Add Media Instructions (optional)
- Natural language: "Gallery recent 5 images"
- Examples: "Screenshots from today", "Media from last 2 days"
-
Add Links (optional)
- One URL per line
- Content will be crawled and incorporated
-
Select Platforms (required)
- Choose: Threads, Instagram, Twitter/X, LinkedIn
- Must select at least one
-
Click "Post Now"
- Watch real-time progress
- Results appear for each platform
- Use "Stop" to abort if needed
Gallery recent images
All media between Jan 4 and Jan 6
Media from last 2 days
All videos from gallery
Screenshots from today
Content uploaded in the last 48 hours
┌──────────────────────────────────────────────────────────┐
│ Web Interface │
│ (Flask + SSE Progress) │
├──────────────────────────────────────────────────────────┤
│ │
│ Content Input Link Crawler Platform Agents │
│ ├─ Description ├─ URL Extract ├─ Threads │
│ ├─ Media Hints ├─ Context ├─ Instagram │
│ └─ Links └─ AI Transform ├─ Twitter/X │
│ └─ LinkedIn │
└──────────────────────────────────────────────────────────┘
- Conversational, community-oriented content
- Thread support (multi-post style)
- Natural tone and hashtags
- 500 character limit per post
- Visual, engaging content with captions
- Share sheet selection (Feed → Reels → Instagram fallback)
- Catchy captions (150-200 chars)
- 20+ relevant hashtags
- Emoji suggestions
- Concise, viral-ready content
- 280 character optimization
- Trending hashtags
- Media attachment via Google Photos
- Professional, technical content
- Technical headlines and detailed descriptions
- 15 professional hashtags
- Thought leadership tone
.
├── web/
│ ├── app.py # Flask server with SSE
│ ├── templates/
│ │ └── index.html # Web UI
│ └── static/
│ ├── style.css # Dark theme styling
│ └── app.js # Frontend + SSE client
├── agents/
│ ├── threads_agent.py # Threads posting logic
│ ├── instagram_agent.py # Instagram automation
│ ├── twitter_agent.py # Twitter/X posting
│ └── linkedin_agent.py # LinkedIn posting
├── core/
│ ├── models.py # Data models
│ ├── base_agent.py # Abstract base agent
│ ├── link_crawler.py # URL crawling
│ ├── content_transformer.py # AI optimization
│ └── orchestrator.py # Legacy CLI orchestrator
├── config/
│ ├── settings.py # App configuration
│ └── droidrun_config.yaml # DroidRun settings
├── utils/
│ ├── logger.py # Logging utilities
│ └── text_utils.py # Text processing
└── requirements.txt # Dependencies
User Input (description + links + media)
↓
Extract URLs from description and links field
↓
Crawl URLs for content (2-level deep)
↓
Combine user description + crawled content
↓
AI Transformation (Google Gemini per platform)
↓
Platform-specific optimized content
↓
Sequential posting to selected platforms
↓
Real-time progress streamed to browser
- First Platform: Agent navigates device to select media based on instructions
- Subsequent Platforms: Reuses same media selection strategy
- Share Sheet Handling:
- Instagram: Feed → Reels → Instagram fallback with waits
- LinkedIn: Explicit media instruction parsing
- Twitter/X: Direct share to Twitter
- Threads: Direct share to Threads
# Required
export GOOGLE_API_KEY="your-google-api-key"
# Optional
export APP_ENV="production" # development, production, testing
export LOG_LEVEL="INFO" # DEBUG, INFO, WARNING, ERROREdit config/droidrun_config.yaml:
llm_profiles:
default:
provider: "openai" # or anthropic, google
model: "gpt-4"
api_key: "your-api-key"
agent:
max_steps: 15
timeout: 1500 # secondsEdit config/settings.py to enable/disable platforms:
PLATFORMS = {
"threads": {"enabled": True, "timeout": 60},
"instagram": {"enabled": True, "timeout": 90},
"twitter": {"enabled": True, "timeout": 60},
"linkedin": {"enabled": True, "timeout": 90},
}Submit content for posting.
Form Data:
text: Post descriptionmedia_source_instructions: Natural language media selectionlinks: URLs (one per line)platforms: JSON array["threads", "instagram"]
Response:
{
"success": true,
"message": "Content posted successfully",
"results": [{ "platform": "threads", "success": true, "reason": "Posted" }]
}Server-Sent Events stream for real-time updates.
Event Data:
{
"step": 1,
"total": 3,
"message": "Preparing content",
"percentage": 33,
"log": "Starting transformation...",
"logType": "info"
}GOOGLE_API_KEY not set
- Set environment:
export GOOGLE_API_KEY="your-key" - Or create
.envfile in project root
config/droidrun_config.yaml not found
- Copy
config/droidrun_config.yaml.example - Add your LLM API keys
- Verify YAML syntax
Platform posting fails
- Check app is installed on device
- Verify account is logged in
- Review logs for specific errors
Media selection fails
- Ensure instructions are clear
- Check Google Photos app is installed
- Verify device has media in specified timeframe
Progress stream disconnects
- Check browser console for errors
- Verify Flask server is running
- Check network connectivity
LOG_LEVEL=DEBUG python web/app.pyShows:
- Detailed agent decision-making
- Full error stack traces
- URL extraction details
- Content transformation steps
- Link Crawling: 5-10s per URL
- Content Transformation: 3-5s per platform
- Platform Posting: 20-60s per platform
- Total Workflow: 1-4 minutes for 4 platforms with media
Project by Umang Khhatri
For issues:
- Check troubleshooting section
- Review terminal logs
- Check DroidRun documentation at https://docs.droidrun.ai
- Review code comments for agent-specific details