Nirav Madhani commited on
Commit
9f2d44c
·
1 Parent(s): 1cff7cd

feat: Add CV Markdown to PDF converter with MCP integration

Browse files

- Implement Gradio-based web application for converting markdown to PDF
- Add MCP function registration for AI assistant integration
- Include sample CV and formatting instructions
- Fix lambda registration issue and use API base URL from environment variable
- Update README with detailed project documentation
- Configure proper requirements and gitignore files

Files changed (6) hide show
  1. .gitignore +7 -0
  2. Instructions.md +110 -0
  3. README.md +13 -1
  4. Sample.md +58 -0
  5. app.py +260 -0
  6. requirements.txt +0 -0
.gitignore ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ .env
2
+ *.pyc
3
+ __pycache__/
4
+ .DS_Store
5
+ *.pdf
6
+ *.backup
7
+ Task.md
Instructions.md ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 📋 CV Formatting Instructions
2
+
3
+ ## YAML Front Matter (Required)
4
+ Start your CV with YAML metadata enclosed in triple dashes:
5
+ ```yaml
6
+ ---
7
+ name: Your Full Name
8
+ header:
9
+ - text: |
10
+ <span style="font-size: 1.2em; font-weight: bold;">Your Job Title</span>
11
+ - text: <span class="iconify" data-icon="tabler:phone"></span> (555) 123-4567
12
+ newLine: true
13
+ - text: <span class="iconify" data-icon="tabler:mail"></span> your.email@domain.com
14
+ link: mailto:your.email@domain.com
15
+ - text: <span class="iconify" data-icon="tabler:brand-linkedin"></span> LinkedIn
16
+ link: https://linkedin.com/in/yourprofile
17
+ - text: <span class="iconify" data-icon="tabler:brand-github"></span> GitHub
18
+ link: https://github.com/yourusername
19
+ ---
20
+ ```
21
+
22
+ ## Special Formatting Tags
23
+
24
+ ### Level 2 Headers (Company/Institution Names)
25
+ - Use `[L2]Company Name[/L2]` for company names
26
+ - Use `[L2R]Location[/L2R]` for right-aligned location information
27
+ - Example: `[L2]Example Corp[/L2] [L2R]City, State[/L2R]`
28
+
29
+ ### Level 3 Headers (Job Titles/Degrees)
30
+ - Use `[L3]Job Title[/L3]` for job titles or degree names
31
+ - Use `[L3R]Date Range[/L3R]` for right-aligned date information
32
+ - Example: `[L3]Senior Software Engineer[/L3] [L3R]Oct 2020 - Present[/L3R]`
33
+
34
+ ## Section Structure
35
+
36
+ ### Experience Section
37
+ ```markdown
38
+ ## Experience
39
+
40
+ [L2]Company Name[/L2] [L2R]City, State[/L2R]
41
+
42
+ [L3]Job Title[/L3] [L3R]Start Date - End Date[/L3R]
43
+
44
+ - Bullet point describing achievement or responsibility
45
+ - Another bullet point with specific impact
46
+ - Use action verbs and quantify results when possible
47
+ ```
48
+
49
+ ### Education Section
50
+ ```markdown
51
+ ## Education
52
+
53
+ [L2]University Name[/L2] GPA X.XX [L2R]City, State[/L2R]
54
+ [L3]Degree Name[/L3] [L3R]Start Year - End Year[/L3R]
55
+ ```
56
+
57
+ ### Skills Section
58
+ Use HTML `<br>` tags for line breaks and organize by categories:
59
+ ```markdown
60
+ ## Skills
61
+
62
+ **Category 1:** Skill1, Skill2, Skill3, <strong>Highlighted Skill</strong>
63
+ <br>
64
+ **Category 2:** More skills here
65
+ <br>
66
+ **Category 3:** Additional skills
67
+ ```
68
+
69
+ ### Certifications Section
70
+ ```markdown
71
+ ## Certifications
72
+
73
+ - Certificate Name [<span class="iconify" data-icon="mdi:open-in-new"></span>](certificate-url)
74
+ - Certificate without link
75
+ ```
76
+
77
+ ## Icons and Styling
78
+
79
+ ### Contact Icons
80
+ - Phone: `<span class="iconify" data-icon="tabler:phone"></span>`
81
+ - Email: `<span class="iconify" data-icon="tabler:mail"></span>`
82
+ - LinkedIn: `<span class="iconify" data-icon="tabler:brand-linkedin"></span>`
83
+ - GitHub: `<span class="iconify" data-icon="tabler:brand-github"></span>`
84
+
85
+ ### External Link Icon
86
+ - Use: `<span class="iconify" data-icon="mdi:open-in-new"></span>`
87
+
88
+ ### Text Styling
89
+ - **Bold text:** Use `**text**` for category labels
90
+ - *Emphasized text:* Use `<strong>text</strong>` for highlighting specific skills
91
+ - Job titles should be styled with the [L3] tags, not markdown headers
92
+
93
+ ## Best Practices
94
+
95
+ 1. **Consistency:** Always use the same formatting patterns throughout
96
+ 2. **Alignment:** Use L2R and L3R tags for right-aligned content (dates, locations)
97
+ 3. **Icons:** Include relevant icons for contact information and external links
98
+ 4. **Bullet Points:** Use concise, action-oriented bullet points for experience
99
+ 5. **Categorization:** Group skills by relevant categories
100
+ 6. **Links:** Include clickable links for email, social profiles, and certificates
101
+ 7. **Spacing:** Use proper section breaks with `##` headers
102
+
103
+ ## Required Sections
104
+ 1. **YAML Front Matter** (name and header contact info)
105
+ 2. **Experience** (with L2/L3 formatting)
106
+ 3. **Education** (with L2/L3 formatting)
107
+ 4. **Skills** (categorized with HTML breaks)
108
+ 5. **Certifications** (optional but recommended)
109
+
110
+ This formatting ensures your CV will render properly in the PDF conversion system with consistent styling and professional appearance.
README.md CHANGED
@@ -9,4 +9,16 @@ app_file: app.py
9
  pinned: false
10
  ---
11
 
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  pinned: false
10
  ---
11
 
12
+ # 📄 CV MCP - Markdown to PDF Converter
13
+
14
+ A Gradio-based web application that converts markdown text to PDF using an external API service. This app provides a clean, two-panel interface where users can input markdown on the left and receive a professionally formatted PDF on the right.
15
+
16
+ ## 🌟 Features
17
+
18
+ - **Two-Panel Interface**: Clean split layout with markdown input on the left and PDF output on the right
19
+ - **Real-time Conversion**: Click "Convert to PDF" button to process your markdown
20
+ - **External API Integration**: Uses the Nirav Madhani Resume Server API for HTML conversion
21
+ - **PDF Generation**: Converts API-returned HTML to PDF using xhtml2pdf library
22
+ - **Example Templates**: Pre-built markdown examples for quick testing
23
+ - **Responsive Design**: Modern, user-friendly interface built with Gradio
24
+
Sample.md ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ name: Jane Smith
3
+ header:
4
+ - text: |
5
+ <span style="font-size: 1.2em; font-weight: bold;">Software Engineer</span>
6
+ - text: <span class="iconify" data-icon="tabler:phone"></span> (555) 123-4567
7
+ newLine: true
8
+ - text: <span class="iconify" data-icon="tabler:mail"></span> fname.lastname@email.com
9
+ link: mailto:jane.smith@email.com
10
+ - text: <span class="iconify" data-icon="tabler:brand-linkedin"></span> LinkedIn
11
+ link: https://linkedin.com/in/firstnamelastname
12
+ - text: <span class="iconify" data-icon="tabler:brand-github"></span> GitHub
13
+ link: https://github.com/firstnamelastname
14
+ ---
15
+
16
+ ## Experience
17
+
18
+ [L2]Example Corp[/L2] [L2R]City, State[/L2R]
19
+
20
+ [L3]Senior Software Engineer[/L3] [L3R]Oct 2020 - Present[/L3R]
21
+
22
+ - Developed and maintained critical systems.
23
+ - Led a team of junior developers.
24
+
25
+ [L3]Junior Software Engineer[/L3] [L3R]Jan 2018 - Oct 2020[/L3R]
26
+
27
+ - Developed and maintained critical systems.
28
+ - Led a team of junior developers.
29
+
30
+ ## Education
31
+
32
+ [L2]State University[/L2] GPA 3.75 [L2R]Anytown, USA[/L2R]
33
+ [L3]B.S. in Computer Science[/L3] [L3R]2012 - 2016[/L3R]
34
+
35
+ ## Skills
36
+
37
+ **Programming Languages:** Python, Java, JavaScript/TypeScript, C++, Go, SQL, C#
38
+ <br>
39
+ **Frameworks/Libraries:** Spring Boot, React (Hooks), Node.js (Express.js), FastAPI, Django/Flask, Pandas, NumPy, TensorFlow, Keras, MXNet, LangChain, Unity, <strong>SMOL Agents</strong>
40
+ <br>
41
+ **Databases & Caching:** PostgreSQL, MySQL, MongoDB, Redis, Elasticsearch, Pinecone (Vector DBs), Azure SQL
42
+ <br>
43
+ **Cloud & DevOps:** Azure (App Service, AKS, AI Services, Monitor, VNet), AWS, GCP, Docker, Kubernetes, Terraform, CI/CD (GitHub Actions), IaC
44
+ <br>
45
+ **Machine Learning & AI:** LLMs, NLP, RAG, Prompt Engineering, Semantic Search, Generative AI, Deep Learning (CNN, GAN, ResNet, SRGAN), TensorFlow, Keras, MXNet, Spark, MLOps
46
+ <br>
47
+ **APIs & Communication:** RESTful APIs, OAuth2, JWT, gRPC, GraphQL
48
+ <br>
49
+ **Tools & Methodologies:** Git, Agile (Scrum), Jira, TDD, Performance Optimization, Scalability, GitHub Copilot, Playwright, Snyk, bs4, lxml
50
+
51
+ ## Certifications
52
+
53
+ - Certificate 1 [<span class="iconify" data-icon="mdi:open-in-new"></span>](https://certificates.example.com/certificate-1)
54
+ - Certificate 2
55
+ - Certificate 3 [<span class="iconify" data-icon="mdi:open-in-new"></span>](https://certificates.example.com/certificate-3)
56
+ - Certificate 4 [<span class="iconify" data-icon="mdi:open-in-new"></span>](https://certificates.example.com/certificate-4)
57
+ - Certificate 5 [<span class="iconify" data-icon="mdi:open-in-new"></span>](https://certificates.example.com/certificate-5)
58
+ - Certificate 6 [<span class="iconify" data-icon="mdi:open-in-new"></span>](https://certificates.example.com/certificate-6)
app.py ADDED
@@ -0,0 +1,260 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import requests
3
+ import os
4
+ from dotenv import load_dotenv
5
+ import tempfile
6
+
7
+ # Load environment variables
8
+ load_dotenv()
9
+
10
+ def get_sample_cv():
11
+ """
12
+ Return the sample CV markdown content for reference
13
+ """
14
+ try:
15
+ with open('Sample.md', 'r', encoding='utf-8') as f:
16
+ return f.read()
17
+ except FileNotFoundError:
18
+ return "Sample.md file not found in the current directory."
19
+ except Exception as e:
20
+ return f"Error reading Sample.md: {str(e)}"
21
+
22
+ def get_cv_formatting_instructions():
23
+ """
24
+ Return detailed CV formatting instructions from external markdown file
25
+ """
26
+ try:
27
+ with open('Instructions.md', 'r', encoding='utf-8') as f:
28
+ return f.read()
29
+ except FileNotFoundError:
30
+ return "Instructions.md file not found in the current directory."
31
+ except Exception as e:
32
+ return f"Error reading Instructions.md: {str(e)}"
33
+
34
+ def convert_markdown_to_pdf(markdown_text):
35
+ """
36
+ Convert markdown text to PDF and HTML using the external API endpoints
37
+
38
+ Args:
39
+ markdown_text (str): The markdown text to convert
40
+
41
+ Returns:
42
+ tuple: (pdf_path, html_content, status_message)
43
+ """
44
+ if not markdown_text.strip():
45
+ return None, "", "Please enter some markdown text."
46
+
47
+ # Get bearer token from environment
48
+ bearer_token = os.getenv('BEARER_TOKEN')
49
+ if not bearer_token or bearer_token == 'your_bearer_token_here':
50
+ return None, "", "❌ Bearer token not configured. Please set BEARER_TOKEN in .env file."
51
+
52
+ try:
53
+ headers = {
54
+ 'Authorization': f'Bearer {bearer_token}',
55
+ 'Content-Type': 'text/markdown'
56
+ }
57
+
58
+ # Get base URL from environment
59
+ base_url = os.getenv('API_BASE_URL', 'https://nirav-madhani-resume-server.hf.space')
60
+
61
+ # Get PDF directly from API
62
+ pdf_url = f"{base_url}/convert/pdf"
63
+ print(f"📡 Making request to {pdf_url}")
64
+ pdf_response = requests.post(pdf_url, data=markdown_text, headers=headers, timeout=30)
65
+
66
+ if pdf_response.status_code != 200:
67
+ return None, "", f"❌ PDF API request failed with status {pdf_response.status_code}: {pdf_response.text}"
68
+
69
+ # Save PDF to temporary file
70
+ with tempfile.NamedTemporaryFile(delete=False, suffix='.pdf', mode='w+b') as temp_pdf:
71
+ temp_pdf.write(pdf_response.content)
72
+ pdf_path = temp_pdf.name
73
+
74
+ # Get HTML for preview
75
+ html_url = f"{base_url}/convert/html"
76
+ print(f"📡 Making request to {html_url}")
77
+ html_response = requests.post(html_url, data=markdown_text, headers=headers, timeout=30)
78
+
79
+ if html_response.status_code != 200:
80
+ # PDF worked but HTML failed - still return PDF
81
+ return pdf_path, "", f"✅ PDF generated successfully! (HTML preview failed: {html_response.status_code})"
82
+
83
+ html_content = html_response.text
84
+ return pdf_path, html_content, "✅ PDF and HTML generated successfully via API!"
85
+
86
+ except requests.exceptions.RequestException as e:
87
+ return None, "", f"❌ Network error: {str(e)}"
88
+ except Exception as e:
89
+ return None, "", f"❌ Error generating PDF: {str(e)}"
90
+
91
+ def process_conversion(markdown_text):
92
+ """
93
+ Process the markdown conversion and return results for Gradio interface
94
+
95
+ Args:
96
+ markdown_text (str): The markdown text to convert
97
+
98
+ Returns:
99
+ tuple: (pdf_file_path, html_content, status_message)
100
+ """
101
+ pdf_path, html_content, message = convert_markdown_to_pdf(markdown_text)
102
+ return pdf_path, html_content, message
103
+
104
+ # MCP Tool Functions (callable by AI assistants)
105
+ def mcp_get_sample_cv():
106
+ """MCP tool: Get sample CV markdown
107
+
108
+ Returns:
109
+ str: The sample CV markdown content
110
+ """
111
+ return get_sample_cv()
112
+
113
+ def mcp_get_cv_instructions():
114
+ """MCP tool: Get CV formatting instructions
115
+
116
+ Returns:
117
+ str: The CV formatting instructions
118
+ """
119
+ return get_cv_formatting_instructions()
120
+
121
+ def mcp_convert_cv(markdown_text: str):
122
+ """MCP tool: Convert CV markdown to PDF
123
+
124
+ Args:
125
+ markdown_text (str): The markdown text to convert to PDF
126
+
127
+ Returns:
128
+ str: The conversion result message
129
+ """
130
+ pdf_path, html_content, message = process_conversion(markdown_text)
131
+ return f"Conversion result: {message}"
132
+
133
+ # Create Gradio interface
134
+ with gr.Blocks(title="CV Markdown to PDF Converter", theme=gr.themes.Soft()) as demo:
135
+ gr.Markdown("# 📄 CV Markdown to PDF Converter")
136
+ gr.Markdown("Convert your CV markdown to professional PDF format. Use the Instructions & Sample tab to learn the proper formatting.")
137
+
138
+ with gr.Tabs():
139
+ with gr.TabItem("🚀 Convert CV"):
140
+ with gr.Row():
141
+ with gr.Column(scale=1):
142
+ gr.Markdown("## Input")
143
+ markdown_input = gr.Textbox(
144
+ label="CV Markdown Text",
145
+ placeholder="Enter your CV markdown here... (see Instructions & Sample tab for formatting guide)",
146
+ lines=20,
147
+ max_lines=30
148
+ )
149
+
150
+ with gr.Column(scale=1):
151
+ gr.Markdown("## Output")
152
+
153
+ with gr.Tabs():
154
+ with gr.TabItem("📄 PDF Download"):
155
+ pdf_output = gr.File(
156
+ label="Generated PDF",
157
+ file_types=[".pdf"]
158
+ )
159
+
160
+ with gr.TabItem("🌐 HTML Preview"):
161
+ html_output = gr.HTML(
162
+ label="HTML Preview",
163
+ value="HTML preview will appear here after conversion..."
164
+ )
165
+
166
+ status_message = gr.Textbox(
167
+ label="Status",
168
+ interactive=False,
169
+ lines=2
170
+ )
171
+
172
+ with gr.Row():
173
+ convert_btn = gr.Button("🚀 Convert to PDF", variant="primary", size="lg")
174
+
175
+ # Event handler
176
+ convert_btn.click(
177
+ fn=process_conversion,
178
+ inputs=[markdown_input],
179
+ outputs=[pdf_output, html_output, status_message]
180
+ )
181
+
182
+ with gr.TabItem("📋 Instructions & Sample"):
183
+ with gr.Tabs():
184
+ with gr.TabItem("📖 Formatting Instructions"):
185
+ gr.Markdown(get_cv_formatting_instructions())
186
+
187
+ with gr.TabItem("📄 Sample CV"):
188
+ gr.Markdown("## Sample CV Markdown")
189
+ gr.Markdown("Below is a complete sample CV showing all the formatting patterns:")
190
+
191
+ sample_cv_display = gr.Code(
192
+ value=get_sample_cv(),
193
+ language="markdown",
194
+ label="Sample CV Markdown Code",
195
+ lines=30,
196
+ max_lines=50
197
+ )
198
+
199
+ copy_sample_btn = gr.Button("📋 Copy Sample to Converter", variant="secondary")
200
+
201
+ # Copy sample to main input
202
+ copy_sample_btn.click(
203
+ fn=get_sample_cv,
204
+ outputs=[markdown_input]
205
+ )
206
+
207
+ # Example CV templates
208
+ with gr.Row():
209
+ gr.Examples(
210
+ examples=[
211
+ [get_sample_cv()],
212
+ ["""---
213
+ name: John Doe
214
+ header:
215
+ - text: |
216
+ <span style="font-size: 1.2em; font-weight: bold;">Full Stack Developer</span>
217
+ - text: <span class="iconify" data-icon="tabler:phone"></span> (555) 987-6543
218
+ newLine: true
219
+ - text: <span class="iconify" data-icon="tabler:mail"></span> john.doe@email.com
220
+ link: mailto:john.doe@email.com
221
+ ---
222
+
223
+ ## Experience
224
+
225
+ [L2]Tech Startup Inc.[/L2] [L2R]San Francisco, CA[/L2R]
226
+
227
+ [L3]Full Stack Developer[/L3] [L3R]Jan 2022 - Present[/L3R]
228
+
229
+ - Designed and implemented scalable web applications serving 10K+ users
230
+ - Reduced page load times by 40% through optimization techniques
231
+ - Led migration from monolith to microservices architecture
232
+
233
+ ## Education
234
+
235
+ [L2]University of California[/L2] GPA 3.8 [L2R]Berkeley, CA[/L2R]
236
+ [L3]B.S. in Computer Science[/L3] [L3R]2018 - 2022[/L3R]
237
+
238
+ ## Skills
239
+
240
+ **Programming:** Python, JavaScript, TypeScript, Java
241
+ <br>
242
+ **Frameworks:** React, Node.js, Django, Spring Boot
243
+ <br>
244
+ **Databases:** PostgreSQL, MongoDB, Redis
245
+ """],
246
+ ],
247
+ inputs=[markdown_input],
248
+ label="📝 CV Templates"
249
+ )
250
+
251
+ # Register MCP tools
252
+ gr.api(mcp_get_sample_cv)
253
+ gr.api(mcp_get_cv_instructions)
254
+ gr.api(mcp_convert_cv)
255
+
256
+ # Launch the app with MCP enabled
257
+ if __name__ == "__main__":
258
+ demo.launch(
259
+ mcp_server=True
260
+ )
requirements.txt ADDED
Binary file (64 Bytes). View file