import gradio as gr import csv import io import json from typing import List, Dict, Any import math def parse_csv_file(file_content: str) -> Dict[str, Any]: """Parse CSV content and extract guest information from name and message columns""" try: # Create a StringIO object to read the CSV csv_file = io.StringIO(file_content) # Read CSV with different possible delimiters for delimiter in [',', ';', '\t']: try: csv_file.seek(0) # Reset file pointer reader = csv.DictReader(csv_file, delimiter=delimiter) # Get the header row headers = reader.fieldnames if not headers or len(headers) < 2: continue # Use the first two columns: name and message name_column = headers[0] message_column = headers[1] # Parse the data and filter out entries with blank names or descriptions guests = [] for i, row in enumerate(reader): name = row.get(name_column, '').strip() title = row.get(message_column, '').strip() # Only add if both name and description are not blank if name and title: guests.append({ 'id': i, 'name': name, 'title': title }) if guests: return {'success': True, 'guests': guests, 'total': len(guests)} except Exception as e: continue return {'success': False, 'error': 'Could not parse CSV file. Please ensure it has at least 2 columns (name and message).'} except Exception as e: return {'success': False, 'error': f'Error parsing CSV: {str(e)}'} def arrange_guests_into_tables(guests: List[Dict]) -> List[List[Dict]]: """Arrange guests into tables of 10 people each with smart distribution""" if not guests: return [] # Categorize guests by industry/role type based on message content categories = { 'tech': ['engineer', 'developer', 'programmer', 'software', 'tech', 'it', 'data', 'ai', 'ml', 'technology', 'scientist'], 'business': ['manager', 'director', 'ceo', 'founder', 'executive', 'business', 'strategy', 'operations', 'consultant', 'product'], 'creative': ['designer', 'creative', 'marketing', 'content', 'writer', 'artist', 'media', 'communications', 'strategist'], 'sales': ['sales', 'account', 'client', 'business development', 'partnership', 'account manager'], 'finance': ['finance', 'accounting', 'investment', 'banking', 'financial', 'analyst', 'cfo'], 'other': [] } categorized_guests = {cat: [] for cat in categories.keys()} # Categorize each guest based on their message/description for guest in guests: title_lower = guest['title'].lower() categorized = False for category, keywords in categories.items(): if category == 'other': continue if any(keyword in title_lower for keyword in keywords): categorized_guests[category].append(guest) categorized = True break if not categorized: categorized_guests['other'].append(guest) # Calculate how many tables we need total_guests = len(guests) num_tables = (total_guests + 9) // 10 # Ceiling division to get number of tables needed # Initialize tables tables = [[] for _ in range(num_tables)] # Distribute guests strategically across all tables # First, distribute major categories evenly major_categories = ['tech', 'business', 'creative', 'sales'] for category in major_categories: guests_in_category = categorized_guests[category] if guests_in_category: # Distribute evenly across all tables for i, guest in enumerate(guests_in_category): table_index = i % num_tables if len(tables[table_index]) < 10: tables[table_index].append(guest) # Then distribute remaining guests (finance, other) remaining_guests = [] for category in ['finance', 'other']: remaining_guests.extend(categorized_guests[category]) # Also add any guests that didn't fit in the first round for table in tables: for guest in guests: if guest not in [g for table_guests in tables for g in table_guests]: if len(table) < 10: table.append(guest) break # Fill remaining slots with any leftover guests for guest in guests: if guest not in [g for table_guests in tables for g in table_guests]: for table in tables: if len(table) < 10: table.append(guest) break return tables def create_circular_table_html(table_number: int, guests: List[Dict]) -> str: """Create HTML for a circular table with guests seated around it""" if not guests: return "" # Calculate positions for seats around the circle num_guests = len(guests) radius = 120 # Radius of the circle center_x, center_y = 150, 150 # Center of the circle # Generate seat positions seats = [] for i in range(num_guests): angle = (2 * 3.14159 * i) / num_guests # Distribute evenly around circle x = center_x + radius * math.cos(angle) y = center_y + radius * math.sin(angle) seats.append((x, y)) # Create HTML for the table html = f"""
Table {table_number}
""" # Add seats around the table for i, (guest, (x, y)) in enumerate(zip(guests, seats)): # Get initials from name initials = ''.join([name[0].upper() for name in guest['name'].split() if name]) if not initials: initials = guest['name'][:2].upper() html += f"""
{initials}
""" html += """
{len(guests)} guests
""" return html def process_csv_and_arrange_tables(csv_content: str) -> str: """Main function to process CSV and arrange tables""" try: # Parse CSV result = parse_csv_file(csv_content) if not result['success']: return f"❌ Error: {result['error']}" guests = result['guests'] total_guests = result['total'] if total_guests == 0: return "❌ No valid guests found in CSV. Please ensure you have at least 2 columns (name and message) with non-empty values." # Arrange tables tables = arrange_guests_into_tables(guests) if not tables: return "❌ No tables could be created." # Generate output with circular tables output = f"🎉 Successfully processed {total_guests} guests!\n\n" output += f"📊 Created {len(tables)} table(s) with smart distribution:\n\n" # Add CSS for styling output += """ """ # Add statistics output += f"""

📈 Table Statistics

Total Guests: {total_guests} | Tables Created: {len(tables)}

""" # Create circular tables output += '
' for i, table in enumerate(tables, 1): output += create_circular_table_html(i, table) output += '
' # Add detailed guest list output += '
' for i, table in enumerate(tables, 1): output += f'

🍽️ Table {i} ({len(table)} guests)

' for j, guest in enumerate(table, 1): output += f'
{j}. {guest["name"]} - {guest["title"]}
' output += '
' output += '
' return output except Exception as e: return f"❌ Error processing request: {str(e)}" def create_sample_csv() -> str: """Create a sample CSV for users to download""" sample_data = """name,message John Smith,Software Engineer at TechCorp Sarah Johnson,Marketing Director at Creative Agency Michael Brown,CEO of StartupXYZ Emily Davis,Data Scientist at AI Labs David Wilson,Product Manager at Innovation Inc Lisa Chen,UX Designer at Design Studio Robert Taylor,Sales Manager at SalesForce Amanda Rodriguez,Financial Analyst at Finance Corp James Lee,Content Strategist at Media Group Jennifer White,Business Development at Growth Co Alex Thompson,Data Engineer at DataFlow Maria Garcia,Creative Director at ArtStudio Chris Anderson,VP of Sales at SalesPro Rachel Kim,Product Designer at DesignHub Tom Wilson,Investment Analyst at Capital Corp""" return sample_data # Create the Gradio interface with gr.Blocks( title="Party Planner - Guest Table Arranger", theme=gr.themes.Soft(), css=""" .gradio-container { max-width: 1400px !important; margin: 0 auto !important; } .main-header { text-align: center; margin-bottom: 2rem; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 2rem; border-radius: 15px; margin-bottom: 2rem; } .sample-csv { background: #f0f8ff; padding: 1rem; border-radius: 8px; margin: 1rem 0; border-left: 4px solid #667eea; } .input-section { background: white; padding: 20px; border-radius: 10px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); margin-bottom: 20px; } """ ) as demo: gr.HTML("""

🎉 Party Planner - Guest Table Arranger

Upload your guest list CSV and let AI arrange them into optimal circular table seating!

""") with gr.Row(): with gr.Column(scale=1): gr.HTML("""

📋 How to use:

  1. Prepare a CSV file with 2 columns: name and message/description
  2. Upload your CSV file below
  3. Click "Arrange Tables" to see the smart circular seating arrangement

📄 Sample CSV Format:

name,message
John Smith,Software Engineer at TechCorp
Sarah Johnson,Marketing Director at Creative Agency
Michael Brown,CEO of StartupXYZ
""") sample_csv = gr.Textbox( label="Sample CSV Content", value=create_sample_csv(), lines=10, interactive=False ) download_sample = gr.Button("📥 Download Sample CSV", variant="secondary") with gr.Column(scale=2): gr.HTML("""

📁 Upload Your Guest List

""") csv_input = gr.Textbox( label="📁 Paste your CSV content here (or upload file below)", placeholder="Paste your CSV content here...", lines=10 ) file_input = gr.File( label="📂 Or upload CSV file", file_types=[".csv"], file_count="single" ) arrange_btn = gr.Button("🎯 Arrange Tables", variant="primary", size="lg") output = gr.HTML( label="📊 Table Arrangement Results", value="

Upload your guest list to see the circular table arrangement!

🎉 Your tables will appear as beautiful circles with guests seated around them

" ) # Event handlers def handle_file_upload(file): if file is None: return "" try: with open(file.name, 'r', encoding='utf-8') as f: content = f.read() return content except Exception as e: return f"Error reading file: {str(e)}" def download_sample_csv(): return create_sample_csv() # Connect events file_input.change( fn=handle_file_upload, inputs=[file_input], outputs=[csv_input] ) arrange_btn.click( fn=process_csv_and_arrange_tables, inputs=[csv_input], outputs=[output] ) download_sample.click( fn=download_sample_csv, outputs=[csv_input] ) # Launch the app if __name__ == "__main__": demo.launch()