# Project export: Ai&U

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: Are you ready to ace your next job interview with confidence? Say hello to Ai&U – your personalized interview preparation assistant powered by expressional artificial intelligence technology.
- Devpost: https://devpost.com/software/ai-u-jlvfew
- GitHub: https://github.com/isabellaqian/treehack24
- Team: 2 GitHub contributor(s) — isabellaqian (4 commits), Ge (1 commits)

## Devpost submission (written by the team)

### Inspiration

In the hectic moments before a job interview, users may experience a flurry of emotions, from nervousness to self-doubt, as they grapple with the pressure to perform well and make a positive impression on the interviewer. Our inspiration for Ai&U stemmed from our collective experiences with interviews and findings from the user research we conducted, in which users ranging from under 18 to 34 with diverse educational backgrounds and work experiences described their "nervousness," "lack of feedback," and "difficulty answering certain types of question." We noticed that traditional interview preparation methods, such as rehearsing responses or seeking advice from friends and mentors, often lack personalized feedback and fail to simulate the dynamic nature of real interview scenarios. According to the research survey, most users are comfortable interacting with an AI avatar for interview preparation. Some users wished for a tool that would enact different company’s interview processes (like a boba shop vs tech corporate), analyze body language and take note of the times that they fidget or stutter, questions based on past interviews, and a way to know what interviewers think of their answers. Recognizing the growing importance of AI technology in various fields, we saw an opportunity to leverage it to create a solution that addresses these shortcomings. By combining AI-driven simulation with personalized feedback and a friendly user experience, we aimed to provide users with a more effective and engaging way to enhance their confidence in interviews and increase their chances of success.

### What it does

Ai&U is a website that utilizes AI avatars to prepare users for interviews. Before the live interview with an AI avatar, users input the job description and resume. AI analyzes this information and prepares specific questions for the interview. During the interview, the AI interviewer reacts with expressions based on the user's responses. We used voice-to-text as well as AI avatars to implement these features. After the interview, Ai&U generates a feedback page along with an AI chat where users can receive personalized feedback and ask the AI interviewer questions directly.

### How we built it

We used Figma to design the entire website. Then, we used Next.js to build the frontend and Node.js for the backend,

### Challenges we ran into

It was difficult to connect the front and back end through API calls. We didn't have much experience with this, so it was quite challenging to make API endpoints.

### Accomplishments we're proud of

We are really proud of the emphasis on the user throughout the design process. Creating the virtual interview avatar was also really cool, and we are proud that the feature was tested properly.

### What we learned

Through our user research and development process, we learned the importance of personalized feedback and real-time interaction in interview preparation. We discovered that users face various challenges, including nervousness, difficulty answering certain types of questions, and lack of feedback on their performance. We also learned a lot about team management and combining frontend and backend.

### What's next

Based on the survey results, we want to include the user's past interview results as a way to personalize future interview questions. For example, if the user has been weak in questions that account for "leadership and management" skills, future AI interviews may specifically tackle those types of questions. We also want to develop a feature in which users can choose their AI interviewer (Google software recruiter, BobaGuys manager, etc) for a more personalized and targeted mock interview. In addition, we want to record the user's interview with the AI and have it as part of the feedback page where specific phrases will have timestamps that the AI interviewer wants to comment on specifically.

## README (from the GitHub repository)

# Ai&U: AI Avatar Interview Preparation Platform
![Ai U User Interface](https://github.com/isabellaqian/treehack24/assets/145081878/ff87394d-6c0a-43ae-896c-3d47b78a1ef2)

## Inspiration
In the hectic moments before a job interview, users often experience a range of emotions from nervousness to self-doubt. Traditional interview preparation methods, such as rehearsing responses or seeking advice from friends and mentors, often lack personalized feedback and fail to simulate the dynamic nature of real interview scenarios. Our inspiration for Ai&U stemmed from our collective experiences and user research, revealing common issues like "nervousness," "lack of feedback," and "difficulty answering certain types of questions." Recognizing the growing importance of AI technology, we saw an opportunity to leverage it to create a solution that addresses these shortcomings.

## Features
- **Personalized AI-Driven Interviews:** Users can input their job description and resume to receive specific interview questions.
- **AI Avatar Interactions:** AI avatars react with expressions based on user responses.
- **Voice-to-Text:** Translates spoken responses into text for analysis.
- **Feedback Generation:** Provides detailed feedback on performance, highlighting areas for improvement.
- **AI Chat Assistance:** Users can ask follow-up questions and receive additional feedback from the AI interviewer.
- **Interview Recording:** Records interviews for later review with timestamped comments.

## How It Works
1. **User Input:** Users enter their job description and upload their resume.
2. **AI Preparation:** The AI analyzes the information and generates tailored interview questions.
3. **Live Interview:** Users engage in a simulated interview with an AI avatar that reacts to their responses.
4. **Feedback:** After the interview, users receive a detailed feedback report and can interact with the AI for further insights.

![Ai U Interview Interface](https://github.com/isabellaqian/treehack24/assets/145081878/0d41a66a-4d55-444b-b157-388c8eeb4943) 
![Ai U Feedback Interface](https://github.com/isabellaqian/treehack24/assets/145081878/6be95f80-664b-43d1-b4a0-96cc5325ae96)

## Technologies Used
- **Frontend:** Next.js, CSS
- **Backend:** Node.js
- **AI & NLP:** Python, Jupyter Notebook
- **Design:** Figma

## Challenges Faced
- **API Integration:** Connecting the frontend and backend through API calls was challenging due to our limited experience.
- **Real-Time Interaction:** Ensuring smooth and realistic interactions between users and AI avatars required significant fine-tuning.

## Accomplishments
- **User-Centric Design:** Prioritized user experience throughout the design process.
- **AI Avatar Development:** Successfully developed and tested the virtual interview avatar feature.
- **Comprehensive Feedback:** Implemented a robust feedback system that provides personalized insights.

## Lessons Learned
- **Importance of Personalized Feedback:** Recognized the value of real-time, personalized feedback in improving interview preparation.
- **Team Collaboration:** Gained insights into effective team management and integrating frontend and backend development.

## Future Plans
- **Enhanced Personalization:** Incorporate users' past interview results to tailor future questions.
- **Interviewer Selection:** Allow users to choose their AI interviewer based on specific roles or companies.
- **Detailed Feedback:** Record interviews and provide timestamped comments for specific feedback points.


## Detected evidence (automated analysis)

Indexed codebase: 13 recognized source files, 22 KB.
- CSS (language) — detected in the code
- JavaScript (language) — detected in the code
- Next.js (technology) — detected in the code
- OpenAI (technology) — detected in the code
- React (technology) — detected in the code
- TypeScript (language) — detected in the code
- Python (language) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (18 of 18)

```
.gitignore
jsconfig.json
next.config.mjs
package.json
README.md
src/app/globals.css
src/app/interview/meeting/page.js
src/app/interview/meeting/page.module.css
src/app/interview/page.js
src/app/interview/page.module.css
src/app/layout.js
src/app/page.js
src/app/page.module.css
src/app/ui/fonts.ts
src/app/ui/navbar.css
src/app/ui/navbar.js
src/app/ui/navItem.js
tsconfig.json
```

### Dependencies

- package.json: @types/react@18.2.56, next@14.1.0, openai@^4.28.0, react@^18, react-dom@^18, typescript@5.3.3

### Recent commits (newest first)

- README.md
- README.md
- feat: add backend
- meeting page
- interview page
- basic skeleton
- Initial commit from Create Next App

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

### package.json

```
{
  "name": "treehack24",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "next": "14.1.0",
    "openai": "^4.28.0",
    "react": "^18",
    "react-dom": "^18"
  },
  "devDependencies": {
    "@types/react": "18.2.56",
    "typescript": "5.3.3"
  }
}

```

### src/app/layout.js

```javascript
import { Inter } from "next/font/google";
import "./globals.css";
import Navbar from "./ui/navbar";

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

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

// export default function RootLayout({ children }) {
//   return (
//     <html lang="en">
//       <body className={inter.className}>{children}</body>
//     </html>
//   );
// }

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body className={inter.className}>
        <Navbar />
        {children}
      </body>
    </html>
  );
}

```

### src/app/page.js

```javascript
import Image from "next/image";
import styles from "./page.module.css";
import { roboto } from "./ui/fonts";
import Link from "next/link";

export default function Home() {
  return (
    <div className={styles.main}>
      <div
        className={styles.areYouReady}
      >{`Are you ready to ace your next job interview with confidence? Say hello to Ai&U – your personalized interview preparation assistant powered by cutting-edge artificial intelligence technology.`}</div>
      <div className={styles.frame}>
        <div className={styles.boostYourConfidenceContainer}>
          <p className={styles.boostYour}>Boost your</p>
          <p className={styles.boostYour}>{`confidence `}</p>
          <p className={styles.withAiu}>
            <span className={styles.with}>{`with `}</span>
            <span className={styles.aiu}>{`Ai&U`}</span>
          </p>
        </div>
        <div className={styles.experienceNowWrapper}>
          <Link href={"/interview"}>
            <div className={styles.experienceNow}>Experience Now</div>
          </Link>
        </div>
        <div className={styles.anAiPowered}>
          An AI powered platform to help you ace your interviews
        </div>
        <Image
          className={styles.image9Icon}
          src={"/landing2.png"}
          width="440"
          height="280"
        />
        <Image
          className={styles.image8Icon}
          src={"/landing1.png"}
          width="490"
          height="320"
        />
        {/* <img className={styles.image9Icon} alt="" src="/image-9@2x.png" />
        <img className={styles.image8Icon} alt="" src="/image-8@2x.png" /> */}
      </div>
    </div>
  );
}

```

### src/app/interview/page.js

```javascript
"use client";
import { useState } from "react";
import styles from "./page.module.css";
import Image from "next/image";
import { redirect } from "next/navigation";

export default function Home() {
  const [formData, setFormData] = useState({
    jobTitle: "",
    jobDescription: "",
    additionalDetails: "",
  });
  const [isVisible, setIsVisible] = useState(false);

  const handleChange = (e) => {
    const { name, value } = e.target;
    setFormData((prevState) => ({
      ...prevState,
      [name]: value,
    }));
  };

  const handleSubmit = async (e) => {
    //MANUALLY redict to meeting page
    redirect("/interview/meeting");
    e.preventDefault(); // Prevent the default form submit action

    // Here you can handle the submission to your backend, for example:
    try {
      const response = await fetch("/api/submit-job", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify(formData),
      });

      if (response.ok) {
        // Handle successful submission here
        alert("Job submitted successfully!");
        // Reset form or redirect user
        setFormData({
          jobTitle: "",
          jobDescription: "",
          additionalDetails: "",
        });
      } else {
        // Handle errors here
        alert("Submission failed.");
      }
    } catch (error) {
      console.error("Submission error:", error);
      alert("Submission error.");
    }
  };
  const submitForm = () => {
    document.getElementById("jobForm").submit();
  };
  return (
    <div className={styles.main}>
      <div className={styles.left}>
        <p style={{ "font-size": 32, "font-weight": 700 }}>
          Tell us about yourself.
        </p>
        <form onSubmit={handleSubmit} className={styles.form} id="jobForm">
          <div>
            <label htmlFor="jobTitle">Job Title</label>
            <br />
            <textarea
              type="text"
              id="jobTitle"
              name="jobTitle"
              value={formData.jobTitle}
              placeholder="Enter the job title"
              onChange={handleChange}
              className={styles.textarea}
            />
          </div>
          <div>
            <label htmlFor="jobDescription">Job Description</label>
            <br />
            <textarea
              id="jobDescription"
              name="jobDescription"
              value={formData.jobDescription}
              placeholder="Enter the job description, the company, location, and any other job related information."
              onChange={handleChange}
              className={styles.textarea}
            />
          </div>
          <div>
            <label htmlFor="additionalDetails">Additional Details</label>
            <br />
            <textarea
              id="additionalDetails"
              name="additionalDetails"
              value={formData.additionalDetails}
              placeholder="Enter any additional information."
              onChange={handleChange}
              className={styles.textarea}
            />
          </div>
          <div>
            <label htmlFor="chooseInterview">Choose your AI interviewer:</label>
          </div>
        </form>
      </div>
      <div className={styles.right}>
        <Image
          src="/interview.png"
          width="537"
          height="323"
          alt="interviewer"
        />
        <div className={styles.text}>
          Ready to embark on your journey to interview success? Click the button
          below to kickstart your interactive AI interview experience
        </div>
        <button onClick={submitForm} className={styles.button}>
          Begin interview
        </button>
        <div style={{ flexDirection: "row", display: "flex" }}>
          <input
            type="checkbox"
            id="toggleContent"
            checked={isVisible}
            onChange={(e) => setIsVisible(e.target.checked)}
          />
          <div>I understand my interview will be recorded</div>
        </div>
      </div>
    </div>
  );
}

```

### src/app/interview/meeting/page.js

```javascript
// buttons all hardcoded to direct to home page
import styles from "./page.module.css";
import Image from "next/image";
import Link from "next/link";
export default function Home() {
  return (
    <div className={styles.main}>
      <h1>Interview with AI Joe</h1>
      <div className={styles.convoWrapper}>
        <div className={styles.intvwrBlock}>
          <Image
            src="/interviewer_placeholder.png"
            width="76"
            height="66"
            alt="interviewer icon"
            className={styles.profile}
          />
          <div className={styles.intvwrText}>
            How do you think your experiences support your goal of becoming a
            full stack developer?
          </div>
        </div>
      </div>
      <div className={styles.videoWrapper}>
        <Image
          src="/interviewer_placeholder.png"
          width="537"
          height="323"
          alt="interviewer video"
          className={styles.video}
        />
        <Image
          src="/interviewer_placeholder.png"
          width="537"
          height="323"
          alt="interviewee video"
          className={styles.video}
        />
      </div>
      <div className={styles.icons}>
        <Link href="/">
          <Image
            src="/icons/microphone.svg"
            width="55"
            height="55"
            alt="microphone button"
          />
        </Link>
        <Link href="/">
          <Image
            src="/icons/video.svg"
            width="55"
            height="55"
            alt="video button"
          />
        </Link>
        <Link href="/">
          <Image
            src="/icons/share.svg"
            width="55"
            height="55"
            alt="sharing button"
          />
        </Link>
        <Link href="/">
          <Image
            src="/icons/more.svg"
            width="55"
            height="55"
            alt="more options button"
          />
        </Link>
        <Link href="/">
          <Image
            src="/icons/endcall.svg"
            width="55"
            height="55"
            alt="end call button"
          />
        </Link>
        <Link href="/">
          <Image
            src="/icons/info.png"
            width="35"
            height="35"
            alt="more info button"
          />
        </Link>
      </div>
    </div>
  );
}

```

### src/app/globals.css

```css
@import url("https://fonts.googleapis.com/css2?family=Sarabun:wght@300;400;600&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@600&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Josefin+Sans:wght@600&display=swap");
:root {
  --max-width: 1100px;
  --border-radius: 12px;
  --font-mono: ui-monospace, Menlo, Monaco, "Cascadia Mono", "Segoe UI Mono",
    "Roboto Mono", "Oxygen Mono", "Ubuntu Monospace", "Source Code Pro",
    "Fira Mono", "Droid Sans Mono", "Courier New", monospace;

  --foreground-rgb: 0, 0, 0;
  --background-start-rgb: 214, 219, 220;
  --background-end-rgb: 255, 255, 255;

  --primary-glow: conic-gradient(
    from 180deg at 50% 50%,
    #16abff33 0deg,
    #0885ff33 55deg,
    #54d6ff33 120deg,
    #0071ff33 160deg,
    transparent 360deg
  );
  --secondary-glow: radial-gradient(
    rgba(255, 255, 255, 1),
    rgba(255, 255, 255, 0)
  );

  --tile-start-rgb: 239, 245, 249;
  --tile-end-rgb: 228, 232, 233;
  --tile-border: conic-gradient(
    #00000080,
    #00000040,
    #00000030,
    #00000020,
    #00000010,
    #00000010,
    #00000080
  );

  --callout-rgb: 238, 240, 241;
  --callout-border-rgb: 172, 175, 176;
  --card-rgb: 180, 185, 188;
  --card-border-rgb: 131, 134, 135;

  /* fonts */
    --font-sarabun: Sarabun;
    --font-josefin-sans: "Josefin Sans";
    --font-inter: Inter;
  
    /* font sizes */
    --font-size-5xl: 24px;
    --font-size-xl: 20px;
  
    /* Colors */
    --color-white: #fff;
    --purple-blue: #3932e5;
  
    /* Border radiuses */
    --br-mini: 15px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --foreground-rgb: 255, 255, 255;
    --background-start-rgb: 0, 0, 0;
    --background-end-rgb: 0, 0, 0;

    --primary-glow: radial-gradient(rgba(1, 65, 255, 0.4), rgba(1, 65, 255, 0));
    --secondary-glow: linear-gradient(
      to bottom right,
      rgba(1, 65, 255, 0),
      rgba(1, 65, 255, 0),
      rgba(1, 65, 255, 0.3)
    );

    --tile-start-rgb: 2, 13, 46;
    --tile-end-rgb: 2, 5, 19;
    --tile-border: conic-gradient(
      #ffffff80,
      #ffffff40,
      #ffffff30,
      #ffffff20,
      #ffffff10,
      #ffffff10,
      #ffffff80
    );

    --callout-rgb: 20, 20, 20;
    --callout-border-rgb: 108, 108, 108;
    --card-rgb: 100, 100, 100;
    --card-border-rgb: 200, 200, 200;
  }
}

* {
  box-sizing: border-box;
  padding: 10;
  margin: 10;
}

html,
body {
  max-width: 100vw;
  overflow-x: hidden;
}
a {
  color: inherit;
  text-decoration: none;
}

@media (prefers-color-scheme: dark) {
  html {
    color-scheme: dark;
  }
}
body {
  margin: 0;
  line-height: normal;
}
```

### src/app/page.module.css

```css
.frameChild {
  width: 35px;
  position: relative;
  height: 35px;
}

.interview {
  position: relative;
  line-height: 22.4px;
  font-weight: 300;
}

.interviewParent {
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  justify-content: flex-start;
  gap: 62px;
}

.frameParent {
  gap: 61px;
}

.componentParent,
.frameParent,
.frameWrapper {
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  justify-content: flex-start;
}

.componentParent {
  position: absolute;
  top: 78px;
  left: 0;
  width: 1164px;
  align-items: center;
  justify-content: flex-end;
  gap: 182px;
}

.areYouReady {
  position: absolute;
  top: 822px;
  left: 313px;
  font-size: var(--font-size-5xl);
  line-height: 22.4px;
  font-weight: 600;
  text-align: center;
  display: -webkit-inline-box;
  overflow: hidden;
  text-overflow: ellipsis;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  width: 886px;
}

.boostYour {
  margin-block-start: 0;
  margin-block-end: 5px;
}

.aiu,
.boostYour,
.with {
  font-weight: 600;
}

.aiu {
  font-family: var(--font-josefin-sans);
  background: linear-gradient(178.39deg, #fff, #72d3f6);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}

.withAiu {
  margin: 0;
}

.boostYourConfidenceContainer {
  position: absolute;
  top: 29px;
  left: 0;
  display: inline-block;
  width: 442px;
  height: 260px;
  font-family: var(--font-inter);
}

.experienceNow {
  cursor: pointer;
  display: flex;
  width: 324px;
  height: 47px;
  padding: 12px 17px;
  justify-content: center;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
  border-radius: 8px;
  background: #FFF;
  border: none;
  /* font-family: var(--font-inter); */
  color: var(--Purple-blue, #3932E5);
  font-family: Sarabun;
  font-size: 24px;
}

.experienceNowWrapper {
  position: absolute;
  top: 429px;
  left: 4px;
  border-radius: 8px;
  /* background-color: var(--color-white); */
  width: 324px;
  height: 47px;
  overflow: hidden;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  padding: 12px 17px;
  box-sizing: border-box;
  font-size: var(--font-size-5xl);
  color: var(--purple-blue);
}

.anAiPowered {
  position: absolute;
  top: 323px;
  left: 13px;
  font-size: 16px;
  line-height: 22.4px;
  display: inline-block;
  width: 256px;
  height: 60px;
}

.image8Icon,
.image9Icon {
  position: absolute;
  top: 0;
  left: 732px;
  border-radius: var(--br-mini);
  width: 490px;
  height: 319px;
  object-fit: cover;
}

.image8Icon {
  top: 211px;
  left: 551px;
  width: 436px;
  height: 283px;
}

.frame {
  position: absolute;
  top: 239px;
  left: 140px;
  width: 1222px;
  height: 494px;
  overflow: hidden;
  font-size: 72px;
}

.landingPage {
  width: 100%;
  position: relative;
  background-color: #362fcb;
  height: 982px;
  overflow: hidden;
  text-align: left;
  font-size: var(--font-size-xl);
  color: var(--color-white);
  font-family: var(--font-sarabun);
}
.main {
  background-color: #362fcb;
}
```

### src/app/ui/fonts.ts

```typescript
import { Roboto, Quicksand } from 'next/font/google';
 
export const roboto = Roboto({ subsets: ['latin'], weight: '400' });
export const quicksand = Quicksand({ subsets: ['latin'], weight: '400' });
```

### src/app/ui/navItem.js

```javascript
import Link from "next/link";
const NavItem = ({ text, href, active }) => {
  return (
    <Link href={href}>
      <div className={`nav__item ${active ? "active" : ""}`}>{text}</div>
    </Link>
  );
};

export default NavItem;

```

### src/app/ui/navbar.css

```css
.nav__menu-list {
    display: flex;
    gap: 60px;
    align-items: center;
}

nav {
    display: flex;
    flex-direction: row;
    gap: 120px;
    padding-left: 150px;
    padding-top: 80px;
    font-size: 20px;
    text-transform: lowercase;
    color:#362fcb;
}
```

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