import os import requests import random import threading import time import schedule import tweepy import gradio as gr # Secrets from HF Space environment HF_TOKEN = os.environ['HF_TOKEN'] CONSUMER_KEY = os.environ['CONSUMER_KEY'] CONSUMER_SECRET = os.environ['CONSUMER_SECRET'] ACCESS_TOKEN = os.environ['ACCESS_TOKEN'] ACCESS_SECRET = os.environ['ACCESS_SECRET'] # LLM API setup API_URL = "https://router.huggingface.co/v1/chat/completions" headers = { "Authorization": f"Bearer {HF_TOKEN}", } def query(payload): response = requests.post(API_URL, headers=headers, json=payload) return response.json() # Topics for posts topics = [ "GeoAI as a field and it's application", "application of Geology with Tech for exploration", "application of AI in geological exploration", "Entrepreneurship" ] # Function to generate a high-quality post using LLM def generate_post(topic=None): if topic is None or topic == "Random": topic = random.choice(topics) prompt = f"Generate a high-quality, educational, and informative X (Twitter) post under 280 characters showcasing expertise in {topic}. Make it engaging, insightful, and professional. Include relevant hashtags and hashtags shouldn't be more than 2 or not even at all in some post also avoid using - in the post so it looks natural." response = query({ "messages": [{"role": "user", "content": prompt}], "model": "deepseek-ai/DeepSeek-V3.2:novita", "max_tokens": 200, "temperature": 0.8 }) post_content = response["choices"][0]["message"]["content"].strip() if len(post_content) > 280: post_content = post_content[:277] + "..." return post_content # Tweepy v2 Client setup client = tweepy.Client( consumer_key=CONSUMER_KEY, consumer_secret=CONSUMER_SECRET, access_token=ACCESS_TOKEN, access_token_secret=ACCESS_SECRET ) # Global queue and scheduler state post_queue = [] scheduler_running = False scheduler_thread = None # Function to post to X def post_to_x(content): try: response = client.create_tweet(text=content) tweet_id = response.data['id'] return f"Posted! https://x.com/user/status/{tweet_id}" except Exception as e: return f"Error: {str(e)}" # Scheduler job — posts one item from queue def scheduled_post_job(): global post_queue if post_queue: content = post_queue.pop(0) # FIFO: first in, first out result = post_to_x(content) print(f"[Scheduler] {result}\nContent: {content}") return result, "\n\n".join(post_queue) if post_queue else "Queue is empty." else: print("[Scheduler] Queue is empty.") return "No post scheduled — queue is empty.", "Queue is empty." # Background scheduler loop def run_scheduler(): global scheduler_running schedule.every(2).hours.do(scheduled_post_job) while scheduler_running: schedule.run_pending() time.sleep(30) # Start scheduler def start_scheduler(): global scheduler_running, scheduler_thread if not scheduler_running: scheduler_running = True scheduler_thread = threading.Thread(target=run_scheduler, daemon=True) scheduler_thread.start() return "Scheduler started! Posts every 2 hours from the queue." return "Scheduler is already running." # Stop scheduler def stop_scheduler(): global scheduler_running scheduler_running = False return "Scheduler stopped." # Clear queue function def clear_queue(): global post_queue post_queue.clear() return "Queue cleared.", "Queue is empty." # Gradio functions def generate_new_post(topic): content = generate_post(topic) return content, gr.update(visible=True) def add_to_queue(content): global post_queue stripped = content.strip() if stripped and stripped not in post_queue: post_queue.append(stripped) return ( "", # Clear the current post box gr.update(visible=False), # Hide Add button "\n\n".join(post_queue) if post_queue else "Queue is empty." ) # Gradio Interface with gr.Blocks(title="X Post Generator & Scheduler") as demo: gr.Markdown("# AI/Tech/Startups X Post Generator & Queue Scheduler") gr.Markdown("Generate → Review → Add to queue → Start scheduler for automated 2-hour posting.") with gr.Row(): topic_input = gr.Dropdown(choices=["Random"] + topics, value="Random", label="Topic") generate_btn = gr.Button("Generate New Post") current_post = gr.Textbox(label="Generated Post (Review before adding)", lines=6, interactive=False) add_btn = gr.Button("➕ Add to Queue", visible=False) queue_display = gr.Textbox( label="Post Queue (will be posted in order, every 2 hours)", value="Queue is empty.", lines=12, interactive=False ) with gr.Row(): start_btn = gr.Button("Start Scheduler") stop_btn = gr.Button("Stop Scheduler") clear_queue_btn = gr.Button("Clear Queue") status_box = gr.Textbox(label="Status", value="Ready", interactive=False) # Event bindings generate_btn.click( generate_new_post, inputs=topic_input, outputs=[current_post, add_btn] ) add_btn.click( add_to_queue, inputs=current_post, outputs=[current_post, add_btn, queue_display] ) start_btn.click( start_scheduler, outputs=status_box ) stop_btn.click( stop_scheduler, outputs=status_box ) clear_queue_btn.click( clear_queue, outputs=[status_box, queue_display] ) demo.launch()