omgy commited on
Commit
aa4596d
·
verified ·
1 Parent(s): 978fc34

Upload 3 files

Browse files
Files changed (3) hide show
  1. Dockerfile +46 -0
  2. app.py +619 -0
  3. requirements.txt +36 -0
Dockerfile ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use Python 3.11 slim image
2
+ FROM python:3.11-slim
3
+
4
+ # Set working directory
5
+ WORKDIR /app
6
+
7
+ # Install system dependencies for WeasyPrint and PDF generation
8
+ RUN apt-get update && apt-get install -y \
9
+ gcc \
10
+ g++ \
11
+ libpango-1.0-0 \
12
+ libpangoft2-1.0-0 \
13
+ libharfbuzz-subset0 \
14
+ libffi-dev \
15
+ libgdk-pixbuf2.0-0 \
16
+ libcairo2 \
17
+ shared-mime-info \
18
+ wkhtmltopdf \
19
+ && rm -rf /var/lib/apt/lists/*
20
+
21
+ # Copy requirements first for better caching
22
+ COPY requirements.txt .
23
+
24
+ # Install Python dependencies
25
+ RUN pip install --no-cache-dir -r requirements.txt
26
+
27
+ # Copy application code
28
+ COPY . .
29
+
30
+ # Create necessary directories
31
+ RUN mkdir -p /tmp/generated_docs
32
+
33
+ # Set environment variables
34
+ ENV FLASK_APP=app.py
35
+ ENV PYTHONUNBUFFERED=1
36
+ ENV PORT=7860
37
+
38
+ # Expose port (Hugging Face uses 7860 by default)
39
+ EXPOSE 7860
40
+
41
+ # Health check
42
+ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
43
+ CMD python -c "import requests; requests.get('http://localhost:7860/health')"
44
+
45
+ # Run the application with gunicorn
46
+ CMD gunicorn --bind 0.0.0.0:7860 --workers 2 --threads 4 --timeout 120 app:app
app.py ADDED
@@ -0,0 +1,619 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Vero Template Generator Backend
3
+ Flask API for generating professional documents using Gemini AI
4
+ """
5
+
6
+ import io
7
+ import os
8
+ import sys
9
+ from datetime import datetime
10
+
11
+ from flask import Flask, jsonify, request, send_file
12
+ from flask_cors import CORS
13
+ from utils.docx_generator import get_docx_generator
14
+ from utils.gemini_client import get_gemini_client
15
+ from utils.pdf_generator import get_pdf_generator
16
+
17
+ # Initialize Flask app
18
+ app = Flask(__name__)
19
+ CORS(app)
20
+
21
+ # Initialize services
22
+ try:
23
+ gemini_client = get_gemini_client()
24
+ docx_generator = get_docx_generator()
25
+ pdf_generator = get_pdf_generator()
26
+ print("✓ All services initialized successfully", file=sys.stderr)
27
+ except Exception as e:
28
+ print(f"✗ Error initializing services: {str(e)}", file=sys.stderr)
29
+ sys.exit(1)
30
+
31
+
32
+ # ============================================================================
33
+ # HEALTH CHECK
34
+ # ============================================================================
35
+
36
+
37
+ @app.route("/health", methods=["GET"])
38
+ def health_check():
39
+ """Health check endpoint"""
40
+ return jsonify(
41
+ {
42
+ "status": "healthy",
43
+ "service": "Vero Template Generator",
44
+ "version": "1.0.0",
45
+ "timestamp": datetime.now().isoformat(),
46
+ "endpoints": [
47
+ "/generate-resume",
48
+ "/generate-cover-letter",
49
+ "/generate-proposal",
50
+ "/generate-invoice",
51
+ "/generate-contract",
52
+ "/generate-portfolio-pdf",
53
+ "/enhance-description",
54
+ "/enhance-skills-summary",
55
+ ],
56
+ }
57
+ )
58
+
59
+
60
+ # ============================================================================
61
+ # RESUME GENERATOR
62
+ # ============================================================================
63
+
64
+
65
+ @app.route("/generate-resume", methods=["POST"])
66
+ def generate_resume():
67
+ """
68
+ Generate professional resume
69
+ Expected JSON:
70
+ {
71
+ "personal_info": {
72
+ "name": "John Doe",
73
+ "email": "john@example.com",
74
+ "phone": "+1234567890",
75
+ "location": "City, State",
76
+ "linkedin": "linkedin.com/in/johndoe",
77
+ "website": "johndoe.com"
78
+ },
79
+ "summary": "Professional summary text",
80
+ "experience": [
81
+ {
82
+ "title": "Senior Developer",
83
+ "company": "Tech Corp",
84
+ "location": "City, State",
85
+ "start_date": "Jan 2020",
86
+ "end_date": "Present",
87
+ "responsibilities": ["Task 1", "Task 2"]
88
+ }
89
+ ],
90
+ "education": [
91
+ {
92
+ "degree": "Bachelor of Science",
93
+ "field": "Computer Science",
94
+ "school": "University Name",
95
+ "graduation_date": "May 2019",
96
+ "gpa": "3.8",
97
+ "honors": "Magna Cum Laude"
98
+ }
99
+ ],
100
+ "skills": ["Python", "JavaScript", "React"],
101
+ "certifications": [
102
+ {
103
+ "name": "AWS Certified",
104
+ "issuer": "Amazon",
105
+ "date": "2023"
106
+ }
107
+ ],
108
+ "projects": [
109
+ {
110
+ "name": "Project Name",
111
+ "description": "Description",
112
+ "technologies": ["Tech1", "Tech2"]
113
+ }
114
+ ],
115
+ "enhance_with_ai": true
116
+ }
117
+ """
118
+ try:
119
+ data = request.get_json()
120
+
121
+ if not data:
122
+ return jsonify({"error": "No data provided"}), 400
123
+
124
+ # Optional: Enhance descriptions with AI
125
+ if data.get("enhance_with_ai", False):
126
+ print("Enhancing resume content with AI...", file=sys.stderr)
127
+
128
+ # Enhance professional summary
129
+ if data.get("summary"):
130
+ skills = data.get("skills", [])
131
+ if isinstance(skills, dict):
132
+ skills = [s for skill_list in skills.values() for s in skill_list]
133
+ data["summary"] = gemini_client.generate_skills_summary(
134
+ skills, data.get("years_experience", 0)
135
+ )
136
+
137
+ # Enhance work experience descriptions
138
+ if data.get("experience"):
139
+ for exp in data["experience"]:
140
+ if exp.get("responsibilities"):
141
+ enhanced_resps = []
142
+ for resp in exp["responsibilities"]:
143
+ try:
144
+ enhanced = gemini_client.enhance_resume_description(
145
+ resp, exp.get("title", "")
146
+ )
147
+ enhanced_resps.append(enhanced)
148
+ except Exception as e:
149
+ print(
150
+ f"Error enhancing responsibility: {str(e)}",
151
+ file=sys.stderr,
152
+ )
153
+ enhanced_resps.append(resp)
154
+ exp["responsibilities"] = enhanced_resps
155
+
156
+ # Enhance project descriptions
157
+ if data.get("projects"):
158
+ for proj in data["projects"]:
159
+ if proj.get("description"):
160
+ try:
161
+ enhanced = gemini_client.enhance_portfolio_description(proj)
162
+ proj["description"] = enhanced
163
+ except Exception as e:
164
+ print(f"Error enhancing project: {str(e)}", file=sys.stderr)
165
+
166
+ # Generate DOCX
167
+ print("Generating resume document...", file=sys.stderr)
168
+ docx_buffer = docx_generator.generate_resume(data)
169
+
170
+ # Prepare filename
171
+ name = data.get("personal_info", {}).get("name", "Resume")
172
+ filename = f"{name.replace(' ', '_')}_Resume.docx"
173
+
174
+ return send_file(
175
+ docx_buffer,
176
+ mimetype="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
177
+ as_attachment=True,
178
+ download_name=filename,
179
+ )
180
+
181
+ except Exception as e:
182
+ print(f"Error generating resume: {str(e)}", file=sys.stderr)
183
+ return jsonify({"error": str(e)}), 500
184
+
185
+
186
+ # ============================================================================
187
+ # COVER LETTER GENERATOR
188
+ # ============================================================================
189
+
190
+
191
+ @app.route("/generate-cover-letter", methods=["POST"])
192
+ def generate_cover_letter():
193
+ """
194
+ Generate personalized cover letter
195
+ Expected JSON:
196
+ {
197
+ "name": "John Doe",
198
+ "address": "123 Main St, City, State",
199
+ "email": "john@example.com",
200
+ "phone": "+1234567890",
201
+ "date": "January 15, 2024",
202
+ "company": "Tech Corp",
203
+ "hiring_manager": "Jane Smith",
204
+ "position": "Senior Developer",
205
+ "skills": ["Python", "React", "AWS"],
206
+ "experience": "5 years of full-stack development",
207
+ "tone": "formal",
208
+ "custom_content": "Optional pre-written content",
209
+ "generate_with_ai": true
210
+ }
211
+ """
212
+ try:
213
+ data = request.get_json()
214
+
215
+ if not data:
216
+ return jsonify({"error": "No data provided"}), 400
217
+
218
+ # Generate content with AI if requested
219
+ if data.get("generate_with_ai", True) and not data.get("custom_content"):
220
+ print("Generating cover letter content with AI...", file=sys.stderr)
221
+ content = gemini_client.generate_cover_letter(data)
222
+ data["content"] = content
223
+ elif data.get("custom_content"):
224
+ data["content"] = data["custom_content"]
225
+ else:
226
+ return (
227
+ jsonify(
228
+ {
229
+ "error": "Either generate_with_ai must be true or custom_content must be provided"
230
+ }
231
+ ),
232
+ 400,
233
+ )
234
+
235
+ # Generate DOCX
236
+ print("Generating cover letter document...", file=sys.stderr)
237
+ docx_buffer = docx_generator.generate_cover_letter(data)
238
+
239
+ # Prepare filename
240
+ name = data.get("name", "Applicant").replace(" ", "_")
241
+ company = data.get("company", "Company").replace(" ", "_")
242
+ filename = f"{name}_CoverLetter_{company}.docx"
243
+
244
+ return send_file(
245
+ docx_buffer,
246
+ mimetype="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
247
+ as_attachment=True,
248
+ download_name=filename,
249
+ )
250
+
251
+ except Exception as e:
252
+ print(f"Error generating cover letter: {str(e)}", file=sys.stderr)
253
+ return jsonify({"error": str(e)}), 500
254
+
255
+
256
+ # ============================================================================
257
+ # PROPOSAL GENERATOR
258
+ # ============================================================================
259
+
260
+
261
+ @app.route("/generate-proposal", methods=["POST"])
262
+ def generate_proposal():
263
+ """
264
+ Generate business proposal
265
+ Expected JSON:
266
+ {
267
+ "title": "Web Development Proposal",
268
+ "client_name": "ABC Company",
269
+ "prepared_by": "Your Company Name",
270
+ "date": "January 15, 2024",
271
+ "project_title": "E-commerce Website",
272
+ "scope": "Develop a full-featured e-commerce platform",
273
+ "deliverables": ["Website", "Admin Panel", "Mobile App"],
274
+ "timeline": "3 months",
275
+ "budget": "$50,000",
276
+ "generate_with_ai": true,
277
+ "custom_content": "Optional pre-written proposal"
278
+ }
279
+ """
280
+ try:
281
+ data = request.get_json()
282
+
283
+ if not data:
284
+ return jsonify({"error": "No data provided"}), 400
285
+
286
+ # Generate proposal content with AI if requested
287
+ if data.get("generate_with_ai", True) and not data.get("custom_content"):
288
+ print("Generating proposal content with AI...", file=sys.stderr)
289
+ content = gemini_client.generate_proposal(data)
290
+ data["content"] = content
291
+ elif data.get("custom_content"):
292
+ data["content"] = data["custom_content"]
293
+
294
+ # Generate DOCX
295
+ print("Generating proposal document...", file=sys.stderr)
296
+ docx_buffer = docx_generator.generate_proposal(data)
297
+
298
+ # Prepare filename
299
+ client = data.get("client_name", "Client").replace(" ", "_")
300
+ title = data.get("project_title", "Proposal").replace(" ", "_")
301
+ filename = f"Proposal_{client}_{title}.docx"
302
+
303
+ return send_file(
304
+ docx_buffer,
305
+ mimetype="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
306
+ as_attachment=True,
307
+ download_name=filename,
308
+ )
309
+
310
+ except Exception as e:
311
+ print(f"Error generating proposal: {str(e)}", file=sys.stderr)
312
+ return jsonify({"error": str(e)}), 500
313
+
314
+
315
+ # ============================================================================
316
+ # INVOICE GENERATOR
317
+ # ============================================================================
318
+
319
+
320
+ @app.route("/generate-invoice", methods=["POST"])
321
+ def generate_invoice():
322
+ """
323
+ Generate professional invoice
324
+ Expected JSON:
325
+ {
326
+ "invoice_number": "INV-001",
327
+ "invoice_date": "2024-01-15",
328
+ "due_date": "2024-02-15",
329
+ "from_info": {
330
+ "name": "Your Business",
331
+ "address": "123 Business St",
332
+ "email": "billing@business.com",
333
+ "phone": "+1234567890"
334
+ },
335
+ "to_info": {
336
+ "name": "Client Name",
337
+ "address": "456 Client Ave",
338
+ "email": "client@example.com"
339
+ },
340
+ "items": [
341
+ {
342
+ "description": "Service/Product",
343
+ "quantity": 1,
344
+ "rate": 1000,
345
+ "amount": 1000
346
+ }
347
+ ],
348
+ "tax_rate": 8.5,
349
+ "discount": 0,
350
+ "notes": "Thank you for your business",
351
+ "payment_instructions": "Payment via bank transfer"
352
+ }
353
+ """
354
+ try:
355
+ data = request.get_json()
356
+
357
+ if not data:
358
+ return jsonify({"error": "No data provided"}), 400
359
+
360
+ # Validate required fields
361
+ if not data.get("items"):
362
+ return jsonify({"error": "Invoice items are required"}), 400
363
+
364
+ # Generate DOCX
365
+ print("Generating invoice document...", file=sys.stderr)
366
+ docx_buffer = docx_generator.generate_invoice(data)
367
+
368
+ # Prepare filename
369
+ invoice_num = data.get("invoice_number", "INV-001").replace("/", "-")
370
+ filename = f"Invoice_{invoice_num}.docx"
371
+
372
+ return send_file(
373
+ docx_buffer,
374
+ mimetype="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
375
+ as_attachment=True,
376
+ download_name=filename,
377
+ )
378
+
379
+ except Exception as e:
380
+ print(f"Error generating invoice: {str(e)}", file=sys.stderr)
381
+ return jsonify({"error": str(e)}), 500
382
+
383
+
384
+ # ============================================================================
385
+ # CONTRACT GENERATOR
386
+ # ============================================================================
387
+
388
+
389
+ @app.route("/generate-contract", methods=["POST"])
390
+ def generate_contract():
391
+ """
392
+ Generate legal contract
393
+ Expected JSON:
394
+ {
395
+ "contract_type": "Freelance Service Agreement",
396
+ "date": "January 15, 2024",
397
+ "party1": {
398
+ "name": "Service Provider",
399
+ "address": "123 Provider St"
400
+ },
401
+ "party2": {
402
+ "name": "Client Name",
403
+ "address": "456 Client Ave"
404
+ },
405
+ "effective_date": "January 20, 2024",
406
+ "expiration_date": "December 31, 2024",
407
+ "custom_terms": "Net 30 payment terms",
408
+ "generate_with_ai": true,
409
+ "custom_content": "Optional pre-written terms"
410
+ }
411
+ """
412
+ try:
413
+ data = request.get_json()
414
+
415
+ if not data:
416
+ return jsonify({"error": "No data provided"}), 400
417
+
418
+ # Generate contract terms with AI if requested
419
+ if data.get("generate_with_ai", True) and not data.get("custom_content"):
420
+ print("Generating contract terms with AI...", file=sys.stderr)
421
+ contract_type = data.get("contract_type", "Service Agreement")
422
+ custom_terms = data.get("custom_terms", "")
423
+ terms = gemini_client.enhance_contract_terms(contract_type, custom_terms)
424
+ data["terms"] = terms
425
+ elif data.get("custom_content"):
426
+ data["terms"] = data["custom_content"]
427
+
428
+ # Generate DOCX
429
+ print("Generating contract document...", file=sys.stderr)
430
+ docx_buffer = docx_generator.generate_contract(data)
431
+
432
+ # Prepare filename
433
+ contract_type = data.get("contract_type", "Contract").replace(" ", "_")
434
+ filename = f"{contract_type}_Contract.docx"
435
+
436
+ return send_file(
437
+ docx_buffer,
438
+ mimetype="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
439
+ as_attachment=True,
440
+ download_name=filename,
441
+ )
442
+
443
+ except Exception as e:
444
+ print(f"Error generating contract: {str(e)}", file=sys.stderr)
445
+ return jsonify({"error": str(e)}), 500
446
+
447
+
448
+ # ============================================================================
449
+ # PORTFOLIO PDF EXPORT
450
+ # ============================================================================
451
+
452
+
453
+ @app.route("/generate-portfolio-pdf", methods=["POST"])
454
+ def generate_portfolio_pdf():
455
+ """
456
+ Generate portfolio PDF
457
+ Expected JSON:
458
+ {
459
+ "name": "John Doe",
460
+ "title": "Full Stack Developer",
461
+ "bio": "Professional bio text",
462
+ "contact": {
463
+ "email": "john@example.com",
464
+ "phone": "+1234567890",
465
+ "website": "johndoe.com",
466
+ "linkedin": "linkedin.com/in/johndoe"
467
+ },
468
+ "skills": ["Python", "React", "AWS"],
469
+ "experience": [...],
470
+ "education": [...],
471
+ "projects": [...],
472
+ "certifications": [...],
473
+ "enhance_with_ai": false
474
+ }
475
+ """
476
+ try:
477
+ data = request.get_json()
478
+
479
+ if not data:
480
+ return jsonify({"error": "No data provided"}), 400
481
+
482
+ # Optional AI enhancement
483
+ if data.get("enhance_with_ai", False):
484
+ print("Enhancing portfolio content with AI...", file=sys.stderr)
485
+
486
+ # Enhance bio
487
+ if data.get("bio"):
488
+ data["bio"] = gemini_client.improve_text_quality(
489
+ data["bio"], "professional"
490
+ )
491
+
492
+ # Enhance project descriptions
493
+ if data.get("projects"):
494
+ for proj in data["projects"]:
495
+ if proj.get("description"):
496
+ try:
497
+ enhanced = gemini_client.enhance_portfolio_description(proj)
498
+ proj["description"] = enhanced
499
+ except Exception as e:
500
+ print(f"Error enhancing project: {str(e)}", file=sys.stderr)
501
+
502
+ # Generate PDF
503
+ print("Generating portfolio PDF...", file=sys.stderr)
504
+ pdf_buffer = pdf_generator.generate_portfolio_pdf(data)
505
+
506
+ # Prepare filename
507
+ name = data.get("name", "Portfolio").replace(" ", "_")
508
+ filename = f"{name}_Portfolio.pdf"
509
+
510
+ return send_file(
511
+ pdf_buffer,
512
+ mimetype="application/pdf",
513
+ as_attachment=True,
514
+ download_name=filename,
515
+ )
516
+
517
+ except Exception as e:
518
+ print(f"Error generating portfolio PDF: {str(e)}", file=sys.stderr)
519
+ return jsonify({"error": str(e)}), 500
520
+
521
+
522
+ # ============================================================================
523
+ # AI ENHANCEMENT UTILITIES
524
+ # ============================================================================
525
+
526
+
527
+ @app.route("/enhance-description", methods=["POST"])
528
+ def enhance_description():
529
+ """
530
+ Enhance text description with AI
531
+ Expected JSON:
532
+ {
533
+ "text": "Original text to enhance",
534
+ "context": "resume/portfolio/proposal",
535
+ "role": "Optional job role for context"
536
+ }
537
+ """
538
+ try:
539
+ data = request.get_json()
540
+
541
+ if not data or not data.get("text"):
542
+ return jsonify({"error": "Text is required"}), 400
543
+
544
+ text = data["text"]
545
+ context = data.get("context", "general")
546
+ role = data.get("role", "")
547
+
548
+ if context == "resume":
549
+ enhanced = gemini_client.enhance_resume_description(text, role)
550
+ elif context == "portfolio":
551
+ project_data = {
552
+ "title": role,
553
+ "description": text,
554
+ "technologies": data.get("technologies", []),
555
+ "role": data.get("your_role", "Developer"),
556
+ }
557
+ enhanced = gemini_client.enhance_portfolio_description(project_data)
558
+ else:
559
+ enhanced = gemini_client.improve_text_quality(text, "professional")
560
+
561
+ return jsonify({"original": text, "enhanced": enhanced, "success": True})
562
+
563
+ except Exception as e:
564
+ print(f"Error enhancing description: {str(e)}", file=sys.stderr)
565
+ return jsonify({"error": str(e)}), 500
566
+
567
+
568
+ @app.route("/enhance-skills-summary", methods=["POST"])
569
+ def enhance_skills_summary():
570
+ """
571
+ Generate professional skills summary
572
+ Expected JSON:
573
+ {
574
+ "skills": ["Python", "React", "AWS"],
575
+ "experience_years": 5
576
+ }
577
+ """
578
+ try:
579
+ data = request.get_json()
580
+
581
+ if not data or not data.get("skills"):
582
+ return jsonify({"error": "Skills list is required"}), 400
583
+
584
+ skills = data["skills"]
585
+ years = data.get("experience_years", 0)
586
+
587
+ summary = gemini_client.generate_skills_summary(skills, years)
588
+
589
+ return jsonify({"skills": skills, "summary": summary, "success": True})
590
+
591
+ except Exception as e:
592
+ print(f"Error generating skills summary: {str(e)}", file=sys.stderr)
593
+ return jsonify({"error": str(e)}), 500
594
+
595
+
596
+ # ============================================================================
597
+ # ERROR HANDLERS
598
+ # ============================================================================
599
+
600
+
601
+ @app.errorhandler(404)
602
+ def not_found(error):
603
+ """Handle 404 errors"""
604
+ return jsonify({"error": "Endpoint not found"}), 404
605
+
606
+
607
+ @app.errorhandler(500)
608
+ def internal_error(error):
609
+ """Handle 500 errors"""
610
+ return jsonify({"error": "Internal server error"}), 500
611
+
612
+
613
+ # ============================================================================
614
+ # MAIN
615
+ # ============================================================================
616
+
617
+ if __name__ == "__main__":
618
+ port = int(os.environ.get("PORT", 7860))
619
+ app.run(host="0.0.0.0", port=port, debug=False)
requirements.txt ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Flask and Web Framework
2
+ Flask==3.0.0
3
+ Flask-CORS==4.0.0
4
+ gunicorn==21.2.0
5
+
6
+ # Google Gemini AI
7
+ google-generativeai==0.3.2
8
+
9
+ # Document Generation
10
+ python-docx==1.1.0
11
+ python-pptx==0.6.23
12
+ Pillow==10.1.0
13
+
14
+ # PDF Generation
15
+ reportlab==4.0.7
16
+ PyPDF2==3.0.1
17
+ weasyprint==60.1
18
+
19
+ # HTML to PDF
20
+ pdfkit==1.0.0
21
+
22
+ # Data Processing
23
+ python-dateutil==2.8.2
24
+ pytz==2023.3
25
+
26
+ # Environment Variables
27
+ python-dotenv==1.0.0
28
+
29
+ # HTTP Requests
30
+ requests==2.31.0
31
+
32
+ # JSON Processing
33
+ jsonschema==4.20.0
34
+
35
+ # Utilities
36
+ python-magic==0.4.27