Spaces:
Sleeping
Sleeping
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) |