import tkinter as tk from tkinter import ttk, filedialog, messagebox import os class CVGeneratorApp: def __init__(self, root): self.root = root self.root.title("LaTeX CV Generator") self.root.geometry("1200x800") # Create notebook for tabs self.notebook = ttk.Notebook(root) self.notebook.pack(fill='both', expand=True, padx=5, pady=5) # Create frames for each section self.personal_frame = ttk.Frame(self.notebook) self.education_frame = ttk.Frame(self.notebook) self.experience_frame = ttk.Frame(self.notebook) self.projects_frame = ttk.Frame(self.notebook) self.skills_frame = ttk.Frame(self.notebook) self.leadership_frame = ttk.Frame(self.notebook) self.output_frame = ttk.Frame(self.notebook) # Add tabs self.notebook.add(self.personal_frame, text='Personal Info') self.notebook.add(self.education_frame, text='Education') self.notebook.add(self.experience_frame, text='Experience') self.notebook.add(self.projects_frame, text='Projects') self.notebook.add(self.skills_frame, text='Skills') self.notebook.add(self.leadership_frame, text='Leadership') self.notebook.add(self.output_frame, text='LaTeX Output') self.setup_personal_info() self.setup_education() self.setup_experience() self.setup_projects() self.setup_skills() self.setup_leadership() self.setup_output() # Button frame at bottom button_frame = ttk.Frame(root) button_frame.pack(fill='x', padx=5, pady=5) ttk.Button(button_frame, text="Generate LaTeX", command=self.generate_latex).pack(side='left', padx=5) ttk.Button(button_frame, text="Save to File", command=self.save_to_file).pack(side='left', padx=5) ttk.Button(button_frame, text="Clear All", command=self.clear_all).pack(side='left', padx=5) def setup_personal_info(self): ttk.Label(self.personal_frame, text="Personal Information", font=('Arial', 14, 'bold')).pack(pady=10) form_frame = ttk.Frame(self.personal_frame) form_frame.pack(fill='x', padx=20, pady=10) fields = [ ("First Name:", "first_name"), ("Last Name:", "last_name"), ("Address:", "address"), ("Phone:", "phone"), ("Email:", "email"), ("LinkedIn:", "linkedin"), ("GitHub:", "github"), ] self.personal_vars = {} for i, (label_text, var_name) in enumerate(fields): ttk.Label(form_frame, text=label_text).grid(row=i, column=0, sticky='e', pady=5, padx=5) self.personal_vars[var_name] = tk.StringVar() entry = ttk.Entry(form_frame, textvariable=self.personal_vars[var_name], width=50) entry.grid(row=i, column=1, sticky='w', pady=5, padx=5) def setup_education(self): ttk.Label(self.education_frame, text="Education", font=('Arial', 14, 'bold')).pack(pady=10) # Main education edu_frame = ttk.LabelFrame(self.education_frame, text="Degree Information", padding=10) edu_frame.pack(fill='x', padx=20, pady=10) self.edu_vars = { 'university': tk.StringVar(), 'degree': tk.StringVar(), 'start_date': tk.StringVar(), 'end_date': tk.StringVar(), 'location': tk.StringVar(), } fields = [ ("University:", 'university'), ("Degree:", 'degree'), ("Start Date:", 'start_date'), ("End Date:", 'end_date'), ("Location:", 'location'), ] for i, (label, var_name) in enumerate(fields): ttk.Label(edu_frame, text=label).grid(row=i, column=0, sticky='e', pady=3, padx=5) ttk.Entry(edu_frame, textvariable=self.edu_vars[var_name], width=50).grid(row=i, column=1, sticky='w', pady=3, padx=5) # Coursework course_frame = ttk.LabelFrame(self.education_frame, text="Relevant Coursework (comma-separated)", padding=10) course_frame.pack(fill='x', padx=20, pady=10) self.coursework_text = tk.Text(course_frame, height=4, width=80) self.coursework_text.pack(pady=5) def setup_experience(self): ttk.Label(self.experience_frame, text="Work Experience", font=('Arial', 14, 'bold')).pack(pady=10) self.experience_entries = [] self.exp_container = ttk.Frame(self.experience_frame) self.exp_container.pack(fill='both', expand=True, padx=20, pady=10) ttk.Button(self.exp_container, text="Add Position", command=self.add_experience).pack(pady=5) def add_experience(self): exp_frame = ttk.LabelFrame(self.exp_container, text=f"Position {len(self.experience_entries) + 1}", padding=10) exp_frame.pack(fill='x', pady=10) vars_dict = { 'company': tk.StringVar(), 'title': tk.StringVar(), 'start_date': tk.StringVar(), 'end_date': tk.StringVar(), 'location': tk.StringVar(), } fields = [ ("Company:", 'company'), ("Title:", 'title'), ("Start Date:", 'start_date'), ("End Date:", 'end_date'), ("Location:", 'location'), ] for i, (label, var_name) in enumerate(fields): ttk.Label(exp_frame, text=label).grid(row=i, column=0, sticky='e', pady=3, padx=5) ttk.Entry(exp_frame, textvariable=vars_dict[var_name], width=50).grid(row=i, column=1, sticky='w', pady=3, padx=5) ttk.Label(exp_frame, text="Responsibilities (one per line):").grid(row=len(fields), column=0, columnspan=2, sticky='w', pady=(10, 3)) responsibilities = tk.Text(exp_frame, height=5, width=80) responsibilities.grid(row=len(fields) + 1, column=0, columnspan=2, pady=3) self.experience_entries.append((vars_dict, responsibilities)) def setup_projects(self): ttk.Label(self.projects_frame, text="Projects", font=('Arial', 14, 'bold')).pack(pady=10) self.project_entries = [] self.proj_container = ttk.Frame(self.projects_frame) self.proj_container.pack(fill='both', expand=True, padx=20, pady=10) ttk.Button(self.proj_container, text="Add Project", command=self.add_project).pack(pady=5) def add_project(self): proj_frame = ttk.LabelFrame(self.proj_container, text=f"Project {len(self.project_entries) + 1}", padding=10) proj_frame.pack(fill='x', pady=10) vars_dict = { 'name': tk.StringVar(), 'technologies': tk.StringVar(), 'date': tk.StringVar(), } fields = [ ("Project Name:", 'name'), ("Technologies:", 'technologies'), ("Date:", 'date'), ] for i, (label, var_name) in enumerate(fields): ttk.Label(proj_frame, text=label).grid(row=i, column=0, sticky='e', pady=3, padx=5) ttk.Entry(proj_frame, textvariable=vars_dict[var_name], width=50).grid(row=i, column=1, sticky='w', pady=3, padx=5) ttk.Label(proj_frame, text="Description (one per line):").grid(row=len(fields), column=0, columnspan=2, sticky='w', pady=(10, 3)) description = tk.Text(proj_frame, height=4, width=80) description.grid(row=len(fields) + 1, column=0, columnspan=2, pady=3) self.project_entries.append((vars_dict, description)) def setup_skills(self): ttk.Label(self.skills_frame, text="Technical Skills", font=('Arial', 14, 'bold')).pack(pady=10) skills_frame = ttk.Frame(self.skills_frame) skills_frame.pack(fill='x', padx=20, pady=10) self.skills_vars = { 'languages': tk.StringVar(), 'tools': tk.StringVar(), 'technologies': tk.StringVar(), } fields = [ ("Languages:", 'languages'), ("Developer Tools:", 'tools'), ("Technologies/Frameworks:", 'technologies'), ] for i, (label, var_name) in enumerate(fields): ttk.Label(skills_frame, text=label).grid(row=i, column=0, sticky='ne', pady=5, padx=5) ttk.Entry(skills_frame, textvariable=self.skills_vars[var_name], width=50).grid(row=i, column=1, sticky='w', pady=5, padx=5) def setup_leadership(self): ttk.Label(self.leadership_frame, text="Leadership / Extracurricular", font=('Arial', 14, 'bold')).pack(pady=10) self.leadership_entries = [] self.lead_container = ttk.Frame(self.leadership_frame) self.lead_container.pack(fill='both', expand=True, padx=20, pady=10) ttk.Button(self.lead_container, text="Add Activity", command=self.add_leadership).pack(pady=5) def add_leadership(self): lead_frame = ttk.LabelFrame(self.lead_container, text=f"Activity {len(self.leadership_entries) + 1}", padding=10) lead_frame.pack(fill='x', pady=10) vars_dict = { 'organization': tk.StringVar(), 'role': tk.StringVar(), 'date': tk.StringVar(), 'location': tk.StringVar(), } fields = [ ("Organization:", 'organization'), ("Role:", 'role'), ("Date:", 'date'), ("Location:", 'location'), ] for i, (label, var_name) in enumerate(fields): ttk.Label(lead_frame, text=label).grid(row=i, column=0, sticky='e', pady=3, padx=5) ttk.Entry(lead_frame, textvariable=vars_dict[var_name], width=50).grid(row=i, column=1, sticky='w', pady=3, padx=5) ttk.Label(lead_frame, text="Achievements (one per line):").grid(row=len(fields), column=0, columnspan=2, sticky='w', pady=(10, 3)) achievements = tk.Text(lead_frame, height=4, width=80) achievements.grid(row=len(fields) + 1, column=0, columnspan=2, pady=3) self.leadership_entries.append((vars_dict, achievements)) def setup_output(self): ttk.Label(self.output_frame, text="Generated LaTeX Code", font=('Arial', 14, 'bold')).pack(pady=10) self.output_text = tk.Text(self.output_frame, wrap='word', width=120, height=40) scrollbar = ttk.Scrollbar(self.output_text, command=self.output_text.yview) self.output_text.configure(yscrollcommand=scrollbar.set) self.output_text.pack(side='left', fill='both', expand=True, padx=20, pady=10) scrollbar.pack(side='right', fill='y') def generate_latex(self): latex_code = self.build_latex_cv() self.output_text.delete(1.0, tk.END) self.output_text.insert(1.0, latex_code) self.notebook.select(6) # Switch to output tab def build_latex_cv(self): # Document class and packages latex = r"""\documentclass[11pt,a4paper]{article} \usepackage[utf8]{inputenc} \usepackage[T1]{fontenc} \usepackage{geometry} \usepackage{enumitem} \usepackage{hyperref} \usepackage{parskip} \geometry{margin=1in} \setlist[itemize]{leftmargin=*, nosep, topsep=2pt, itemsep=2pt} \pagestyle{empty} \begin{document} """ # Personal Info first_name = self.personal_vars['first_name'].get() last_name = self.personal_vars['last_name'].get() latex += f"\\begin{{center}}\n" latex += f"\\textbf{{\\LARGE {first_name} {last_name}}}\\\\\n" address = self.personal_vars['address'].get() phone = self.personal_vars['phone'].get() email = self.personal_vars['email'].get() linkedin = self.personal_vars['linkedin'].get() github = self.personal_vars['github'].get() contact_parts = [] if address: contact_parts.append(address) if phone: contact_parts.append(f"\\href{{tel:{phone}}}{{{phone}}}") if email: contact_parts.append(f"\\href{{mailto:{email}}}{{{email}}}") if linkedin: contact_parts.append( f"\\href{{https://{linkedin}}}{{linkedin.com/in/{linkedin.replace('https://', '').replace('www.', '')}}}") if github: contact_parts.append(f"\\href{{https://github.com/{github}}}{{github.com/{github}}}") latex += " | ".join(contact_parts) + "\n" latex += f"\\end{{center}}\n\n" # Education latex += "\\section*{Education}\n" university = self.edu_vars['university'].get() degree = self.edu_vars['degree'].get() start_date = self.edu_vars['start_date'].get() end_date = self.edu_vars['end_date'].get() location = self.edu_vars['location'].get() if university: date_str = f"{start_date} -- {end_date}" if start_date and end_date else "" latex += f"\\noindent\\textbf{{{university}}}\\hfill {date_str}\\\\\n" latex += f"\\textit{{{degree}}}\n" if location: latex += f"\\\\{location}" latex += "\n\n" # Coursework coursework = self.coursework_text.get(1.0, tk.END).strip() if coursework: latex += "\\subsection*{Relevant Coursework}\n" courses = [c.strip() for c in coursework.split(',') if c.strip()] latex += "\\begin{itemize}\n" for i in range(0, len(courses), 4): row_courses = courses[i:i + 4] latex += " \\item " + " \\quad $\\bullet$ ".join(row_courses) + "\n" latex += "\\end{itemize}\n\n" # Experience latex += "\\section*{Experience}\n" for vars_dict, resp_text in self.experience_entries: company = vars_dict['company'].get() title = vars_dict['title'].get() start = vars_dict['start_date'].get() end = vars_dict['end_date'].get() location = vars_dict['location'].get() if company: date_str = f"{start} -- {end}" if start and end else "" latex += f"\\noindent\\textbf{{{company}}}\\hfill {date_str}\\\\\n" latex += f"\\textit{{{title}}}" if location: latex += f"\\\\{location}" latex += "\n" responsibilities = resp_text.get(1.0, tk.END).strip() if responsibilities: latex += "\\begin{itemize}\n" for resp in responsibilities.split('\n'): if resp.strip(): latex += f" \\item {resp.strip()}\n" latex += "\\end{itemize}\n" latex += "\n" # Projects latex += "\\section*{Projects}\n" for vars_dict, desc_text in self.project_entries: name = vars_dict['name'].get() tech = vars_dict['technologies'].get() date = vars_dict['date'].get() if name: tech_str = f" | {tech}" if tech else "" latex += f"\\noindent\\textbf{{{name}}}\\textit{{{tech_str}}}\\hfill {date}\\\\\n" description = desc_text.get(1.0, tk.END).strip() if description: latex += "\\begin{itemize}\n" for desc in description.split('\n'): if desc.strip(): latex += f" \\item {desc.strip()}\n" latex += "\\end{itemize}\n" latex += "\n" # Skills latex += "\\section*{Technical Skills}\n" languages = self.skills_vars['languages'].get() tools = self.skills_vars['tools'].get() technologies = self.skills_vars['technologies'].get() if languages or tools or technologies: if languages: latex += f"\\noindent\\textbf{{Languages:}} {languages}\\\\\n" if tools: latex += f"\\textbf{{Developer Tools:}} {tools}\\\\\n" if technologies: latex += f"\\textbf{{Technologies/Frameworks:}} {technologies}\n" latex += "\n" # Leadership latex += "\\section*{Leadership / Extracurricular}\n" for vars_dict, achieve_text in self.leadership_entries: org = vars_dict['organization'].get() role = vars_dict['role'].get() date = vars_dict['date'].get() location = vars_dict['location'].get() if org: latex += f"\\noindent\\textbf{{{org}}}\\hfill {date}\\\\\n" latex += f"\\textit{{{role}}}" if location: latex += f"\\\\{location}" latex += "\n" achievements = achieve_text.get(1.0, tk.END).strip() if achievements: latex += "\\begin{itemize}\n" for achieve in achievements.split('\n'): if achieve.strip(): latex += f" \\item {achieve.strip()}\n" latex += "\\end{itemize}\n" latex += "\n" latex += "\\end{document}" return latex def save_to_file(self): latex_code = self.output_text.get(1.0, tk.END).strip() if not latex_code: messagebox.showwarning("Warning", "Please generate LaTeX code first!") return file_path = filedialog.asksaveasfilename( defaultextension=".tex", filetypes=[("LaTeX files", "*.tex"), ("All files", "*.*")] ) if file_path: with open(file_path, 'w', encoding='utf-8') as f: f.write(latex_code) messagebox.showinfo("Success", f"CV saved to {file_path}") def clear_all(self): if messagebox.askyesno("Confirm", "Are you sure you want to clear all fields?"): # Clear personal info for var in self.personal_vars.values(): var.set("") # Clear education for var in self.edu_vars.values(): var.set("") self.coursework_text.delete(1.0, tk.END) # Clear experience for widget in self.exp_container.winfo_children(): widget.destroy() self.experience_entries = [] ttk.Button(self.exp_container, text="Add Position", command=self.add_experience).pack(pady=5) # Clear projects for widget in self.proj_container.winfo_children(): widget.destroy() self.project_entries = [] ttk.Button(self.proj_container, text="Add Project", command=self.add_project).pack(pady=5) # Clear skills for var in self.skills_vars.values(): var.set("") # Clear leadership for widget in self.lead_container.winfo_children(): widget.destroy() self.leadership_entries = [] ttk.Button(self.lead_container, text="Add Activity", command=self.add_leadership).pack(pady=5) # Clear output self.output_text.delete(1.0, tk.END) def main(): root = tk.Tk() app = CVGeneratorApp(root) root.mainloop() if __name__ == "__main__": main()