import os import sys import time import gradio as gr from openai import OpenAI from pptx import Presentation from pptx.util import Pt from dotenv import load_dotenv # Load environment variables load_dotenv() # Get API key from environment variable OPENROUTER_API_KEY = os.getenv("OPENROUTER_API_KEY") if not OPENROUTER_API_KEY: raise ValueError("OPENROUTER_API_KEY environment variable is not set") # OpenRouter API configuration MODEL_NAME = "meta-llama/llama-3.3-8b-instruct:free" SITE_URL = "https://proposal-generator.io" # Replace with your actual site URL SITE_NAME = "Professional Proposal Generator" # Replace with your actual site name # Initialize OpenAI client for OpenRouter client = OpenAI( base_url="https://openrouter.ai/api/v1", api_key=OPENROUTER_API_KEY, ) def generate_proposal(description): """Generate a proposal from a description using OpenRouter API""" prompt = f"""Create a detailed project proposal with these sections: 1. Executive Summary 2. Project Background 3. Goals and Objectives 4. Methodology and Approach 5. Timeline 6. Budget Considerations 7. Expected Outcomes 8. Team and Resources 9. Risk Assessment 10. Conclusion Include specific details in each section. Project Description: {description} Complete Project Proposal:""" try: completion = client.chat.completions.create( extra_headers={ "HTTP-Referer": SITE_URL, # Optional. Site URL for rankings on openrouter.ai. "X-Title": SITE_NAME, # Optional. Site title for rankings on openrouter.ai. }, model=MODEL_NAME, messages=[ { "role": "system", "content": "You are a professional business proposal writer with expertise in creating detailed, well-structured project proposals." }, { "role": "user", "content": prompt } ], temperature=0.7, max_tokens=4000 ) proposal = completion.choices[0].message.content return proposal except Exception as e: print(f"Error generating proposal: {e}") return f"Error generating proposal: {e}" def create_slides(proposal): """Create PowerPoint slides from the proposal""" prs = Presentation() # Add title slide title_slide = prs.slides.add_slide(prs.slide_layouts[0]) title_slide.shapes.title.text = "Project Proposal" subtitle = title_slide.placeholders[1] subtitle.text = "Generated with AI" # List of sections to look for sections = [ "Executive Summary", "Project Background", "Goals and Objectives", "Methodology", "Timeline", "Budget", "Expected Outcomes", "Team and Resources", "Risk Assessment", "Conclusion" ] # Split text into paragraphs paragraphs = proposal.split('\n\n') # Process each paragraph current_section = None current_content = [] found_sections = [] for para in paragraphs: para = para.strip() if not para: continue # Check if this is a section header is_header = False for section in sections: if section.lower() in para.lower() and len(para) < 100: # Save previous section if current_section and current_content: found_sections.append((current_section, current_content)) # Start new section current_section = para current_content = [] is_header = True break if not is_header: current_content.append(para) # Add the last section if current_section and current_content: found_sections.append((current_section, current_content)) # Create slides for each section for title, content_paras in found_sections: # Section title slide section_slide = prs.slides.add_slide(prs.slide_layouts[2]) section_slide.shapes.title.text = title # Content slides current_slide = None paragraphs_on_slide = 0 for para in content_paras: # Start a new slide if needed if current_slide is None or paragraphs_on_slide >= 5: current_slide = prs.slides.add_slide(prs.slide_layouts[1]) current_slide.shapes.title.text = title text_frame = current_slide.placeholders[1].text_frame paragraphs_on_slide = 0 else: text_frame.add_paragraph() # Add a blank line between paragraphs # Add the paragraph p = text_frame.add_paragraph() p.text = para # Basic formatting based on content if para.startswith("-") or para.startswith("*"): p.level = 1 paragraphs_on_slide += 1 # Save the presentation output_path = "proposal_slides.pptx" prs.save(output_path) return output_path def process_input(description): """Process the input and generate both proposal and slides""" # Check if input is too short if len(description.strip()) < 10: return "Please provide a more detailed project description (at least 10 characters).", None # Generate the proposal proposal = generate_proposal(description) # Create the slides ppt_path = create_slides(proposal) return proposal, ppt_path # Create Gradio interface def create_interface(): with gr.Blocks(title="Professional Project Proposal Generator") as app: gr.Markdown("# Professional Project Proposal Generator") gr.Markdown("Enter a project description to generate a comprehensive proposal and presentation slides using Meta Llama 3.3.") with gr.Row(): with gr.Column(scale=1): description_input = gr.Textbox( label="Project Description", placeholder="Describe your project in detail...", lines=10 ) generate_button = gr.Button("Generate Proposal", variant="primary") # Examples examples = gr.Examples( examples=[ "Develop a cloud-based SaaS platform for performance evaluation in educational institutions and corporate environments.", "Create a mobile application for sustainable waste management and recycling in urban communities.", "Design and implement a smart agriculture system using IoT sensors for small-scale farms." ], inputs=description_input ) with gr.Column(scale=2): proposal_output = gr.Textbox(label="Generated Proposal", lines=20) slides_output = gr.File(label="PowerPoint Slides") generate_button.click( process_input, inputs=description_input, outputs=[proposal_output, slides_output] ) return app # Main script code if __name__ == "__main__": print("Starting Gradio interface...") app = create_interface() app.launch(share=True)