Spaces:
Runtime error
Runtime error
File size: 18,772 Bytes
2d12925 3bb5012 2d12925 3bb5012 2d12925 3bb5012 2d12925 3bb5012 2d12925 3bb5012 2d12925 3bb5012 2d12925 3bb5012 2d12925 3bb5012 2d12925 3bb5012 2d12925 3bb5012 2d12925 3bb5012 2d12925 96ee6f0 3bb5012 2d12925 3bb5012 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 | import gradio as gr
import numpy as np
import random
import requests
import io
import re
from datetime import datetime
from PIL import Image, ImageDraw, ImageFont
import textwrap
import google.generativeai as genai
from diffusers import DiffusionPipeline
import torch
# Set device and model for SDXL-Turbo
device = "cuda" if torch.cuda.is_available() else "cpu"
model_repo_id = "stabilityai/sdxl-turbo"
torch_dtype = torch.float16 if torch.cuda.is_available() else torch.float32
# Initialize SDXL-Turbo pipeline
pipe = DiffusionPipeline.from_pretrained(model_repo_id, torch_dtype=torch_dtype)
pipe = pipe.to(device)
MAX_SEED = np.iinfo(np.int32).max
MAX_IMAGE_SIZE = 1024
class CurrentAffairsGenerator:
def __init__(self, gemini_api_key, news_api_key=None, logo_url=None):
self.gemini_api_key = gemini_api_key
self.news_api_key = news_api_key
self.logo_url = logo_url
self.newsapi_base_url = "https://newsapi.org/v2/everything"
if self.gemini_api_key:
try:
genai.configure(api_key=self.gemini_api_key)
self.gemini_model = genai.GenerativeModel('gemini-2.5-flash')
except Exception as e:
gr.Warning(f"Could not configure Gemini API: {e}.")
self.gemini_model = None
else:
self.gemini_model = None
self.brand_colors = {
'primary': '#0F172A',
'accent': '#F59E0B',
'text': '#FFFFFF',
'text_shadow': '#000000',
}
def fetch_latest_news(self, category):
if self.news_api_key:
gr.Info(f"Searching for live news about '{category}'...")
try:
news_data = self._search_with_newsapi(category)
if news_data:
gr.Info("Successfully fetched live news!")
return news_data
gr.Warning("Could not find relevant live news. Using a sample article.")
except Exception as e:
gr.Error(f"News API Error: {e}. Using a sample article.")
return self._get_sample_news(category)
def _search_with_newsapi(self, category):
params = {
'q': f'"{category}" AND "India"',
'language': 'en',
'sortBy': 'publishedAt',
'pageSize': 10,
'apiKey': self.news_api_key
}
response = requests.get(self.newsapi_base_url, params=params)
response.raise_for_status()
articles = response.json().get('articles', [])
for article in articles:
content = article.get('content')
description = article.get('description')
full_content = content if content and len(content) > 10 else description
if full_content:
full_content_cleaned = re.sub(r'\[\s*\+\d+\s*chars\s*\]$', '', full_content).strip()
if len(full_content_cleaned) > 50:
return {
'title': article['title'],
'full_content': full_content_cleaned,
'source': article['source']['name'],
'category': category
}
return None
def _get_sample_news(self, topic=None):
sample_news = [
{'title': 'ISRO Confirms Gaganyaan Crew Module is Flight-Ready', 'full_content': 'The Indian Space Research Organisation has successfully completed all qualification tests for its first crewed space mission. This milestone includes rigorous vibration tests, acoustic assessments, and a series of parachute deployment simulations. The crew module is now officially certified for flight, bringing India one step closer to sending its own astronauts into space.', 'source': 'ISRO', 'category': 'Science'},
{'title': 'India Launches "Bharat AI" Research Supercluster', 'full_content': 'In a major push for artificial intelligence, the government has funded a new initiative to build a world-class AI ecosystem. This supercluster will connect top research institutions and startups, providing them with immense computing power and a platform for collaboration to solve India-specific challenges.', 'source': 'Ministry of Technology', 'category': 'Technology'},
{'title': 'UPI Transactions Cross 10 Billion Mark in a Single Month', 'full_content': 'India\'s Unified Payments Interface (UPI) has set a new global benchmark for digital payments, crossing the 10 billion transaction mark in a single month. This reflects the rapid and widespread adoption of digital finance across both urban and rural India, transforming the nation\'s economic landscape.', 'source': 'Reserve Bank of India', 'category': 'Economy'}
]
if topic:
topic_lower = topic.lower()
filtered_news = [news for news in sample_news if topic_lower in news['category'].lower()]
if filtered_news: return random.choice(filtered_news)
return random.choice(sample_news)
def generate_llm_content(self, news_data):
if not self.gemini_model:
return news_data['title'], [f"Key Update: {news_data['full_content']}"]
prompt = f"""
Act as an expert social media analyst. Analyze this news:
Title: "{news_data['title']}"
Content: "{news_data['full_content']}"
Your Task:
1. Create one short, impactful headline (under 10 words).
2. Generate 3 highly informative bullet points.
3. IMPORTANT: For the bullet points, provide ONLY the text. DO NOT include any leading emojis or symbols like '☐', '-', or '*'.
Output Format (Strictly follow this):
HEADLINE: [Your headline here]
BULLETS:
[Your first insightful bullet point text]
[Your second insightful bullet point text]
[Your third insightful bullet point text]
"""
try:
response = self.gemini_model.generate_content(prompt)
clean_text = re.sub(r'[\*#]', '', response.text)
headline = clean_text.split("HEADLINE:")[1].split("BULLETS:")[0].strip()
bullets_str = clean_text.split("BULLETS:")[1].strip()
bullets = [line.strip().lstrip('- ') for line in bullets_str.split('\n') if line.strip()]
return headline, bullets[:3]
except Exception as e:
gr.Warning(f"Gemini content generation failed: {e}. Using fallback.")
return news_data['title'], [news_data['full_content']]
def create_image_prompt(self, news_data):
category = news_data.get('category', 'General').lower()
prompts = {
'technology': [
"Futuristic cityscape with holographic data streams and glowing circuits, cinematic lighting, deep blue and gold palette, 4K hyper-detailed digital art.",
"Abstract visualization of a neural network, glowing nodes connected by light trails, dark background, symbolizing AI and connectivity.",
"Sleek server room with a liquid cooling system, neon blue lights reflecting on polished surfaces, representing high-performance computing.",
"Digital art of a human brain merging with a glowing circuit board, illustrating the concept of human-computer interface.",
],
'economy': [
"Abstract visualization of a bullish stock market graph turning into a growing tree with coin-like leaves, against a modern city skyline.",
"A dynamic 3D render of the Indian Rupee symbol glowing brightly, surrounded by upward-trending financial charts and graphs.",
"A bustling, modern marketplace where digital transactions are visualized as light flowing between people and vendors, symbolizing a digital economy.",
"Photorealistic image of a new infrastructure project like a bridge or highway, bathed in golden morning light, representing national growth.",
],
'science': [
"A stunning view of a satellite orbiting Earth with the Indian subcontinent visible below, against a cosmic background of nebulae and stars.",
"A clean, modern laboratory with scientists working with holographic displays showing DNA strands and molecular structures, high-tech aesthetic.",
"Digital painting of the Gaganyaan spacecraft soaring through the upper atmosphere, leaving a trail of fire and smoke.",
"Microscopic view of new material discovery, with crystalline structures glowing with internal light, abstract and beautiful.",
],
'environment': [
"Lush green Indian landscape integrating futuristic eco-technology like solar panels that follow the sun and artistic wind turbines.",
"A pristine river flowing through a regenerated forest, with clear water and abundant wildlife, symbolizing ecological restoration.",
"Concept art of a 'vertical forest' skyscraper in an Indian city, covered in plants and trees, promoting urban greening.",
"A split view showing a polluted city on one side and a clean, green city on the other, highlighting the choice for a sustainable future.",
],
}
prompt_list = prompts.get(category, prompts['technology'])
base_prompt = random.choice(prompt_list)
return f"{base_prompt}, professional design, high resolution, visually striking for social media."
def generate_background_image(self, news_data, seed, randomize_seed, width=1024, height=1024, guidance_scale=0.0, num_inference_steps=2):
prompt = self.create_image_prompt(news_data)
gr.Info(f"🎨 Generating a unique image with prompt: \"{prompt}\"")
if randomize_seed:
seed = random.randint(0, MAX_SEED)
generator = torch.Generator().manual_seed(seed)
try:
image = pipe(
prompt=prompt,
negative_prompt="",
guidance_scale=guidance_scale,
num_inference_steps=num_inference_steps,
width=width,
height=height,
generator=generator,
).images[0]
return image, seed
except Exception as e:
gr.Error(f"Image generation failed: {e}. Using fallback image.")
return self._create_fallback_image(), seed
def _create_fallback_image(self):
img = Image.new('RGB', (1080, 1080))
draw = ImageDraw.Draw(img)
for i in range(1080):
r, g, b = int(15 + 15 * (i/1080)), int(23 + 18 * (i/1080)), int(42 + 17 * (i/1080))
draw.line([(0, i), (1080, i)], fill=(r, g, b))
return img
def _get_logo(self, size=60):
if self.logo_url:
try:
response = requests.get(self.logo_url)
response.raise_for_status()
logo_img = Image.open(io.BytesIO(response.content)).convert("RGBA")
logo_img.thumbnail((size, size))
return logo_img
except Exception as e:
gr.Warning(f"Failed to load logo from URL: {e}. Using fallback.")
logo = Image.new('RGBA', (size, size), (0, 0, 0, 0))
draw = ImageDraw.Draw(logo)
draw.ellipse([0, 0, size, size], fill=self.brand_colors['accent'])
try:
font = ImageFont.truetype("seguibld.ttf", int(size * 0.7))
except IOError:
font = ImageFont.load_default()
draw.text((size/2, size/2), "P", font=font, fill='white', anchor="mm")
return logo
def _draw_text_with_outline(self, draw, position, text, font, fill_color, shadow_color):
x, y = position
outline = 2
for dx in range(-outline, outline + 1):
for dy in range(-outline, outline + 1):
if dx != 0 or dy != 0:
draw.text((x + dx, y + dy), text, font=font, fill=shadow_color)
draw.text(position, text, font=font, fill=fill_color)
def create_instagram_post(self, category, seed, randomize_seed, width=1024, height=1024, guidance_scale=0.0, num_inference_steps=2):
news_data = self.fetch_latest_news(category)
if not news_data:
gr.Error("Could not retrieve any news story. Please try again.")
return None, None, None, seed
headline, bullet_points = self.generate_llm_content(news_data)
bg_image, seed = self.generate_background_image(news_data, seed, randomize_seed, width, height, guidance_scale, num_inference_steps)
bg_image = bg_image.resize((1080, 1080))
overlay = Image.new('RGBA', (1080, 1080), (0, 0, 0, 0))
draw = ImageDraw.Draw(overlay)
draw.rectangle([0, 0, 1080, 1080], fill=(0, 0, 0, 80))
try:
title_font = ImageFont.truetype("impact.ttf", 85)
bullet_font = ImageFont.truetype("verdana.ttf", 36)
brand_font = ImageFont.truetype("verdana.ttf", 28)
date_font = ImageFont.truetype("verdanab.ttf", 24)
except IOError:
gr.Warning("Custom fonts not found. Using default fonts.")
title_font, bullet_font, brand_font, date_font = (ImageFont.load_default(),)*4
draw.text((60, 60), "TODAY'S UPDATE", font=date_font, fill=self.brand_colors['accent'])
y_pos = 150
for line in textwrap.wrap(headline.upper(), width=25):
self._draw_text_with_outline(draw, (60, y_pos), line, title_font, self.brand_colors['text'], self.brand_colors['text_shadow'])
y_pos += 95
y_pos = 480
content_area_end_y = 930
stop_drawing = False
for point_text in bullet_points:
if stop_drawing:
break
bullet_radius = 6
bullet_x = 70
first_line_height = bullet_font.getbbox('A')[3]
bullet_y = y_pos + (first_line_height / 2) - bullet_radius
if bullet_y > content_area_end_y:
break
draw.ellipse(
(bullet_x, bullet_y, bullet_x + bullet_radius*2, bullet_y + bullet_radius*2),
fill=self.brand_colors['accent']
)
text_x = bullet_x + bullet_radius*2 + 20
wrapped_text = textwrap.wrap(point_text, width=40)
line_y = y_pos
for line in wrapped_text:
if line_y + first_line_height > content_area_end_y:
stop_drawing = True
break
self._draw_text_with_outline(draw, (text_x, line_y), line, bullet_font, self.brand_colors['text'], self.brand_colors['text_shadow'])
line_y += 45
y_pos = line_y + 20
draw.rectangle([0, 950, 1080, 1080], fill=self.brand_colors['primary'])
logo = self._get_logo(size=100)
final_image = Image.alpha_composite(bg_image.convert('RGBA'), overlay)
final_image.paste(logo, (940, 965), logo)
draw_final = ImageDraw.Draw(final_image)
draw_final.text((60, 990), "+91 9354253889", font=brand_font, fill=self.brand_colors['text'], anchor="lm")
draw_final.text((920, 990), "pragzo.com", font=brand_font, fill=self.brand_colors['accent'], anchor="rm")
return final_image, headline, news_data, seed
# Gradio Interface
def generate_post(gemini_api_key, news_api_key, logo_url, category, seed, randomize_seed, width, height, guidance_scale, num_inference_steps, progress=gr.Progress(track_tqdm=True)):
if not gemini_api_key:
gr.Error("Please provide a Gemini API key.")
return None, None, None, seed
generator = CurrentAffairsGenerator(gemini_api_key, news_api_key, logo_url)
image, headline, news_data, seed = generator.create_instagram_post(category, seed, randomize_seed, width, height, guidance_scale, num_inference_steps)
if image:
img_buffer = io.BytesIO()
image.save(img_buffer, format='PNG')
return image, headline, f"**Original Title:** {news_data['title']}\n**Source:** {news_data['source']}\n**Content Analyzed by AI:**\n\n> {news_data['full_content']}", seed
return None, None, None, seed
css = """
#col-container {
margin: 0 auto;
max-width: 800px;
}
"""
with gr.Blocks(css=css) as demo:
gr.Markdown("# 🚀 Pragzo | AI Current Affairs Post Generator")
gr.Markdown("Instantly create stunning, unique Instagram posts from live news, powered by AI and SDXL-Turbo.")
with gr.Column(elem_id="col-container"):
with gr.Row():
gemini_api_key = gr.Textbox(label="Gemini API Key", type="password", placeholder="Enter your Gemini API key")
news_api_key = gr.Textbox(label="News API Key (Optional)", type="password", placeholder="Enter your News API key")
logo_url = gr.Textbox(label="Logo URL (Optional)", placeholder="https://.../logo.png")
with gr.Row():
category = gr.Dropdown(
label="News Category",
choices=["Technology", "Economy", "Science", "Environment", "Sports", "Education"],
value="Technology"
)
run_button = gr.Button("🛰️ Generate Post", variant="primary")
result = gr.Image(label="Generated Instagram Post", show_label=True)
headline = gr.Textbox(label="AI-Generated Headline", interactive=False)
news_content = gr.Markdown(label="Source News Content")
with gr.Accordion("Advanced Image Settings", open=False):
seed = gr.Slider(label="Seed", minimum=0, maximum=MAX_SEED, step=1, value=0)
randomize_seed = gr.Checkbox(label="Randomize seed", value=True)
with gr.Row():
width = gr.Slider(label="Width", minimum=256, maximum=MAX_IMAGE_SIZE, step=32, value=1024)
height = gr.Slider(label="Height", minimum=256, maximum=MAX_IMAGE_SIZE, step=32, value=1024)
with gr.Row():
guidance_scale = gr.Slider(label="Guidance scale", minimum=0.0, maximum=10.0, step=0.1, value=0.0)
num_inference_steps = gr.Slider(label="Number of inference steps", minimum=1, maximum=50, step=1, value=2)
run_button.click(
fn=generate_post,
inputs=[gemini_api_key, news_api_key, logo_url, category, seed, randomize_seed, width, height, guidance_scale, num_inference_steps],
outputs=[result, headline, news_content, seed]
)
if __name__ == "__main__":
demo.launch() |