Spaces:
Sleeping
Sleeping
File size: 9,133 Bytes
2c01a8f |
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 |
"""
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() |