Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NextJS Fullstack Webapp #149

Merged
merged 4 commits into from
Sep 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -137,3 +137,6 @@ dmypy.json
.vscode/*

scripts/similarity/config.yml

# Secrets
*.local.yml
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,16 @@ Follow these steps to set up the environment and run the application.

2. Open `localhost:80` on your browser

<br/>

### Running the Web Application

The full stack Next.js (React and FastAPI) web application allows users to interact with the Resume Matcher tool interactively via a web browser.

To run the full stack web application (frontend client and backend api servers), follow the instructions over on the [webapp README](/webapp/README.md) file.

<br/>

### Cohere and Qdrant

1. Visit [Cohere website registration](https://dashboard.cohere.ai/welcome/register) and create an account.
Expand Down
5 changes: 4 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ decorator==5.1.1
en-core-web-md @ https://github.com/explosion/spacy-models/releases/download/en_core_web_md-3.6.0/en_core_web_md-3.6.0-py3-none-any.whl#sha256=1618fc62e7aedc2b778caa3ea6e9c8280beac3b83fe7b93316cbb9e8f3abe7c5
en-core-web-sm @ https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.6.0/en_core_web_sm-3.6.0-py3-none-any.whl#sha256=83276fc78a70045627144786b52e1f2728ad5e29e5e43916ec37ea9c26a11212
Faker==19.1.0
fastapi==0.101.1
favicon==0.7.0
floret==0.10.3
fonttools==4.41.0
Expand Down Expand Up @@ -61,6 +62,7 @@ pyparsing==3.0.9
pypdf==3.12.2
pyphen==0.14.0
python-dateutil==2.8.2
python-multipart==0.0.6
pytz==2023.3
pytz-deprecation-shim==0.1.0.post0
PyYAML==6.0
Expand Down Expand Up @@ -102,6 +104,7 @@ typer==0.9.0
typing_extensions==4.7.1
tzdata==2023.3
tzlocal==4.3.1
uvicorn==0.23.2
urllib3>=1.26.14
validators==0.20.0
wasabi==1.1.2
Expand All @@ -110,4 +113,4 @@ zipp==3.16.2
reportlab==4.0.4
easygui==0.98.3
cohere~=4.19.2
qdrant-client>=1.2
qdrant-client>=1.2
11 changes: 11 additions & 0 deletions webapp/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"extends": "next/core-web-vitals",
"rules": {
"no-unused-vars": [
"warn",
{
"argsIgnorePattern": "^_"
}
]
}
}
35 changes: 35 additions & 0 deletions webapp/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
160 changes: 160 additions & 0 deletions webapp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
# Resume Matcher - A Full Stack Web Application

The Resume Matcher takes your resume and job descriptions as input, parses them using Python, and mimics the functionalities of an ATS, providing you with insights and suggestions to make your resume ATS-friendly.

## Demo

View a brief GIF demo of the web apps' design functionality below:

![Resume-Matcher-Web-App-UI-Quick-Demo-2](https://github.com/Sayvai/react-project-dashboard-mvp-match/assets/7581546/5bf9c4c8-a5d1-47ee-8e27-eacda0dbcac9)

## Getting Started

### Prerequisites

- install [Node.js](https://nodejs.org/en/download/). The version used for this project is v18.17.0

- install [Python](https://www.python.org/downloads/). The version used for this project is v3.11.5

### Setup

- clone the repository
- navigate to the project directory (e.g. `cd Resume-Matcher`)
- Follow the [README](../README.md) instructions set out in the root of the repository to setup the Python environment and run the Python scripts.
- navigate to the `webapp` directory (e.g. `cd webapp`)
- run `npm install` to install the frontend client app dependencies
- run `npm run dev` to start the web app (i.e. this script will start the frontend client and backend FastAPI servers concurrently within one terminal process inside `webapp` directory`)
- once both servers are ready, open [http://localhost:3000](http://localhost:3000) on your browser to view and interact with the app.

### Extra Setup Hints

- 💡 You may also decide to run the frontend and backend servers in separate terminal processes independently of one another. To run the frontend server in isolation, run `npm run next-dev`. To run the backend FastAPI server in isolation, run `npm run fastapi-dev`.

## Debugging

### VS Code Debugger - FastAPI Backend

When working with the backend web application files, you may like to debug the backend server during runtime and have the ability to set breakpoints to pause execution on certain line(s), inspect variable values, and other runtime data using the VS Code debugger. To do so, follow the steps below:

#### Setup VS Code Launch Configuration

- Open the VS Code debugger tab (i.e. the bug icon on the left sidebar)

- Click on the gear icon to open the launch.json file

- Add the following configuration to the launch.json file, and save:

```json
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug FastAPI Backend",
"type": "python",
"request": "launch",
"module": "uvicorn",
"args": ["webapp.backend.api.index:app", "--reload"],
"jinja": true,
"justMyCode": true
}
]
}
```

#### Start the Backend Server in Debug Mode

- ⚠️ IMPORTANT: Before proceeding along this set of steps, ensure the frontend server is NOT running. It will need to be running in isolation of the backend server, after the backend server has succesfully completed its starup process.

- Open the VS Code debugger tab (i.e. the bug icon on the left sidebar)

- Select the "Debug FastAPI Backend" configuration from the dropdown

- Click on the play button to start the backend server in debug mode

- A new terminal window will open and the backend server will start running in debug mode

- You may optionally set breakpoints in the backend python files to pause execution on certain line(s), inspect variable values, and other runtime data, as you interact with the app or make requests to the backend server.

- Esnure the frontend server is running in isolation of the backend server, after the backend server has succesfully completed its starup process. By running the following command in a separate terminal window:

```bash
npm run next-dev
```

- Once the backend server (and frontend server) is ready, open [http://localhost:3000](http://localhost:3000) on your browser to view and interact with the app.

### Visual demonstration of running the FastAPI backend server in VS Code Debugger

![Resume-Matcher-vs-code-debug-backend-fastapi-demo](https://github.com/srbhr/Resume-Matcher/assets/7581546/04b3b8e2-98c4-40ff-964f-8075c55091c9)

## Troubleshooting Common Issues

### Error: connect ECONNREFUSED 127.0.0.1:8000

<details>
<summary>You may encounter the following <code>Error: connect ECONNREFUSED 127.0.0.1:8000</code> error in the terminal (and browser ui throws an exception) when running the frontend server in isolation of the backend server via npm run next-dev (👉 👀 click to reveal error snippet):</summary>

```bash
[0] Failed to proxy http://127.0.0.1:8000/api/service-keys Error: connect ECONNREFUSED 127.0.0.1:8000
[0] at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1495:16) {
[0] errno: -61,
[0] code: 'ECONNREFUSED',
[0] syscall: 'connect',
[0] address: '127.0.0.1',
[0] port: 8000
[0] }
[0] Error: connect ECONNREFUSED 127.0.0.1:8000
[0] at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1495:16) {
[0] errno: -61,
[0] code: 'ECONNREFUSED',
[0] syscall: 'connect',
[0] address: '127.0.0.1',
[0] port: 8000
[0] }
[0] SyntaxError: Unexpected token I in JSON at position 0
[0] at JSON.parse (<anonymous>)
[0] at parseJSONFromBytes (node:internal/deps/undici/undici:6662:19)
[0] at successSteps (node:internal/deps/undici/undici:6636:27)
[0] at node:internal/deps/undici/undici:1236:60
[0] at node:internal/process/task_queues:140:7
[0] at AsyncResource.runInAsyncScope (node:async_hooks:203:9)
[0] at AsyncResource.runMicrotask (node:internal/process/task_queues:137:8)
[0] at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
[0] - error node_modules/next/dist/compiled/react-server-dom-webpack/cjs/react-server-dom-webpack-server.edge.development.js (340:14) @ getErrorMessage
```

</details>
<br/>

💡 This is most likely because the backend server has not yet started in isolation. To resolve this, ensure the backend server is running in isolation of the frontend server, by running the following command in a separate terminal window, and wait for the backend server to complete its startup process, then refresh the browser window to view the app:

```bash
npm run fastapi-dev
```

💡 Or, you may alternatively run the backend server using the VS Code debugger, as described in the [VS Code Debugger - FastAPI Backend](#vs-code-debugger---fastapi-backend) section above.

## Future Improvements

Below are some of the improvements that can be made to the web app for future consideration:

- 👉 Replace mock response data with real data from the backend. View file; [scripts/resume_processor.py](/webapp/backend/scripts/resume_processor.py), where the `build_response()` function can be modified to hook up to other python scripts to process and return the real data from the backend. The initial python response model classes are defined in the [schemas/resume_processor.py](/webapp/backend/schemas/resume_processor.py) file, and so that should help to get started with thinking about how to structure the data to be returned from the backend.
- Add unit tests (frontend and backend)
- Add end-to-end functional tests (frontend)
- Improve the UI/UX of loading and error states as requests are made to the backend

## Technologies Used

This is a full stack web application, hosting the frontend UI interactive web client interface, and the backend server API.

The application is built using the following main technologies:

- [Next.js](https://nextjs.org/) - a React.js meta-framework for building client and server-side rendered React applications

- [FastAPI](https://fastapi.tiangolo.com/) - a Python framework for building web APIs

- [TailwindCSS](https://tailwindcss.com/) - a CSS framework for building responsive web applications

- [Zustand](https://github.com/pmndrs/zustand) - a frontend client state management library

- [react-pdf](https://projects.wojtekmaj.pl/react-pdf/) - a React component library for rendering PDF documents on the frontend ui
37 changes: 37 additions & 0 deletions webapp/app/(routes)/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "@/app/globals.css";
import Header from "@/components/header/header";

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

export const metadata: Metadata = {
title: "Resume Matcher",
description:
"An AI Based Free & Open Source ATS, Resume Matcher to tailor your resume to a job description. Find the best keywords, and gain deep insights into your resume.",
keywords: ["Resume", "Matcher", "ATS", "Score"],
authors: [
{ name: "Samurize", url: "https://github.com/srbhr" },
{ name: "Sayvai", url: "https://github.com/Sayvai" },
],
icons: {
icon: "/favicon-32x32.png",
},
};

export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body className={inter.className}>
<div className="flex flex-col w-full 2xl:w-2/3 m-auto bg-[#2A203B]">
<Header />
{children}
</div>
</body>
</html>
);
}
24 changes: 24 additions & 0 deletions webapp/app/(routes)/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import JobDescriptions from "@/components/job-descriptions/job-descriptions";
import VectorScore from "@/components/vector-scores/vector-scores";
import CommonWords from "@/components/common-words/common-words";
import Suggestions from "@/components/suggestions/suggestions";
import ThirdPartyServicesKeys from "@/components/third-party-services/third-party-services";
import FileUpload from "@/components/resume/file-upload/file-upload";
import ResumeGlance from "@/components/resume/resume-glance/resume-glance";
import Hero from "@/components/hero/hero";

export default function Home() {
return (
<main>
<Hero>
<ThirdPartyServicesKeys />
<FileUpload buttonLabel="Upload Your Resume" />
</Hero>
<ResumeGlance />
<JobDescriptions />
<VectorScore />
<CommonWords />
<Suggestions />
</main>
);
}
22 changes: 22 additions & 0 deletions webapp/app/_components/button/button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import clsx from "clsx";

type ButtonProps = React.HTMLProps<HTMLButtonElement> & {
type?: "button" | "submit" | "reset";
children: React.ReactNode;
};

const Button = ({ children, type = "button", ...props }: ButtonProps) => {
const { className: inheritedClassNames, ...buttonProps } = props;

return (
<button
type={type}
className={clsx("flex gap-2 w-fit rounded-md p-4", inheritedClassNames)}
{...buttonProps}
>
{children}
</button>
);
};

export default Button;
Loading