ans123 commited on
Commit
67b74d5
·
verified ·
1 Parent(s): d6cb6d4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +246 -91
app.py CHANGED
@@ -4,8 +4,17 @@ import time
4
  import gradio as gr
5
  from openai import OpenAI
6
  from pptx import Presentation
7
- from pptx.util import Pt
 
 
 
 
 
 
 
 
8
  from dotenv import load_dotenv
 
9
 
10
  # Load environment variables
11
  load_dotenv()
@@ -16,7 +25,7 @@ if not OPENROUTER_API_KEY:
16
  raise ValueError("OPENROUTER_API_KEY environment variable is not set")
17
 
18
  # OpenRouter API configuration
19
- MODEL_NAME = "meta-llama/llama-3.3-8b-instruct:free"
20
  SITE_URL = "https://proposal-generator.io" # Replace with your actual site URL
21
  SITE_NAME = "Professional Proposal Generator" # Replace with your actual site name
22
 
@@ -26,45 +35,100 @@ client = OpenAI(
26
  api_key=OPENROUTER_API_KEY,
27
  )
28
 
29
- def generate_proposal(description):
30
  """Generate a proposal from a description using OpenRouter API"""
31
- prompt = f"""Create a detailed project proposal with these sections:
32
- 1. Executive Summary
33
- 2. Project Background
34
- 3. Goals and Objectives
35
- 4. Methodology and Approach
36
- 5. Timeline
37
- 6. Budget Considerations
38
- 7. Expected Outcomes
39
- 8. Team and Resources
40
- 9. Risk Assessment
41
- 10. Conclusion
42
-
43
- Include specific details in each section.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
 
45
  Project Description: {description}
46
 
47
- Complete Project Proposal:"""
 
 
48
 
49
  try:
50
  completion = client.chat.completions.create(
51
  extra_headers={
52
- "HTTP-Referer": SITE_URL, # Optional. Site URL for rankings on openrouter.ai.
53
- "X-Title": SITE_NAME, # Optional. Site title for rankings on openrouter.ai.
54
  },
55
  model=MODEL_NAME,
56
  messages=[
57
  {
58
  "role": "system",
59
- "content": "You are a professional business proposal writer with expertise in creating detailed, well-structured project proposals."
60
  },
61
  {
62
  "role": "user",
63
  "content": prompt
64
  }
65
  ],
66
- temperature=0.7,
67
- max_tokens=4000
68
  )
69
 
70
  proposal = completion.choices[0].message.content
@@ -74,91 +138,166 @@ Complete Project Proposal:"""
74
  print(f"Error generating proposal: {e}")
75
  return f"Error generating proposal: {e}"
76
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  def create_slides(proposal):
78
  """Create PowerPoint slides from the proposal"""
79
  prs = Presentation()
80
 
 
 
 
 
 
 
 
 
81
  # Add title slide
82
- title_slide = prs.slides.add_slide(prs.slide_layouts[0])
83
- title_slide.shapes.title.text = "Project Proposal"
84
  subtitle = title_slide.placeholders[1]
85
- subtitle.text = "Generated with AI"
86
 
87
  # List of sections to look for
88
  sections = [
89
  "Executive Summary",
90
  "Project Background",
91
  "Goals and Objectives",
92
- "Methodology",
93
  "Timeline",
94
- "Budget",
95
  "Expected Outcomes",
96
  "Team and Resources",
97
  "Risk Assessment",
98
  "Conclusion"
99
  ]
100
 
101
- # Split text into paragraphs
102
- paragraphs = proposal.split('\n\n')
103
-
104
- # Process each paragraph
105
- current_section = None
106
- current_content = []
107
- found_sections = []
108
 
109
- for para in paragraphs:
110
- para = para.strip()
111
- if not para:
112
- continue
113
-
114
- # Check if this is a section header
115
- is_header = False
116
- for section in sections:
117
- if section.lower() in para.lower() and len(para) < 100:
118
- # Save previous section
119
- if current_section and current_content:
120
- found_sections.append((current_section, current_content))
121
-
122
- # Start new section
123
- current_section = para
124
- current_content = []
125
- is_header = True
126
- break
127
-
128
- if not is_header:
129
- current_content.append(para)
130
-
131
- # Add the last section
132
- if current_section and current_content:
133
- found_sections.append((current_section, current_content))
134
-
135
- # Create slides for each section
136
- for title, content_paras in found_sections:
137
- # Section title slide
138
- section_slide = prs.slides.add_slide(prs.slide_layouts[2])
139
- section_slide.shapes.title.text = title
140
 
141
- # Content slides
142
  current_slide = None
 
143
  paragraphs_on_slide = 0
144
 
145
- for para in content_paras:
 
 
 
 
146
  # Start a new slide if needed
147
- if current_slide is None or paragraphs_on_slide >= 5:
148
- current_slide = prs.slides.add_slide(prs.slide_layouts[1])
149
- current_slide.shapes.title.text = title
150
  text_frame = current_slide.placeholders[1].text_frame
151
  paragraphs_on_slide = 0
152
- else:
153
- text_frame.add_paragraph() # Add a blank line between paragraphs
154
-
155
  # Add the paragraph
156
  p = text_frame.add_paragraph()
157
- p.text = para
158
 
159
- # Basic formatting based on content
160
- if para.startswith("-") or para.startswith("*"):
161
- p.level = 1
 
 
 
 
 
 
 
 
 
 
 
162
 
163
  paragraphs_on_slide += 1
164
 
@@ -167,25 +306,28 @@ def create_slides(proposal):
167
  prs.save(output_path)
168
  return output_path
169
 
170
- def process_input(description):
171
- """Process the input and generate both proposal and slides"""
172
  # Check if input is too short
173
  if len(description.strip()) < 10:
174
- return "Please provide a more detailed project description (at least 10 characters).", None
175
 
176
  # Generate the proposal
177
- proposal = generate_proposal(description)
 
 
 
178
 
179
  # Create the slides
180
  ppt_path = create_slides(proposal)
181
 
182
- return proposal, ppt_path
183
 
184
  # Create Gradio interface
185
  def create_interface():
186
  with gr.Blocks(title="Professional Project Proposal Generator") as app:
187
  gr.Markdown("# Professional Project Proposal Generator")
188
- gr.Markdown("Enter a project description to generate a comprehensive proposal and presentation slides using Meta Llama 3.3.")
189
 
190
  with gr.Row():
191
  with gr.Column(scale=1):
@@ -194,26 +336,39 @@ def create_interface():
194
  placeholder="Describe your project in detail...",
195
  lines=10
196
  )
 
 
 
 
 
 
 
197
  generate_button = gr.Button("Generate Proposal", variant="primary")
198
 
199
  # Examples
200
  examples = gr.Examples(
201
  examples=[
202
- "Develop a cloud-based SaaS platform for performance evaluation in educational institutions and corporate environments.",
203
- "Create a mobile application for sustainable waste management and recycling in urban communities.",
204
- "Design and implement a smart agriculture system using IoT sensors for small-scale farms."
205
  ],
206
- inputs=description_input
207
  )
208
 
209
  with gr.Column(scale=2):
210
- proposal_output = gr.Textbox(label="Generated Proposal", lines=20)
211
- slides_output = gr.File(label="PowerPoint Slides")
 
 
 
 
 
 
212
 
213
  generate_button.click(
214
  process_input,
215
- inputs=description_input,
216
- outputs=[proposal_output, slides_output]
217
  )
218
 
219
  return app
 
4
  import gradio as gr
5
  from openai import OpenAI
6
  from pptx import Presentation
7
+ from pptx.util import Pt, Inches
8
+ from pptx.enum.text import PP_ALIGN
9
+ from pptx.dml.color import RGBColor
10
+ from reportlab.lib.pagesizes import letter
11
+ from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle
12
+ from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
13
+ from reportlab.lib import colors
14
+ from reportlab.lib.units import inch
15
+ from reportlab.lib.enums import TA_CENTER, TA_JUSTIFY
16
  from dotenv import load_dotenv
17
+ import re
18
 
19
  # Load environment variables
20
  load_dotenv()
 
25
  raise ValueError("OPENROUTER_API_KEY environment variable is not set")
26
 
27
  # OpenRouter API configuration
28
+ MODEL_NAME = "meta-llama/llama-3.3-8b-instruct:free" # You can also use more powerful models like "anthropic/claude-3-opus-20240229"
29
  SITE_URL = "https://proposal-generator.io" # Replace with your actual site URL
30
  SITE_NAME = "Professional Proposal Generator" # Replace with your actual site name
31
 
 
35
  api_key=OPENROUTER_API_KEY,
36
  )
37
 
38
+ def generate_proposal(description, project_type=None):
39
  """Generate a proposal from a description using OpenRouter API"""
40
+
41
+ # Create a better prompt with example formatting and detailed instructions
42
+ system_prompt = """You are a professional business proposal writer with expertise in creating detailed, well-structured project proposals.
43
+
44
+ Your proposals are comprehensive, highly detailed, and follow a clear structure with proper formatting. Each section should include substantial content with specific details, bullet points where appropriate, and professional language.
45
+
46
+ Make sure to:
47
+ 1. Include proper formatting with section headings in bold
48
+ 2. Add bullet points for lists and key points
49
+ 3. Include realistic timelines, budgets, and team structures
50
+ 4. Provide concrete, specific details rather than generic statements
51
+ 5. Maintain a professional tone throughout
52
+ 6. Create content that looks like it was written by human experts in the field
53
+
54
+ The proposal must be highly detailed, professionally formatted, and ready for presentation to stakeholders.
55
+ """
56
+
57
+ example_format = """**Project Proposal: [Title based on description]**
58
+
59
+ **1. Executive Summary**
60
+ A comprehensive 3-5 paragraph summary that clearly articulates the project's purpose, key features, benefits, timeline, budget range, and expected outcomes. Include specific metrics and goals.
61
+
62
+ **2. Project Background**
63
+ Detailed explanation of the current situation, market analysis, problems being addressed, and the opportunity. Include specific industry trends, challenges, and the gap this project fills.
64
+
65
+ **3. Goals and Objectives**
66
+ Clearly separated primary goals (broader aims) and specific objectives (measurable targets). Use bullet points for clarity, with each objective being SMART (Specific, Measurable, Achievable, Relevant, Time-bound).
67
+
68
+ **4. Methodology and Approach**
69
+ Detailed explanation of the implementation approach, including specific phases, methodologies, technologies, and frameworks to be used. Outline the specific steps that will be taken.
70
+
71
+ **5. Timeline**
72
+ Specific weekly breakdown of the project with clear milestones, deliverables, and dependencies. Include duration estimates and key decision points.
73
+
74
+ **6. Budget Considerations**
75
+ Detailed budget breakdown with percentages, actual figures, and justifications for each expense category. Include contingency planning and ROI estimates where applicable.
76
+
77
+ **7. Expected Outcomes**
78
+ Comprehensive list of both tangible and intangible outcomes, specific metrics for success, and long-term benefits. Include KPIs that will be used to measure success.
79
+
80
+ **8. Team and Resources**
81
+ Specific team composition with roles, responsibilities, and experience levels. Include external resources, tools, and infrastructure requirements.
82
+
83
+ **9. Risk Assessment**
84
+ Detailed identification of potential risks, probability and impact ratings, and specific mitigation strategies for each risk. Include contingency plans.
85
+
86
+ **10. Conclusion**
87
+ Powerful closing that reinforces the value proposition, summarizes key benefits, and includes a clear call to action."""
88
+
89
+ # Create a project type specific prompt if provided
90
+ project_specific_prompt = ""
91
+ if project_type == "saas_performance":
92
+ project_specific_prompt = """For this SaaS Performance Evaluation Platform, be sure to include:
93
+ - Multi-tenant architecture with role-based access control details
94
+ - User authentication and authorization specifics
95
+ - Dashboard and analytics features with visualization options
96
+ - Evaluation framework customization capabilities
97
+ - Data input methods and integration with external systems
98
+ - Performance tracking and reporting mechanisms
99
+ - Specific technology stack recommendations with justifications
100
+ - Security measures for protecting sensitive performance data
101
+ - Scalability and performance considerations"""
102
+
103
+ prompt = f"""Create a detailed project proposal based on the following description. Format it exactly like the example format provided, with bold section headings and proper structure.
104
+
105
+ {example_format}
106
 
107
  Project Description: {description}
108
 
109
+ {project_specific_prompt}
110
+
111
+ Create a complete, professionally formatted project proposal that could be presented directly to stakeholders. Make each section highly detailed and specific."""
112
 
113
  try:
114
  completion = client.chat.completions.create(
115
  extra_headers={
116
+ "HTTP-Referer": SITE_URL,
117
+ "X-Title": SITE_NAME,
118
  },
119
  model=MODEL_NAME,
120
  messages=[
121
  {
122
  "role": "system",
123
+ "content": system_prompt
124
  },
125
  {
126
  "role": "user",
127
  "content": prompt
128
  }
129
  ],
130
+ temperature=0.5, # Lower temperature for more consistent results
131
+ max_tokens=4500
132
  )
133
 
134
  proposal = completion.choices[0].message.content
 
138
  print(f"Error generating proposal: {e}")
139
  return f"Error generating proposal: {e}"
140
 
141
+ def extract_title(proposal):
142
+ """Extract the title from the proposal"""
143
+ title_match = re.search(r"\*\*Project Proposal: (.*?)\*\*", proposal)
144
+ if title_match:
145
+ return title_match.group(1)
146
+ return "Project Proposal"
147
+
148
+ def create_pdf(proposal, output_path="proposal.pdf"):
149
+ """Create a PDF document from the proposal"""
150
+ doc = SimpleDocTemplate(output_path, pagesize=letter,
151
+ rightMargin=72, leftMargin=72,
152
+ topMargin=72, bottomMargin=72)
153
+
154
+ styles = getSampleStyleSheet()
155
+
156
+ # Create custom styles
157
+ styles.add(ParagraphStyle(name='Title',
158
+ parent=styles['Heading1'],
159
+ fontSize=16,
160
+ alignment=TA_CENTER,
161
+ spaceAfter=20))
162
+
163
+ styles.add(ParagraphStyle(name='SectionHeading',
164
+ parent=styles['Heading2'],
165
+ fontSize=14,
166
+ spaceAfter=12,
167
+ spaceBefore=20))
168
+
169
+ styles.add(ParagraphStyle(name='Normal',
170
+ parent=styles['Normal'],
171
+ fontSize=10,
172
+ alignment=TA_JUSTIFY,
173
+ spaceAfter=10))
174
+
175
+ # Extract title
176
+ title = extract_title(proposal)
177
+
178
+ # Process the proposal content
179
+ story = []
180
+
181
+ # Add title
182
+ story.append(Paragraph(f"<b>Project Proposal: {title}</b>", styles['Title']))
183
+ story.append(Spacer(1, 0.25*inch))
184
+
185
+ # Process sections
186
+ sections = re.split(r'\*\*\d+\.\s+(.*?)\*\*', proposal)
187
+ headers = re.findall(r'\*\*\d+\.\s+(.*?)\*\*', proposal)
188
+
189
+ # The first element in sections is the title area, skip it
190
+ for i, content in enumerate(sections[1:], 0):
191
+ if i < len(headers):
192
+ # Add section header
193
+ story.append(Paragraph(f"<b>{i+1}. {headers[i]}</b>", styles['SectionHeading']))
194
+
195
+ # Process content paragraphs
196
+ paragraphs = content.strip().split('\n\n')
197
+ for para in paragraphs:
198
+ para = para.strip()
199
+ if not para:
200
+ continue
201
+
202
+ # Check if it's a bullet point list
203
+ if re.match(r'^[\*\-]', para):
204
+ # Process bullet points
205
+ bullet_items = re.split(r'\n[\*\-]\s+', para)
206
+ for item in bullet_items:
207
+ item = item.strip()
208
+ if item:
209
+ # Remove leading bullet if present
210
+ item = re.sub(r'^[\*\-]\s+', '', item)
211
+ story.append(Paragraph(f"• {item}", styles['Normal']))
212
+ else:
213
+ # Regular paragraph
214
+ story.append(Paragraph(para, styles['Normal']))
215
+
216
+ # Build the PDF
217
+ doc.build(story)
218
+ return output_path
219
+
220
  def create_slides(proposal):
221
  """Create PowerPoint slides from the proposal"""
222
  prs = Presentation()
223
 
224
+ # Extract title
225
+ title = extract_title(proposal)
226
+
227
+ # Set up slide layouts
228
+ title_slide_layout = prs.slide_layouts[0]
229
+ section_title_layout = prs.slide_layouts[2]
230
+ content_layout = prs.slide_layouts[1]
231
+
232
  # Add title slide
233
+ title_slide = prs.slides.add_slide(title_slide_layout)
234
+ title_slide.shapes.title.text = f"Project Proposal: {title}"
235
  subtitle = title_slide.placeholders[1]
236
+ subtitle.text = "Professional Project Proposal"
237
 
238
  # List of sections to look for
239
  sections = [
240
  "Executive Summary",
241
  "Project Background",
242
  "Goals and Objectives",
243
+ "Methodology and Approach",
244
  "Timeline",
245
+ "Budget Considerations",
246
  "Expected Outcomes",
247
  "Team and Resources",
248
  "Risk Assessment",
249
  "Conclusion"
250
  ]
251
 
252
+ # Extract sections using regex
253
+ section_matches = re.finditer(r'\*\*\d+\.\s+(.*?)\*\*\n\n(.*?)(?=\*\*\d+\.|\Z)',
254
+ proposal, re.DOTALL)
 
 
 
 
255
 
256
+ for match in section_matches:
257
+ section_title = match.group(1)
258
+ section_content = match.group(2).strip()
259
+
260
+ # Add section title slide
261
+ section_slide = prs.slides.add_slide(section_title_layout)
262
+ section_slide.shapes.title.text = section_title
263
+
264
+ # Split content into paragraphs
265
+ paragraphs = section_content.split('\n\n')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
266
 
267
+ # Process each paragraph
268
  current_slide = None
269
+ text_frame = None
270
  paragraphs_on_slide = 0
271
 
272
+ for para in paragraphs:
273
+ para = para.strip()
274
+ if not para:
275
+ continue
276
+
277
  # Start a new slide if needed
278
+ if current_slide is None or paragraphs_on_slide >= 3:
279
+ current_slide = prs.slides.add_slide(content_layout)
280
+ current_slide.shapes.title.text = section_title
281
  text_frame = current_slide.placeholders[1].text_frame
282
  paragraphs_on_slide = 0
283
+
 
 
284
  # Add the paragraph
285
  p = text_frame.add_paragraph()
 
286
 
287
+ # Check if it's a bullet point list
288
+ if re.match(r'^[\*\-]', para):
289
+ # Process bullet points
290
+ bullet_items = re.split(r'\n[\*\-]\s+', para)
291
+ for item in bullet_items:
292
+ item = item.strip()
293
+ if item:
294
+ # Remove leading bullet if present
295
+ item = re.sub(r'^[\*\-]\s+', '', item)
296
+ bullet_p = text_frame.add_paragraph()
297
+ bullet_p.text = item
298
+ bullet_p.level = 1
299
+ else:
300
+ p.text = para
301
 
302
  paragraphs_on_slide += 1
303
 
 
306
  prs.save(output_path)
307
  return output_path
308
 
309
+ def process_input(description, project_type):
310
+ """Process the input and generate both proposal, PDF and slides"""
311
  # Check if input is too short
312
  if len(description.strip()) < 10:
313
+ return "Please provide a more detailed project description (at least 10 characters).", None, None
314
 
315
  # Generate the proposal
316
+ proposal = generate_proposal(description, project_type)
317
+
318
+ # Create the PDF
319
+ pdf_path = create_pdf(proposal)
320
 
321
  # Create the slides
322
  ppt_path = create_slides(proposal)
323
 
324
+ return proposal, pdf_path, ppt_path
325
 
326
  # Create Gradio interface
327
  def create_interface():
328
  with gr.Blocks(title="Professional Project Proposal Generator") as app:
329
  gr.Markdown("# Professional Project Proposal Generator")
330
+ gr.Markdown("Generate comprehensive, professionally formatted project proposals with PDF and PowerPoint exports.")
331
 
332
  with gr.Row():
333
  with gr.Column(scale=1):
 
336
  placeholder="Describe your project in detail...",
337
  lines=10
338
  )
339
+
340
+ project_type = gr.Dropdown(
341
+ label="Project Type",
342
+ choices=["General Project", "SaaS Performance Platform"],
343
+ value="General Project"
344
+ )
345
+
346
  generate_button = gr.Button("Generate Proposal", variant="primary")
347
 
348
  # Examples
349
  examples = gr.Examples(
350
  examples=[
351
+ ["Develop a cloud-based SaaS platform for performance evaluation in educational institutions and corporate environments. The platform will enable users to track, evaluate, and report on individual performance metrics with customizable evaluation models.", "SaaS Performance Platform"],
352
+ ["Create a mobile application for sustainable waste management and recycling in urban communities. The app will connect residents with local recycling centers and provide educational resources on waste reduction.", "General Project"],
353
+ ["Design and implement a smart agriculture system using IoT sensors for small-scale farms. The system will monitor soil conditions, weather patterns, and crop health to optimize irrigation and fertilization.", "General Project"]
354
  ],
355
+ inputs=[description_input, project_type]
356
  )
357
 
358
  with gr.Column(scale=2):
359
+ output_tabs = gr.Tabs()
360
+ with output_tabs:
361
+ with gr.TabItem("Proposal Text"):
362
+ proposal_output = gr.Textbox(label="Generated Proposal", lines=25)
363
+ with gr.TabItem("Documents"):
364
+ with gr.Row():
365
+ pdf_output = gr.File(label="PDF Document")
366
+ slides_output = gr.File(label="PowerPoint Slides")
367
 
368
  generate_button.click(
369
  process_input,
370
+ inputs=[description_input, project_type],
371
+ outputs=[proposal_output, pdf_output, slides_output]
372
  )
373
 
374
  return app