Spaces:
Sleeping
Sleeping
""" | |
Gradio web interface for the Logo Downloader | |
""" | |
import os | |
import gradio as gr | |
import logging | |
from pathlib import Path | |
from typing import Optional | |
from services.logo_downloader import LogoDownloader | |
from services.appconfig import GEMINI_API_KEY, DEFAULT_LOGOS_PER_ENTITY, MAX_LOGOS_PER_ENTITY | |
# Setup logging | |
logging.basicConfig(level=logging.INFO) | |
logger = logging.getLogger(__name__) | |
def process_text_request(text: str, api_key: Optional[str], num_logos: int = DEFAULT_LOGOS_PER_ENTITY): | |
""" | |
Process text and download logos through Gradio interface | |
Args: | |
text (str): Input text | |
api_key (str): Optional Gemini API key | |
num_logos (int): Number of logos per entity | |
Returns: | |
Tuple: (status_message, zip_file_path or None, detailed_results) | |
""" | |
try: | |
# Validate inputs | |
if not text or not text.strip(): | |
return "β Please provide some text to analyze.", None, "No text provided." | |
if num_logos < 1 or num_logos > MAX_LOGOS_PER_ENTITY: | |
return f"β Number of logos must be between 1 and {MAX_LOGOS_PER_ENTITY}.", None, f"Invalid number: {num_logos}" | |
# Use provided API key or environment variable | |
final_api_key = api_key.strip() if api_key and api_key.strip() else GEMINI_API_KEY | |
# Initialize downloader | |
downloader = LogoDownloader(gemini_api_key=final_api_key) | |
# Process the text | |
results = downloader.process_text(text, num_logos) | |
# Format response based on results | |
if results['status'] == 'success' and results['stats']['total_downloads'] > 0: | |
status_msg = f"β {downloader.get_stats_summary()}" | |
zip_path = results.get('zip_path') | |
# Create detailed results | |
detailed_results = _format_detailed_results(results) | |
return status_msg, zip_path, detailed_results | |
elif results['status'] == 'warning': | |
return f"β οΈ {results['message']}", None, results.get('message', 'No details available') | |
else: | |
return f"β Processing failed: {results['message']}", None, results.get('message', 'Unknown error') | |
except Exception as e: | |
logger.error(f"Error in process_text_request: {e}") | |
return f"β An error occurred: {str(e)}", None, f"Error details: {str(e)}" | |
def _format_detailed_results(results): | |
"""Format detailed results for display""" | |
if not results.get('results'): | |
return "No detailed results available." | |
details = [] | |
details.append(f"π **Processing Summary:**") | |
details.append(f"- Total entities found: {results['stats']['total_entities']}") | |
details.append(f"- Total logos downloaded: {results['stats']['total_downloads']}") | |
details.append(f"- Successful entities: {results['stats']['successful_entities']}") | |
details.append(f"- Failed entities: {results['stats']['failed_entities']}") | |
details.append("") | |
details.append("π **Entity Details:**") | |
for result in results['results']: | |
entity = result['entity'] | |
count = result['downloaded_count'] | |
if count > 0: | |
details.append(f"β **{entity}**: {count} logos downloaded") | |
else: | |
error_msg = result.get('error', 'No logos found') | |
details.append(f"β **{entity}**: Failed ({error_msg})") | |
return "\n".join(details) | |
def create_interface(): | |
"""Create and configure Gradio interface""" | |
# Custom CSS for better styling | |
css = """ | |
.gradio-container { | |
max-width: 1200px !important; | |
margin: auto !important; | |
} | |
.main-header { | |
text-align: center; | |
margin-bottom: 2rem; | |
} | |
.status-success { | |
color: #10b981 !important; | |
} | |
.status-error { | |
color: #ef4444 !important; | |
} | |
.status-warning { | |
color: #f59e0b !important; | |
} | |
""" | |
with gr.Blocks(css=css, title="Logo Downloader", theme=gr.themes.Soft()) as interface: | |
# Header | |
gr.HTML(""" | |
<div class="main-header"> | |
<h1>π¨ Logo Downloader</h1> | |
<p>Extract entities from text and download their logos automatically</p> | |
</div> | |
""") | |
with gr.Row(): | |
with gr.Column(scale=2): | |
# Input section | |
gr.Markdown("## π Input") | |
text_input = gr.Textbox( | |
label="Text to analyze", | |
placeholder="Enter text containing company names, products, or brands (e.g., 'We use AWS, Docker, React, and Adobe Photoshop for our projects')", | |
lines=5, | |
max_lines=10 | |
) | |
with gr.Row(): | |
api_key_input = gr.Textbox( | |
label="Gemini API Key (optional)", | |
placeholder="Enter your Gemini API key for better entity extraction", | |
type="password", | |
value="" | |
) | |
num_logos_input = gr.Slider( | |
label="Logos per entity", | |
minimum=1, | |
maximum=MAX_LOGOS_PER_ENTITY, | |
value=DEFAULT_LOGOS_PER_ENTITY, | |
step=1 | |
) | |
process_btn = gr.Button("π Download Logos", variant="primary", size="lg") | |
# API key help | |
gr.Markdown(""" | |
π‘ **Tip:** Get a free Gemini API key at [Google AI Studio](https://makersuite.google.com/app/apikey) for better entity extraction. | |
Without an API key, the tool will use basic pattern matching. | |
""") | |
with gr.Column(scale=1): | |
# Output section | |
gr.Markdown("## π Results") | |
status_output = gr.Textbox( | |
label="Status", | |
interactive=False, | |
lines=2 | |
) | |
download_output = gr.File( | |
label="Download ZIP", | |
interactive=False | |
) | |
detailed_output = gr.Textbox( | |
label="Detailed Results", | |
interactive=False, | |
lines=10, | |
max_lines=15 | |
) | |
# Examples section | |
gr.Markdown("## π‘ Examples") | |
examples = [ | |
[ | |
"Our tech stack includes React, Node.js, MongoDB, Docker, AWS, and we use Figma for design, along with GitHub for version control.", | |
"", | |
8 | |
], | |
[ | |
"The team uses Microsoft Office, Adobe Creative Suite, Slack for communication, Zoom for meetings, and Salesforce for CRM.", | |
"", | |
6 | |
], | |
[ | |
"Popular social media platforms like Instagram, TikTok, Twitter, LinkedIn, and YouTube are essential for digital marketing.", | |
"", | |
5 | |
] | |
] | |
gr.Examples( | |
examples=examples, | |
inputs=[text_input, api_key_input, num_logos_input], | |
outputs=[status_output, download_output, detailed_output], | |
fn=process_text_request, | |
cache_examples=False | |
) | |
# Process button click event | |
process_btn.click( | |
fn=process_text_request, | |
inputs=[text_input, api_key_input, num_logos_input], | |
outputs=[status_output, download_output, detailed_output], | |
show_progress='minimal' | |
) | |
# Footer | |
gr.HTML(""" | |
<div style="text-align: center; margin-top: 2rem; padding: 1rem; border-top: 1px solid #e5e7eb;"> | |
<p>π§ Built with Gradio | π€ Powered by Gemini AI</p> | |
<p><small>This tool respects rate limits and downloads publicly available logos.</small></p> | |
</div> | |
""") | |
return interface | |
def main(): | |
"""Main function to launch the application""" | |
logger.info("Starting Logo Downloader application...") | |
# Check for API key | |
if not GEMINI_API_KEY: | |
logger.warning("No Gemini API key found in environment variables") | |
logger.info("The application will work with fallback entity extraction") | |
else: | |
logger.info("Gemini API key found") | |
# Create and launch interface | |
interface = create_interface() | |
# Launch configuration | |
launch_kwargs = { | |
"server_name": "0.0.0.0", | |
"server_port": int(os.environ.get("PORT", 7860)), | |
"share": False, | |
"show_error": True, | |
"max_threads": 4 | |
} | |
# Launch the interface | |
interface.launch(**launch_kwargs) | |
if __name__ == "__main__": | |
main() |