2 |
3 | # 🐦 Twitter Auto-Post Bot 🤖
4 |
5 | [](https://www.python.org/downloads/release/python-370/)
6 | [](http://docs.tweepy.org/en/latest/)
7 | [](https://platform.openai.com/docs/libraries)
8 |
9 | [](https://schedule.readthedocs.io/en/stable/)
10 | [](https://opensource.org/licenses/MIT)
11 |
12 | Automate your Twitter presence. Auto Post tweets from from openAI GPT-5-nano, from a file, from a string, schedule a new tweet to be posted daily or post the tweet instantly.
13 |
14 |
15 | ---
16 |
17 | ## 🌟 About The Project
18 |
19 | This Python-based Twitter Auto-Post Bot automates tweeting, Credit to the Tweepy library for making this easy, this project enables scheduled and random tweets, offering a dynamic and engaging Twitter experience.
20 |
21 | ### 📁 Files Overview
22 | #### Using OpenAI
23 | ##### Instantly:
24 | - `src/instantly-tweet-from-openai.py`: Immediately tweets a tweet from openAI api response, currently using GPT-5-nano, but you can change the model in [functions.py](https://github.com/lewispour/Twitter-auto-Post-Bot---X.com---Tweepy-python-bot/blob/main/src/functions.py#L21)
25 |
26 | - ###### Prompt defined [here](https://github.com/lewispour/Twitter-auto-Post-Bot---X.com---Tweepy-python-bot/blob/main/src/instantly-tweet-from-openai.py#L7)
27 |
28 | ##### Schedule to auto post, tweet daily at a time:
29 | - `src/schedule-daily-post-from-openai.py`: Automates daily tweets, Runs daily at a scheduled time and queries open ai api to create a tweet, the tweet returned is then automatically tweeted each day to fully automate twitter on auto pilot. By default the model is OPENAI GPT-5-nano but you can change the model in [functions.py](https://github.com/lewispour/Twitter-auto-Post-Bot---X.com---Tweepy-python-bot/blob/main/src/functions.py#L21).
30 | - ###### Prompt defined [here](https://github.com/lewispour/Twitter-auto-Post-Bot---X.com---Tweepy-python-bot/blob/main/src/schedule-daily-post-from-openai.py#L12)
31 | - ###### Schedule time defined [here](https://github.com/lewispour/Twitter-auto-Post-Bot---X.com---Tweepy-python-bot/blob/main/src/schedule-daily-post-from-openai.py#L20)
32 |
33 | #### From File
34 | - `src/schedule-daily-post-from-file.py`: Automates daily tweets, randomly selecting from `tweets.txt`. To change the schedule time [edit this](https://github.com/lewispour/Twitter-auto-Post-Bot---X.com---Tweepy-python-bot/blob/main/src/schedule-daily-post-from-file.py#L22).
35 | - `src/tweeter-random-from-file.py`: Instantly posts a random tweet from `tweets.txt`.
36 |
37 | ###### Add your tweets to `data/tweets.txt`: one per line. They will be randomly selected and tweeted.
38 |
39 | #### Manually tweeting using script
40 | `src/tweeter-from-code.py`: Immediately tweets a pre-defined message with the current date, but you can change this to whatever you like.
41 |
42 | #### common files
43 | - `config/keys.py`: Holds both the creds for openai and twitter api.
44 | - `src/functions.py`: Shared functions for generating tweets from openai and tweet posting
45 | - `requirements.txt`: Lists all necessary Python packages.
46 |
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.
50 |
51 | ## 🚀 Getting Started
52 |
53 | ### Prerequisites
54 |
55 | - Python 3.x
56 | - Tweepy (Twitter API)
57 |
58 | ### Installation
59 |
60 | 1. Clone the repo:
61 | ```sh
62 | git clone git@github.com:lewispour/Twitter-auto-Post-Bot---X.com---Tweepy-python-bot.git
63 | ```
64 | 2. Install Python packages:
65 | ```sh
66 | pip install -r requirements.txt
67 | ```
68 |
69 | ### Setup
70 |
71 | 1. Obtain Twitter API credentials [here](https://developer.twitter.com/apps).
72 | 2. update `config/keys.py` file with your credentials:
73 | ```python
74 | bearer_token = "GET_KEY_FROM_developer.twitter.com/apps"
75 | api_key = "GET_KEY_FROM_developer.twitter.com/apps"
76 | api_secret = "GET_KEY_FROM_developer.twitter.com/apps"
77 | access_token = "GET_KEY_FROM_developer.twitter.com/apps"
78 | access_token_secret = "GET_KEY_FROM_developer.twitter.com/apps"
79 | openai_key = "GET_YOUR_OPENAI_API_KEY_FROM_https://platform.openai.com/api-keys"
80 | ```
81 | 3. Customize `data/tweets.txt` with your tweets. (SKIP: If not using tweet from file)
82 |
83 | ## 🔧 Usage
84 |
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 |
95 | Run any script using Python:
96 |
97 | ```bash
98 | cd src/
99 | python instantly-tweet-from-openai.py
100 | ```
101 |
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:8080**
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-5-nano 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 |
232 | ## 🤝 Contributing
233 |
234 | Contributions are what make the open-source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.
235 |
236 | ## 📝 License
237 |
238 | Distributed under the MIT License. See `LICENSE` for more information.
239 |
240 | ## ✉️ Contact
241 | Project Link: [https://github.com/lewispour/Twitter-auto-Post-Bot---X.com---Tweepy-python-bot](https://github.com/lewispour/Twitter-auto-Post-Bot---X.com---Tweepy-python-bot)
242 |
243 | ## ✉️ Status
244 | - Last tested and still working on 04/12/2025 ✅
245 |
--------------------------------------------------------------------------------
/cli.py:
--------------------------------------------------------------------------------
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()
226 |
--------------------------------------------------------------------------------
/web.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | """
3 | Twitter Auto-Post Bot Web Interface
4 | A browser-based interface for managing automated Twitter posts.
5 | """
6 |
7 | from flask import Flask, render_template, request, jsonify, redirect, url_for, flash
8 | import sys
9 | import os
10 | import random
11 | import json
12 | import threading
13 | import schedule
14 | import time
15 | from datetime import datetime
16 |
17 | sys.path.append(os.path.join(os.path.dirname(__file__), 'config'))
18 | sys.path.append(os.path.join(os.path.dirname(__file__), 'src'))
19 |
20 | import keys
21 | from src.functions import generate_response, initialize_tweepy, get_formatted_date
22 |
23 | app = Flask(__name__)
24 | app.secret_key = 'twitter-bot-secret-key-change-in-production'
25 |
26 | # Global variable to track scheduler
27 | scheduler_running = False
28 | scheduler_thread = None
29 | scheduled_jobs = []
30 |
31 |
32 | def get_tweets_from_file():
33 | """Read all tweets from the tweets.txt file."""
34 | tweets_file = os.path.join(os.path.dirname(__file__), 'data', 'tweets.txt')
35 | if not os.path.exists(tweets_file):
36 | return []
37 |
38 | with open(tweets_file, 'r') as file:
39 | return [line.strip() for line in file.readlines() if line.strip()]
40 |
41 |
42 | def save_tweets_to_file(tweets):
43 | """Save tweets to the tweets.txt file."""
44 | tweets_file = os.path.join(os.path.dirname(__file__), 'data', 'tweets.txt')
45 | os.makedirs(os.path.dirname(tweets_file), exist_ok=True)
46 |
47 | with open(tweets_file, 'w') as file:
48 | for tweet in tweets:
49 | file.write(tweet + '\n')
50 |
51 |
52 | @app.route('/')
53 | def index():
54 | """Dashboard page."""
55 | return render_template('index.html', scheduler_running=scheduler_running, scheduled_jobs=scheduled_jobs)
56 |
57 |
58 | @app.route('/test-credentials', methods=['POST'])
59 | def test_credentials():
60 | """Test Twitter API credentials."""
61 | try:
62 | client, api = initialize_tweepy()
63 | user = api.verify_credentials()
64 |
65 | return jsonify({
66 | 'success': True,
67 | 'data': {
68 | 'username': user.screen_name,
69 | 'name': user.name,
70 | 'followers': user.followers_count,
71 | 'following': user.friends_count
72 | }
73 | })
74 | except Exception as e:
75 | return jsonify({
76 | 'success': False,
77 | 'error': str(e)
78 | }), 400
79 |
80 |
81 | @app.route('/post')
82 | def post_page():
83 | """Post tweet page."""
84 | return render_template('post.html')
85 |
86 |
87 | @app.route('/post-tweet', methods=['POST'])
88 | def post_tweet():
89 | """Post a tweet instantly."""
90 | try:
91 | data = request.get_json()
92 | tweet_type = data.get('type')
93 |
94 | client, _ = initialize_tweepy()
95 |
96 | if tweet_type == 'ai':
97 | prompt = data.get('prompt', 'Create a short tweet about Motorbikes.')
98 | tweet_text = generate_response(prompt)
99 | elif tweet_type == 'file':
100 | tweets = get_tweets_from_file()
101 | if not tweets:
102 | return jsonify({'success': False, 'error': 'No tweets found in file'}), 400
103 | tweet_text = random.choice(tweets)
104 | elif tweet_type == 'text':
105 | tweet_text = data.get('text')
106 | if not tweet_text:
107 | return jsonify({'success': False, 'error': 'No text provided'}), 400
108 | else:
109 | return jsonify({'success': False, 'error': 'Invalid tweet type'}), 400
110 |
111 | client.create_tweet(text=tweet_text)
112 |
113 | return jsonify({
114 | 'success': True,
115 | 'tweet': tweet_text
116 | })
117 | except Exception as e:
118 | return jsonify({
119 | 'success': False,
120 | 'error': str(e)
121 | }), 400
122 |
123 |
124 | @app.route('/manage-tweets')
125 | def manage_tweets():
126 | """Manage tweets page."""
127 | tweets = get_tweets_from_file()
128 | return render_template('manage_tweets.html', tweets=tweets)
129 |
130 |
131 | @app.route('/add-tweet', methods=['POST'])
132 | def add_tweet():
133 | """Add a new tweet to the file."""
134 | try:
135 | data = request.get_json()
136 | tweet = data.get('tweet', '').strip()
137 |
138 | if not tweet:
139 | return jsonify({'success': False, 'error': 'Tweet cannot be empty'}), 400
140 |
141 | tweets = get_tweets_from_file()
142 | tweets.append(tweet)
143 | save_tweets_to_file(tweets)
144 |
145 | return jsonify({'success': True})
146 | except Exception as e:
147 | return jsonify({'success': False, 'error': str(e)}), 400
148 |
149 |
150 | @app.route('/delete-tweet', methods=['POST'])
151 | def delete_tweet():
152 | """Delete a tweet from the file."""
153 | try:
154 | data = request.get_json()
155 | index = data.get('index')
156 |
157 | tweets = get_tweets_from_file()
158 | if 0 <= index < len(tweets):
159 | tweets.pop(index)
160 | save_tweets_to_file(tweets)
161 | return jsonify({'success': True})
162 | else:
163 | return jsonify({'success': False, 'error': 'Invalid index'}), 400
164 | except Exception as e:
165 | return jsonify({'success': False, 'error': str(e)}), 400
166 |
167 |
168 | @app.route('/update-tweet', methods=['POST'])
169 | def update_tweet():
170 | """Update a tweet in the file."""
171 | try:
172 | data = request.get_json()
173 | index = data.get('index')
174 | new_text = data.get('text', '').strip()
175 |
176 | if not new_text:
177 | return jsonify({'success': False, 'error': 'Tweet cannot be empty'}), 400
178 |
179 | tweets = get_tweets_from_file()
180 | if 0 <= index < len(tweets):
181 | tweets[index] = new_text
182 | save_tweets_to_file(tweets)
183 | return jsonify({'success': True})
184 | else:
185 | return jsonify({'success': False, 'error': 'Invalid index'}), 400
186 | except Exception as e:
187 | return jsonify({'success': False, 'error': str(e)}), 400
188 |
189 |
190 | @app.route('/schedule')
191 | def schedule_page():
192 | """Schedule tweets page."""
193 | return render_template('schedule.html', scheduled_jobs=scheduled_jobs, scheduler_running=scheduler_running)
194 |
195 |
196 | def run_scheduler():
197 | """Run the scheduler in a separate thread."""
198 | global scheduler_running
199 | while scheduler_running:
200 | schedule.run_pending()
201 | time.sleep(60)
202 |
203 |
204 | @app.route('/start-schedule', methods=['POST'])
205 | def start_schedule():
206 | """Start scheduled tweets."""
207 | global scheduler_running, scheduler_thread, scheduled_jobs
208 |
209 | try:
210 | data = request.get_json()
211 | schedule_type = data.get('type')
212 | schedule_time = data.get('time', '09:00')
213 | prompt = data.get('prompt', 'Create a short tweet about Motorbikes.')
214 |
215 | if scheduler_running:
216 | return jsonify({'success': False, 'error': 'Scheduler is already running'}), 400
217 |
218 | # Clear existing jobs
219 | schedule.clear()
220 | scheduled_jobs = []
221 |
222 | client, _ = initialize_tweepy()
223 |
224 | if schedule_type == 'ai':
225 | def send_ai_post():
226 | try:
227 | response = generate_response(prompt)
228 | client.create_tweet(text=response)
229 | print(f'Posted tweet: {response}')
230 | except Exception as e:
231 | print(f'Error posting tweet: {str(e)}')
232 |
233 | schedule.every().day.at(schedule_time).do(send_ai_post)
234 | scheduled_jobs.append({
235 | 'type': 'AI Generated',
236 | 'time': schedule_time,
237 | 'prompt': prompt
238 | })
239 |
240 | elif schedule_type == 'file':
241 | def send_file_post():
242 | try:
243 | tweets = get_tweets_from_file()
244 | if tweets:
245 | tweet_text = random.choice(tweets)
246 | client.create_tweet(text=tweet_text)
247 | print(f'Posted tweet: {tweet_text}')
248 | except Exception as e:
249 | print(f'Error posting tweet: {str(e)}')
250 |
251 | schedule.every().day.at(schedule_time).do(send_file_post)
252 | scheduled_jobs.append({
253 | 'type': 'Random from File',
254 | 'time': schedule_time,
255 | 'prompt': 'N/A'
256 | })
257 |
258 | scheduler_running = True
259 | scheduler_thread = threading.Thread(target=run_scheduler, daemon=True)
260 | scheduler_thread.start()
261 |
262 | return jsonify({'success': True, 'message': f'Scheduler started for {schedule_time}'})
263 | except Exception as e:
264 | return jsonify({'success': False, 'error': str(e)}), 400
265 |
266 |
267 | @app.route('/stop-schedule', methods=['POST'])
268 | def stop_schedule():
269 | """Stop scheduled tweets."""
270 | global scheduler_running, scheduled_jobs
271 |
272 | scheduler_running = False
273 | schedule.clear()
274 | scheduled_jobs = []
275 |
276 | return jsonify({'success': True, 'message': 'Scheduler stopped'})
277 |
278 |
279 | @app.route('/scheduler-status')
280 | def scheduler_status():
281 | """Get scheduler status."""
282 | return jsonify({
283 | 'running': scheduler_running,
284 | 'jobs': scheduled_jobs
285 | })
286 |
287 |
288 | if __name__ == '__main__':
289 | print("Starting Twitter Bot Web Interface...")
290 | print("Open your browser and navigate to: http://localhost:8080")
291 | app.run(debug=True, host='0.0.0.0', port=8080)
292 |
--------------------------------------------------------------------------------
/templates/manage_tweets.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block title %}Manage Tweets - Twitter Bot{% endblock %}
4 |
5 | {% block content %}
6 |
7 |
8 |
9 | Manage Tweet Library
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | Add New Tweet
20 |
21 |
22 |
23 |
24 |
25 |
26 | 0 / 280 characters
27 |
28 |
29 |
30 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | Your Tweets ({{ tweets|length }})
40 |
43 |
44 |
45 |
46 | {% if tweets %}
47 | {% for tweet in tweets %}
48 |
49 |
50 |
51 |
{{ tweet }}
52 |
53 |
54 |
55 |
58 |
61 |
64 |
67 |
68 |
69 |
70 | Tweet {{ loop.index }}
71 |
72 |
73 | {% endfor %}
74 | {% else %}
75 |
76 | No tweets in your library yet. Add some tweets above to get started!
77 |