Skip to content

Commit bc90f42

Browse files
committed
adding CLI added webui to allow users to manage via UI also
1 parent 58b7f2c commit bc90f42

File tree

10 files changed

+1921
-4
lines changed

10 files changed

+1921
-4
lines changed

README.md

Lines changed: 143 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,9 @@ This Python-based Twitter Auto-Post Bot automates tweeting, Credit to the Tweepy
4444
- `src/functions.py`: Shared functions for generating tweets from openai and tweet posting
4545
- `requirements.txt`: Lists all necessary Python packages.
4646

47-
### 📁 Upcoming Features
48-
- `Adding CLI`.
47+
### ⭐ New: Command Line Interface (CLI)
48+
49+
The bot now includes a powerful CLI for easy management! See the [CLI Usage](#-cli-usage) section below.
4950

5051
## 🚀 Getting Started
5152

@@ -81,13 +82,153 @@ This Python-based Twitter Auto-Post Bot automates tweeting, Credit to the Tweepy
8182

8283
## 🔧 Usage
8384

85+
### Option 1: Using the Web UI (Recommended)
86+
87+
The easiest way to use the bot is through the browser-based web interface. See the [Web UI Usage](#-web-ui-usage) section below.
88+
89+
### Option 2: Using the CLI
90+
91+
For command-line enthusiasts, see the [CLI Usage](#-cli-usage) section below for terminal-based commands.
92+
93+
### Option 3: Running Scripts Directly
94+
8495
Run any script using Python:
8596

8697
```bash
8798
cd src/
8899
python instantly-tweet-from-openai.py
89100
```
90101

102+
## 🌐 Web UI Usage
103+
104+
The Web UI provides the easiest way to manage your Twitter bot through your browser.
105+
106+
### Starting the Web Interface
107+
108+
After installing dependencies with `pip install -r requirements.txt`, start the web server:
109+
110+
```bash
111+
python web.py
112+
```
113+
114+
The web interface will be available at: **http://localhost:5000**
115+
116+
Your browser should automatically open, or you can manually navigate to the URL.
117+
118+
### Web UI Features
119+
120+
#### Dashboard
121+
- View bot status and scheduler state
122+
- Test Twitter API credentials
123+
- Quick access to all features
124+
- Monitor scheduled jobs
125+
126+
#### Post Tweet
127+
- **AI-Generated Tweets**: Generate tweets using OpenAI's GPT-4 with custom prompts
128+
- **Random from File**: Post a random tweet from your tweets.txt library
129+
- **Custom Tweet**: Write and post your own tweet with character counter
130+
131+
#### Manage Tweets
132+
- View all tweets in your library
133+
- Add new tweets to the library
134+
- Edit existing tweets inline
135+
- Delete unwanted tweets
136+
- See library statistics
137+
138+
#### Schedule
139+
- Schedule daily AI-generated tweets at specific times
140+
- Schedule daily posts from your tweet library
141+
- Monitor scheduler status in real-time
142+
- Start/stop the scheduler
143+
- View active scheduled jobs
144+
145+
### Web UI Tips
146+
147+
- The web server must remain running for scheduled tweets to work
148+
- All times are in 24-hour format (HH:MM)
149+
- Only one scheduler can run at a time
150+
- The interface auto-refreshes scheduler status every 10 seconds
151+
152+
## 🎯 CLI Usage
153+
154+
The CLI provides a simple and intuitive interface for all bot operations.
155+
156+
### Installation
157+
158+
After installing dependencies with `pip install -r requirements.txt`, you can run the CLI:
159+
160+
```bash
161+
python cli.py --help
162+
```
163+
164+
### Available Commands
165+
166+
#### 1. Test Credentials
167+
168+
Test your Twitter API credentials:
169+
170+
```bash
171+
python cli.py test
172+
```
173+
174+
#### 2. Post a Tweet Instantly
175+
176+
**Post with AI (OpenAI):**
177+
```bash
178+
python cli.py post --ai
179+
```
180+
181+
**Post with custom AI prompt:**
182+
```bash
183+
python cli.py post --ai --prompt "Create a tweet about Python programming"
184+
```
185+
186+
**Post random tweet from file:**
187+
```bash
188+
python cli.py post --file
189+
```
190+
191+
**Post custom text:**
192+
```bash
193+
python cli.py post --text "Hello Twitter! This is my custom tweet"
194+
```
195+
196+
#### 3. Schedule Daily Tweets
197+
198+
**Schedule AI-generated tweets:**
199+
```bash
200+
python cli.py schedule-posts --ai --time "09:00"
201+
```
202+
203+
**Schedule with custom prompt:**
204+
```bash
205+
python cli.py schedule-posts --ai --time "14:30" --prompt "Create a tweet about technology"
206+
```
207+
208+
**Schedule tweets from file:**
209+
```bash
210+
python cli.py schedule-posts --file --time "12:00"
211+
```
212+
213+
#### 4. Manage Tweets File
214+
215+
**List all tweets in file:**
216+
```bash
217+
python cli.py list-tweets
218+
```
219+
220+
**Add a new tweet to file:**
221+
```bash
222+
python cli.py add-tweet
223+
```
224+
225+
### CLI Tips
226+
227+
- All times are in 24-hour format (HH:MM)
228+
- Press `Ctrl+C` to stop the scheduler
229+
- The `--help` flag works with any command for more details
230+
- Example: `python cli.py post --help`
231+
91232
## 🤝 Contributing
92233

93234
Contributions are what make the open-source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.

cli.py

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Twitter Auto-Post Bot CLI
4+
A command-line interface for managing automated Twitter posts.
5+
"""
6+
7+
import click
8+
import sys
9+
import os
10+
import schedule
11+
import time
12+
import random
13+
14+
sys.path.append(os.path.join(os.path.dirname(__file__), 'config'))
15+
sys.path.append(os.path.join(os.path.dirname(__file__), 'src'))
16+
17+
import keys
18+
from src.functions import generate_response, initialize_tweepy, get_formatted_date
19+
20+
21+
@click.group()
22+
@click.version_option(version='1.0.0')
23+
def cli():
24+
"""Twitter Auto-Post Bot - Automate your Twitter presence."""
25+
pass
26+
27+
28+
@cli.command()
29+
@click.option('--ai', is_flag=True, help='Generate tweet using AI')
30+
@click.option('--file', 'from_file', is_flag=True, help='Post random tweet from file')
31+
@click.option('--text', help='Post custom text')
32+
@click.option('--prompt', default='Create a short tweet about Motorbikes.', help='Custom prompt for AI (only with --ai)')
33+
def post(ai, from_file, text, prompt):
34+
"""Post a tweet instantly."""
35+
36+
if sum([ai, from_file, bool(text)]) != 1:
37+
click.echo(click.style('Error: Please specify exactly one option: --ai, --file, or --text', fg='red'))
38+
sys.exit(1)
39+
40+
try:
41+
client, _ = initialize_tweepy()
42+
43+
if ai:
44+
click.echo(click.style(f'Generating tweet with AI...', fg='yellow'))
45+
click.echo(click.style(f'Prompt: {prompt}', fg='cyan'))
46+
response = generate_response(prompt)
47+
tweet_text = response
48+
click.echo(click.style(f'\nGenerated tweet: {tweet_text}', fg='green'))
49+
50+
elif from_file:
51+
tweets_file = os.path.join(os.path.dirname(__file__), 'data', 'tweets.txt')
52+
if not os.path.exists(tweets_file):
53+
click.echo(click.style(f'Error: tweets.txt not found at {tweets_file}', fg='red'))
54+
sys.exit(1)
55+
56+
with open(tweets_file, 'r') as file:
57+
lines = [line.strip() for line in file.readlines() if line.strip()]
58+
59+
if not lines:
60+
click.echo(click.style('Error: tweets.txt is empty', fg='red'))
61+
sys.exit(1)
62+
63+
tweet_text = random.choice(lines)
64+
click.echo(click.style(f'Selected tweet: {tweet_text}', fg='green'))
65+
66+
else:
67+
tweet_text = text
68+
click.echo(click.style(f'Posting: {tweet_text}', fg='green'))
69+
70+
client.create_tweet(text=tweet_text)
71+
click.echo(click.style('Tweet posted successfully!', fg='green', bold=True))
72+
73+
except Exception as e:
74+
click.echo(click.style(f'Error posting tweet: {str(e)}', fg='red'))
75+
sys.exit(1)
76+
77+
78+
@cli.command()
79+
@click.option('--ai', is_flag=True, help='Schedule AI-generated tweets')
80+
@click.option('--file', 'from_file', is_flag=True, help='Schedule tweets from file')
81+
@click.option('--time', 'schedule_time', default='09:00', help='Time to post daily (HH:MM format, default: 09:00)')
82+
@click.option('--prompt', default='Create a short tweet about Motorbikes.', help='Custom prompt for AI (only with --ai)')
83+
def schedule_posts(ai, from_file, schedule_time, prompt):
84+
"""Schedule daily tweets at a specific time."""
85+
86+
if not ai and not from_file:
87+
click.echo(click.style('Error: Please specify either --ai or --file', fg='red'))
88+
sys.exit(1)
89+
90+
if ai and from_file:
91+
click.echo(click.style('Error: Please specify only one option: --ai or --file', fg='red'))
92+
sys.exit(1)
93+
94+
try:
95+
client, _ = initialize_tweepy()
96+
97+
if ai:
98+
def send_ai_post():
99+
try:
100+
click.echo(click.style(f'\nGenerating and posting tweet...', fg='yellow'))
101+
response = generate_response(prompt)
102+
client.create_tweet(text=response)
103+
click.echo(click.style(f'Tweet posted: {response}', fg='green'))
104+
click.echo(click.style(f'Next post scheduled for tomorrow at {schedule_time}', fg='cyan'))
105+
except Exception as e:
106+
click.echo(click.style(f'Error posting tweet: {str(e)}', fg='red'))
107+
108+
schedule.every().day.at(schedule_time).do(send_ai_post)
109+
click.echo(click.style(f'Scheduled AI-generated tweets daily at {schedule_time}', fg='green', bold=True))
110+
click.echo(click.style(f'Prompt: {prompt}', fg='cyan'))
111+
112+
else:
113+
tweets_file = os.path.join(os.path.dirname(__file__), 'data', 'tweets.txt')
114+
if not os.path.exists(tweets_file):
115+
click.echo(click.style(f'Error: tweets.txt not found at {tweets_file}', fg='red'))
116+
sys.exit(1)
117+
118+
def send_file_post():
119+
try:
120+
with open(tweets_file, 'r') as file:
121+
lines = [line.strip() for line in file.readlines() if line.strip()]
122+
123+
if not lines:
124+
click.echo(click.style('Error: tweets.txt is empty', fg='red'))
125+
return
126+
127+
tweet_text = random.choice(lines)
128+
client.create_tweet(text=tweet_text)
129+
click.echo(click.style(f'\nTweet posted: {tweet_text}', fg='green'))
130+
click.echo(click.style(f'Next post scheduled for tomorrow at {schedule_time}', fg='cyan'))
131+
except Exception as e:
132+
click.echo(click.style(f'Error posting tweet: {str(e)}', fg='red'))
133+
134+
schedule.every().day.at(schedule_time).do(send_file_post)
135+
click.echo(click.style(f'Scheduled tweets from file daily at {schedule_time}', fg='green', bold=True))
136+
137+
click.echo(click.style('\nPress Ctrl+C to stop the scheduler', fg='yellow'))
138+
139+
while True:
140+
schedule.run_pending()
141+
time.sleep(60)
142+
143+
except KeyboardInterrupt:
144+
click.echo(click.style('\n\nScheduler stopped.', fg='yellow'))
145+
except Exception as e:
146+
click.echo(click.style(f'Error: {str(e)}', fg='red'))
147+
sys.exit(1)
148+
149+
150+
@cli.command()
151+
def test():
152+
"""Test Twitter API credentials."""
153+
try:
154+
click.echo(click.style('Testing Twitter API credentials...', fg='yellow'))
155+
client, api = initialize_tweepy()
156+
157+
user = api.verify_credentials()
158+
click.echo(click.style('\nCredentials verified successfully!', fg='green', bold=True))
159+
click.echo(click.style(f'Authenticated as: @{user.screen_name}', fg='cyan'))
160+
click.echo(click.style(f'Name: {user.name}', fg='cyan'))
161+
click.echo(click.style(f'Followers: {user.followers_count}', fg='cyan'))
162+
click.echo(click.style(f'Following: {user.friends_count}', fg='cyan'))
163+
164+
except Exception as e:
165+
click.echo(click.style(f'\nCredentials test failed: {str(e)}', fg='red'))
166+
click.echo(click.style('\nPlease check your credentials in config/keys.py', fg='yellow'))
167+
sys.exit(1)
168+
169+
170+
@cli.command()
171+
def list_tweets():
172+
"""List all tweets from the tweets.txt file."""
173+
tweets_file = os.path.join(os.path.dirname(__file__), 'data', 'tweets.txt')
174+
175+
if not os.path.exists(tweets_file):
176+
click.echo(click.style(f'Error: tweets.txt not found at {tweets_file}', fg='red'))
177+
sys.exit(1)
178+
179+
try:
180+
with open(tweets_file, 'r') as file:
181+
lines = [line.strip() for line in file.readlines() if line.strip()]
182+
183+
if not lines:
184+
click.echo(click.style('tweets.txt is empty. Add some tweets first!', fg='yellow'))
185+
return
186+
187+
click.echo(click.style(f'\nFound {len(lines)} tweet(s) in file:', fg='green', bold=True))
188+
click.echo()
189+
190+
for i, tweet in enumerate(lines, 1):
191+
click.echo(click.style(f'{i}. ', fg='cyan') + tweet)
192+
193+
except Exception as e:
194+
click.echo(click.style(f'Error reading tweets file: {str(e)}', fg='red'))
195+
sys.exit(1)
196+
197+
198+
@cli.command()
199+
def add_tweet():
200+
"""Add a new tweet to the tweets.txt file interactively."""
201+
tweets_file = os.path.join(os.path.dirname(__file__), 'data', 'tweets.txt')
202+
203+
os.makedirs(os.path.dirname(tweets_file), exist_ok=True)
204+
205+
tweet = click.prompt(click.style('Enter your tweet', fg='cyan'))
206+
207+
if len(tweet) > 280:
208+
click.echo(click.style(f'Warning: Tweet is {len(tweet)} characters (Twitter limit is 280)', fg='yellow'))
209+
if not click.confirm(click.style('Do you want to add it anyway?', fg='yellow')):
210+
click.echo(click.style('Tweet not added.', fg='red'))
211+
return
212+
213+
try:
214+
with open(tweets_file, 'a') as file:
215+
file.write(tweet + '\n')
216+
217+
click.echo(click.style('\nTweet added successfully!', fg='green', bold=True))
218+
219+
except Exception as e:
220+
click.echo(click.style(f'Error adding tweet: {str(e)}', fg='red'))
221+
sys.exit(1)
222+
223+
224+
if __name__ == '__main__':
225+
cli()

data/tweets.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
Here is a tweet
1+
Here is a tweet 1
22
here is a different tweet
33
tweeet tweeet blah blah

0 commit comments

Comments
 (0)