# Project export: Tune.AI

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: TreeHacks 2024
- Tagline: Provide find-tuned resume and tailored cover letter for job applications in just 3 steps.
- Devpost: https://devpost.com/software/tune-ai-dp8b4c
- GitHub: https://github.com/seanflyyy/treehacks2024
- Video: https://www.youtube.com/embed/UVvrS1fRE94?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 3 GitHub contributor(s) — Sean Er (16 commits), Clarence Lin (11 commits), kevindo0720 (7 commits)

## Devpost submission (written by the team)

### Inspiration

As the job market becomes more competitive and fiercer than ever, everyone experiences significant hardship when trying to find a job. The situation is not getting any better soon as layoffs occur more frequently and more people begin looking for jobs. On average, a single application yields an 8.3% chance of landing a job interview, and is even more difficult to secure an offer. As such, Tune.AI aims to reduce the hassle of job search and matches you with the most suitable job!

### What it does

Tune.AI allows users to automatically tailor their resumes according to each specific job posting and also provide cover letters that match with everything on the users' resumes, the company the user is applying to, and the specific job posting's requirement. Tune.AI aims to help users increase their chance of landing interviews with fewer applications and in much less time, with higher accuracy of landing a job that matches their existing skillsets.

### How we built it

Our Platform is comprised of: A resume parser we buildtfrom scratch A Recommendation system to help rank current job postings according to the user's resume An algorithm to help select the most relevant experiences/skills/projects to the job posting that the user wants to apply to AIs that generate tuned resumes and tailored cover letters

### Challenges we ran into

Our project consists of a lot of components and we experienced significant hardships when trying to integrate everything. Steep learning curve for different third party applications that we were trying to integrate Working together in sync and ensuring that we meet our project timeline

### Accomplishments we're proud of

Being able to incorporate the latest technologies (LLM, database, etc) into our platform Creating our resume parser that successfully parsed multiple different resumes of different variations Matching and connecting people with suitable companies

### What we learned

How to collaborate on different components concurrently and connecting them How to integrate third-party apps effectively to help us achieve our goals Stay awake throughout the night to get the job done

### What's next

We hope to enhance the platform's functionality, user engagement, and accuracy by allowing users to interactively add, modify, and validate their skills and experiences through a more engaging UI, possibly using gamification. We also hope to implement a feedback loop where users can provide feedback on the recommendations and generated content, which can be used to fine-tune the algorithms.

## README (from the GitHub repository)

# Treehacks2024's project: Tune.AI 

As the job market becomes more competitive and fiercer than ever, everyone experiences significant hardship when trying to find a job. The situation is not getting any better soon as layoffs occur more frequently and more people begin looking for jobs. On average, a single application yields an 8.3% chance of landing a job interview, and is even more difficult to secure an offer.  As such, Tune.AI aims to reduce the hassle of job search and matches you with the most suitable job!

# Video
[![Video for Tune.ai](https://img.youtube.com/vi/UVvrS1fRE94/0.jpg)](https://www.youtube.com/watch?v=UVvrS1fRE94)




# What it does

Tune.AI allows users to automatically tailor their resumes according to each specific job posting and also provide cover letters that match with everything on the users' resumes, the company the user is applying to, and the specific job posting's requirement. 

Tune.AI aims to help users increase their chance of landing interviews with fewer applications and in much less time, with higher accuracy of landing a job that matches their existing skillsets.

# How we built it

Our Platform is comprised of:
- A resume parser we buildtfrom scratch 
- A Recommendation system to help rank current job postings according to the user's resume
- An algorithm to help select the most relevant experiences/skills/projects to the job posting that the user wants to apply to
- AIs that generate tuned resumes and tailored cover letters
- Tech Stack: Python, Javscript/Typescript/HTML/CSS Tailwind, Chakra UI, Together API, Convex Database, Sklearn, CV render, Flask, React.js, Express.js, Next.js


**DevPost Link**: [Devpost Link](https://devpost.com/software/tune-ai-dp8b4c?ref_content=user-portfolio&ref_feature=in_progress)!
**Presentation Link** [Presentation Link](https://docs.google.com/presentation/d/1joB2o-8mpPFgtcq3sGIFAN2w3Z1lhxouTAQUQG8Vt7Y/edit#slide=id.g2ba444c7c08_0_175)!



## Detected evidence (automated analysis)

Indexed codebase: 79 recognized source files, 143 KB.
- CSS (language) — detected in the code
- JavaScript (language) — detected in the code
- Next.js (technology) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code
- TypeScript (language) — detected in the code
- Flask (technology) — claimed on Devpost, not found in the code
- HTML (language) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (107 of 107)

```
.DS_Store
.gitignore
backend/__init__.py
backend/.DS_Store
backend/.gitignore
backend/app.py
backend/convex/_generated/api.d.ts
backend/convex/_generated/api.js
backend/convex/_generated/dataModel.d.ts
backend/convex/_generated/server.d.ts
backend/convex/_generated/server.js
backend/convex/JobCreateSchemas/companies.js
backend/convex/JobCreateSchemas/jobPosting.js
backend/convex/JobGetNullScores/getNull.js
backend/convex/JobGetNullScores/JobCompanyConnect.js
backend/convex/README.md
backend/convex/tsconfig.json
backend/convex/UserCreateSchemas/details.js
backend/convex/UserCreateSchemas/education.js
backend/convex/UserCreateSchemas/experiences.js
backend/convex/UserCreateSchemas/projects.js
backend/convex/UserCreateSchemas/resume.js
backend/convex/UserCreateSchemas/skills.js
backend/convex/UserCreateSchemas/user.js
backend/convex/UserGetDetails/getDetails.js
backend/convex/UserGetDetails/getEducation.js
backend/convex/UserGetDetails/getExperience
backend/convex/UserGetDetails/getPerson.js
backend/convex/UserGetDetails/getProjects.js
backend/convex/UserGetDetails/getResume.js
backend/convex/UserGetDetails/getSkills.js
backend/JobsRanking.json
backend/models/__init__.py
backend/models/convex/__init__.py
backend/models/convex/main.py
backend/models/convex/routes.py
backend/models/parser/__init__.py
backend/models/parser/parser.py
backend/models/parser/utils.py
backend/models/test.py
backend/models/upload/main.py
backend/package.json
coverLetterGenerator/.DS_Store
coverLetterGenerator/cover_letter.tex
coverLetterGenerator/CoverLetter.txt
coverLetterGenerator/CoverLetterGen.py
coverLetterGenerator/job.json
coverLetterGenerator/stringToLatex.py
coverLetterGenerator/txtToPdf.py
coverLetterGenerator/values.txt
coverLetterGenerator/webScraper.py
filterOutProjectsAndExperiences/FilteredData.json
filterOutProjectsAndExperiences/Filtering.py
filterOutProjectsAndExperiences/sampleDataStructure.json
filterOutProjectsAndExperiences/sampleDataStructure2.json
frontend/.eslintrc.json
frontend/.gitignore
frontend/next.config.mjs
frontend/package.json
frontend/postcss.config.js
frontend/README.md
frontend/src/app/_pages.js
frontend/src/app/components/Date/Month.tsx
frontend/src/app/components/Date/Year.tsx
frontend/src/app/components/TextArea/AutoResizingTextArea.tsx
frontend/src/app/fonts.ts
frontend/src/app/globals.css
frontend/src/app/home/components/JobPosting.tsx
frontend/src/app/home/page.tsx
frontend/src/app/job/components/DownloadPDF.tsx
frontend/src/app/job/page.tsx
frontend/src/app/layout.tsx
frontend/src/app/page.tsx
frontend/src/app/providers.tsx
frontend/src/app/resume/details/page.tsx
frontend/src/app/resume/education/page.tsx
frontend/src/app/resume/experience/components/ExperienceForm.tsx
frontend/src/app/resume/experience/page.tsx
frontend/src/app/resume/projects/components/ProjectsForm.tsx
frontend/src/app/resume/projects/components/ProjectsForm/Technologies.tsx
frontend/src/app/resume/projects/page.tsx
frontend/src/app/resume/skills/components/SkillsInputWithSuggestionts.tsx
frontend/src/app/resume/skills/page.tsx
frontend/src/app/upload/page.tsx
frontend/src/contants.ts
frontend/src/redux/slice/details.ts
frontend/src/redux/store.ts
frontend/src/theme.ts
frontend/tailwind.config.ts
frontend/tsconfig.json
main2.py
output/ALLEN_GU_CV.tex
output/fonts/LICENSE 2.md
output/fonts/LICENSE.md
OverallResumeScorer/ResumeScorer.py
RankAllJobsAccordingToProfile/JobData.json
RankAllJobsAccordingToProfile/JobsRanking.json
RankAllJobsAccordingToProfile/Profile.json
RankAllJobsAccordingToProfile/rankingAllJobs.py
README.md
resumeWriter/.DS_Store
resumeWriter/converted_resume.yaml
resumeWriter/input.json
resumeWriter/json_to_yaml.py
resumeWriter/old_output_ignore/fonts/LICENSE.md
resumeWriter/old_output_ignore/John_Doe_CV.tex
resumeWriter/Test_CV.yaml
```

### Dependencies

- backend/package.json: convex@^1.9.0
- frontend/package.json: @chakra-ui/icons@^2.1.1, @chakra-ui/next-js@^2.2.0, @chakra-ui/react@^2.8.2, @emotion/react@^11.11.3, @emotion/styled@^11.11.0, @reduxjs/toolkit@^2.2.1, @types/node@^20, @types/react@^18, @types/react-dom@^18, autoprefixer@^10.0.1, axios@^1.6.7, eslint@^8, eslint-config-next@14.1.0, framer-motion@^11.0.5, next@14.1.0, next-redux-wrapper@^8.1.0, postcss@^8, react@^18, react-dom@^18, react-redux@^9.1.0, redux@^5.0.1, tailwindcss@^3.3.0, typescript@^5

### Recent commits (newest first)

- Update README.md
- Update README.md
- Merge branch 'main' of https://github.com/seanflyyy/treehacks2024
- updated json file
- Merge branch 'main' of https://github.com/seanflyyy/treehacks2024
- change
- Add backend endpoints
- Merge branch 'main' of https://github.com/seanflyyy/treehacks2024
- Add redux for last 2 set up process
- passing json data for jobs to frontend
- Add redux for first 3 home page
- One file to create resume and cover letter
- Added JSON to resume pdf converter
- backend connected with scorerank
- new changes
- backend change
- modify backend
- backend modification
- Merge branch 'main' of https://github.com/seanflyyy/treehacks2024
- Add UI for jobs and home page

## Key source files (fetched from GitHub, selected and truncated for size)

### output/fonts/LICENSE 2.md

```markdown
Copyright 2010-2022 Adobe (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe in the United States and/or other countries.

This Font Software is licensed under the SIL Open Font License, Version 1.1.

This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL


-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------

PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.

The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded, 
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.

DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.

"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).

"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).

"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.

"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.

PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:

1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.

2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.

3) No Modified Version of th
[truncated — 1486 more characters]
```

### output/fonts/LICENSE.md

```markdown
Copyright 2010-2022 Adobe (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe in the United States and/or other countries.

This Font Software is licensed under the SIL Open Font License, Version 1.1.

This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL


-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------

PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.

The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded, 
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.

DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.

"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).

"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).

"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.

"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.

PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:

1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.

2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.

3) No Modified Version of th
[truncated — 1486 more characters]
```

### backend/package.json

```
{
  "name": "backend",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "convex": "^1.9.0"
  }
}

```

### frontend/package.json

```
{
  "name": "frontend",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "@chakra-ui/icons": "^2.1.1",
    "@chakra-ui/next-js": "^2.2.0",
    "@chakra-ui/react": "^2.8.2",
    "@emotion/react": "^11.11.3",
    "@emotion/styled": "^11.11.0",
    "@reduxjs/toolkit": "^2.2.1",
    "axios": "^1.6.7",
    "framer-motion": "^11.0.5",
    "next": "14.1.0",
    "next-redux-wrapper": "^8.1.0",
    "react": "^18",
    "react-dom": "^18",
    "react-redux": "^9.1.0",
    "redux": "^5.0.1"
  },
  "devDependencies": {
    "@types/node": "^20",
    "@types/react": "^18",
    "@types/react-dom": "^18",
    "autoprefixer": "^10.0.1",
    "eslint": "^8",
    "eslint-config-next": "14.1.0",
    "postcss": "^8",
    "tailwindcss": "^3.3.0",
    "typescript": "^5"
  }
}

```

### backend/app.py

```python
# import models.tex
from .models.parser.parser import parse_and_categorize_resumes
from flask import Flask, request, jsonify
from werkzeug.utils import secure_filename
import os
from flask_cors import CORS
from .models.convex.main import *
import uuid


app = Flask(__name__)
CORS(app, resources={r"/upload/*": {"origins": "http://localhost:3000"}})

UPLOAD_FOLDER = './data/uploads'
ALLOWED_EXTENSIONS = {'pdf'}


@app.route("/")
def hello_world():
    return jsonify(parse_and_categorize_resumes("data/demo.pdf"))

app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER

if not os.path.exists(UPLOAD_FOLDER):
    os.makedirs(UPLOAD_FOLDER)

def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

@app.route('/upload', methods=['POST'])
def upload_file():
    if 'file' not in request.files:
        return jsonify({'error': 'No file part'}), 400
    file = request.files['file']
    if file.filename == '':
        return jsonify({'error': 'No selected file'}), 400
    if file and allowed_file(file.filename):
        filename = secure_filename(file.filename)
        file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
        data = parse_and_categorize_resumes(os.path.join(app.config['UPLOAD_FOLDER'], filename))

        return jsonify({'message': f'{filename} uploaded successfully', 'data' : data}, 200)
    
@app.route('/create_user', methods=['POST'])
def create_user_route():
    data = request.get_json()

    # Insert data into the database
    user_id = uuid.uuid4()
    create_user(user_id, data['details']['name'])
    resume_id = uuid.uuid4()
    create_resume(user_id, resume_id)
    create_details(resume_id, data['details']['name'], data['details']['phone'], data['details']['email'], data['details']['linkedin'], data['details']['github'])
    for education in data['education']:
        create_education(resume_id, education['level_of_education'], education['school'], education['field_of_study'], education['school_location'], education['from_date'], education['to_date'])
    for experience in data['experience']:
        create_experiences(resume_id, experience['company'], experience['position'], experience['date'], experience['responsibilities'], experience['from_date'], experience['to_date'])
    for project in data['projects']:
        create_projects(resume_id, project['title'], project['description'], project['technologies'])
    for skill in data['skills']:
        create_skills(resume_id, skill['skill'])

@app.route('/getJobs')
def get_jobs():
    # Call the relevant methods to get the description of the jobs from the database
    return results

@app.route('/getResume')
def get_resume():
    # Call the relevant methods to get the resume from the database
    return profile
    

@app.route('/coverLetter')
def get_cover_letter():
    """
        Return me the cover letter
    """
    pass

@app.route("/createJSON", methods=['POST'])
def create_json():
    """
        Create a json file
    """
    data = request.get_json()
    print(data)
    # print("data is", data)
    # with open('./data/data.json', 'w') as f:
    #     json.dump(data, f)

    return jsonify({'message': 'File created successfully'}, 200)

if __name__ == '__main__':
    app.run(port=3001)



```

### frontend/src/app/page.tsx

```typescript
"use client";

import Image from "next/image";
import {Link} from "@chakra-ui/next-js";
import {Button, Heading, Text, VStack} from "@chakra-ui/react";

export default function Home() {
  return (
    <VStack height="100vh" justifyContent="center">
      <Heading size="2xl" fontWeight="bold">
        Tune.ai
      </Heading>
      <Text fontSize="xl" color="gray.500" mb={"10px"}>
        Generate a resume and cover letter fine tuned for the job you want.
      </Text>
      <Link href="/upload">
        <Button>Get Started</Button>
      </Link>
    </VStack>
  );
}

```

### frontend/src/app/layout.tsx

```typescript
"use client";

import type {Metadata} from "next";
import {Inter} from "next/font/google";
import "./globals.css";
import {Providers} from "./providers";
import {fonts} from "./fonts";
import {Provider} from "react-redux";
import store from "@/redux/store";

const inter = Inter({subsets: ["latin"]});

// export const metadata: Metadata = {
//   title: "Create Next App",
//   description: "Generated by create next app",
// };

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en" className={fonts.rubik.variable}>
      <body>
        <Providers>
          <Provider store={store}>{children}</Provider>
        </Providers>
      </body>
    </html>
  );
}

```

### backend/models/upload/main.py

```python
# from flask import Flask, request, jsonify
# from werkzeug.utils import secure_filename
# import os

# app = Flask(__name__)

# UPLOAD_FOLDER = './uploads'
# ALLOWED_EXTENSIONS = {'pdf'}

# app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER

# if not os.path.exists(UPLOAD_FOLDER):
#     os.makedirs(UPLOAD_FOLDER)

# def allowed_file(filename):
#     return '.' in filename and \
#            filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

# @app.route('/upload', methods=['POST'])
# def upload_file():
#     print("hello")
#     if 'file' not in request.files:
#         return jsonify({'error': 'No file part'}), 400
#     file = request.files['file']
#     if file.filename == '':
#         return jsonify({'error': 'No selected file'}), 400
#     if file and allowed_file(file.filename):
#         filename = secure_filename(file.filename)
#         file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
#         return jsonify({'message': f'{filename} uploaded successfully'}), 200

```

### backend/convex/_generated/server.js

```javascript
/* eslint-disable */
/**
 * Generated utilities for implementing server-side Convex query and mutation functions.
 *
 * THIS CODE IS AUTOMATICALLY GENERATED.
 *
 * Generated by convex@1.9.0.
 * To regenerate, run `npx convex dev`.
 * @module
 */

import {
  actionGeneric,
  httpActionGeneric,
  queryGeneric,
  mutationGeneric,
  internalActionGeneric,
  internalMutationGeneric,
  internalQueryGeneric,
} from "convex/server";

/**
 * Define a query in this Convex app's public API.
 *
 * This function will be allowed to read your Convex database and will be accessible from the client.
 *
 * @param func - The query function. It receives a {@link QueryCtx} as its first argument.
 * @returns The wrapped query. Include this as an `export` to name it and make it accessible.
 */
export const query = queryGeneric;

/**
 * Define a query that is only accessible from other Convex functions (but not from the client).
 *
 * This function will be allowed to read from your Convex database. It will not be accessible from the client.
 *
 * @param func - The query function. It receives a {@link QueryCtx} as its first argument.
 * @returns The wrapped query. Include this as an `export` to name it and make it accessible.
 */
export const internalQuery = internalQueryGeneric;

/**
 * Define a mutation in this Convex app's public API.
 *
 * This function will be allowed to modify your Convex database and will be accessible from the client.
 *
 * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
 * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
 */
export const mutation = mutationGeneric;

/**
 * Define a mutation that is only accessible from other Convex functions (but not from the client).
 *
 * This function will be allowed to modify your Convex database. It will not be accessible from the client.
 *
 * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
 * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
 */
export const internalMutation = internalMutationGeneric;

/**
 * Define an action in this Convex app's public API.
 *
 * An action is a function which can execute any JavaScript code, including non-deterministic
 * code and code with side-effects, like calling third-party services.
 * They can be run in Convex's JavaScript environment or in Node.js using the "use node" directive.
 * They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}.
 *
 * @param func - The action. It receives an {@link ActionCtx} as its first argument.
 * @returns The wrapped action. Include this as an `export` to name it and make it accessible.
 */
export const action = actionGeneric;

/**
 * Define an action that is only accessible from other Convex functions (but not from the client).
 *
 * @param func - The function. It receives an {@link ActionCtx} as its first argument.
 * @returns The wrapped function. Include this as an `export` to name it and make it accessible.
 */
export const internalAction = internalActionGeneric;

/**
 * Define a Convex HTTP action.
 *
 * @param func - The function. It receives an {@link ActionCtx} as its first argument, and a `Request` object
 * as its second.
 * @returns The wrapped endpoint function. Route a URL path to this function in `convex/http.js`.
 */
export const httpAction = httpActionGeneric;

```

### backend/models/convex/main.py

```python
import os
from pprint import pprint
from dotenv import load_dotenv
from convex import ConvexClient
import json
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity

load_dotenv(".env.local")
load_dotenv()

# Loading the convex client
client = ConvexClient(os.getenv("CONVEX_URL"))

# methods to insert new values into the database
#function to create a user with user_id and name
def create_user(user_id, name):
    client.mutation("UserCreateSchemas/user:post", dict(user_id=user_id, name=name))

#function to create a resume with user_id and resume_id
def create_resume(user_id, resume_id):
    client.mutation("UserCreateSchemas/resume:resumepost", dict(user_id=user_id, resume_id=resume_id))

#function to cteate a skill with resume_id and skills
def create_skills(resume_id, skills):
    client.mutation("UserCreateSchemas/skills:post", dict(resume_id=resume_id, skills=skills))

#function to create details with resume_id, name, phone, email, linkedin, and github   
def create_details(resume_id, name, phone, email, linkedin, github):
    client.mutation("UserCreateSchemas/details:post", dict(resume_id=resume_id, name=name, phone=phone, email=email, linkedin=linkedin, github=github))

#function to create a experience with resume_id, company, position, date, and responsibilities
def create_experiences(resume_id, company, position, date, responsibilities, from_date, to_date):
    client.mutation("UserCreateSchemas/experiences:post", dict(resume_id=resume_id, company=company, position=position, date=date, responsibilities=responsibilities))

#function to create projects with resume_id, title, description, and technologies
def create_projects(resume_id, title, description, technologies):
    client.mutation("UserCreateSchemas/projects:post", dict(resume_id=resume_id, title=title, description=description, technologies=technologies))

#function to create education with resume_id, level_of_education, school, field_of_study, and school_location
def create_education(resume_id, level_of_education, school, field_of_study, school_location, from_date, to_date):
    client.mutation("UserCreateSchemas/education:post", dict(resume_id=resume_id, level_of_education=level_of_education, school=school, field_of_study=field_of_study, school_location=school_location, from_date=from_date, to_date=to_date))

#functions for calling the company and job posting schemas
#function to create a company with company_id and company_name
def create_company(company_id, company_name):
    client.mutation("JobCreateSchemas/companies:post", dict(company_id=company_id, company_name=company_name))

#function to create a job with company_id, title, description, score, and url
def create_job(company_id, title, description, score, url):
    client.mutation("JobCreateSchemas/jobPosting:post", dict(company_id=company_id, title=title, description=description,score=score, url=url))


#function to create a job with company_id, title, description, score, and url
def query_for_jobs():
    jobs = client.query("JobGetNullScores/JobCompanyConnect:get")
    companies = {}
    for item in jobs:
        companies[item["company_id"]] = item["company_name"]
    
    return companies


def jsonify_job_results():
    jobs = client.query("JobGetNullScores/getNull:get")
    companies = query_for_jobs()
    filtered_data = [
        {"company_name": companies[item["company_id"]], "title": item["title"], "description": item["description"], 
         "score": item["score"]}
        for item in jobs
    ]
    json_data = json.dumps(filtered_data, indent=4)
    return json_data


def query_for_details():
    details = client.query("UserGetDetails/getDetails:get")
    #detail = {}
    filtered_data = [
        {"resume_id": item["resume_id"],"name": item["name"], "email": item["email"], "linkedin": item["linkedin"], 
         "github": item["github"], "phone": item["phone"]}
        for item in details
    ]
    return filtered_data


def query_for_experiences():
    resumes = client.query("UserGetDetails/getExperience:get")
    filtered_data = [
        {"resume_id": item["resume_id"],"company": item["company"], "date": item["date"],"position": item["position"],"responsibilities": item["responsibilities"]}
        for item in resumes
    ]
    return filtered_data


def query_for_education():
    education = client.query("UserGetDetails/getEducation:get")
    filtered_data = [
        {"resume_id": item["resume_id"], "school": item["school"], "field_of_study": item["field_of_study"],"level_of_education": item["level_of_education"],"from_date": item["from_date"], "to_date": item["to_date"], "school_location": item["school_location"]}
        for item in education
    ]
    return filtered_data


def query_for_projects():
    projects = client.query("UserGetDetails/getProjects:get")
    filtered_data = [
        {"resume_id": item["resume_id"], "title": item["title"], "description": item["description"],"technologies": item["technologies"]}
        for item in projects
    ]
    return filtered_data

def query_for_skills():
    skills = client.query("UserGetDetails/getSkills:get")
    filtered_data = [
        {"resume_id": item["resume_id"], "skills": item["skills"]}
        for item in skills
    ]
    return filtered_data



def jsonify_profile():
    # Assuming client.query and other query functions return a list of dictionaries
    resume = client.query("UserGetDetails/getResume:get")
    resume_ids = [item["resume_id"] for item in resume]

    details = query_for_details()
    experiences = query_for_experiences()
    education = query_for_education()
    projects = query_for_projects()
    skills = query_for_skills()

    people = []

    for resume_id in resume_ids:
        person = {
            "details": [],
            "experience": [],
            "education": [],
            "projects": [],
            "skills": []
        }

        # Append items to lists if the resume_id matches
        f
[truncated — 3482 more characters]
```

[63 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]