# Project export: Study Buddy

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: CruzHacks 2026
- Tagline: Do you want a study buddy to help you study faster and efficiently for your classes? Introducing your friendly companion, Study Buddy :)
- Devpost: https://devpost.com/software/study-buddy-finwat
- GitHub: https://github.com/ArneshKumar/Study-Buddy
- Video: https://www.youtube.com/embed/HKcUqHGSeo4?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 1 GitHub contributor(s) — ArneshKumar (2 commits)

## Devpost submission (written by the team)

### Inspiration

Me and my friends were struggling with some exams, so we decided to make something that can help save time and make it easier to study, since it would take way longer to review every lecture video and slides. Building Stage We built our project by first allowing the user to upload any audio or video file, then used AssemblyAI API for speech to text in terms of generating a transcript from the file. We finally used Groq AI API to generate a set of flashcards, fill in the blank questions, and multiple choice questions based on the transcript that was generated from the file. We built a login page through Firebase Authentication for future development, which is functional at the moment, but we did not have any further uses of the functionality. We were planning to implement a history tracker, where it tracks the user's previously selected notes for future reference. Challenges We had to figure out how to set up our API keys for AssemblyAI API and Groq AI API, as well as understanding how to leverage those APIs in our project. We also ran into issues with Groq AI API as we had to set up a backend server, where we experienced rate limits through the debugging process. Finally, we had live share collaboration issues that made it tougher to work together on various parts of the project.

## README (from the GitHub repository)

# React + TypeScript + Vite

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.

Currently, two official plugins are available:

- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh

## Expanding the ESLint configuration

If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:

```js
export default tseslint.config({
  extends: [
    // Remove ...tseslint.configs.recommended and replace with this
    ...tseslint.configs.recommendedTypeChecked,
    // Alternatively, use this for stricter rules
    ...tseslint.configs.strictTypeChecked,
    // Optionally, add this for stylistic rules
    ...tseslint.configs.stylisticTypeChecked,
  ],
  languageOptions: {
    // other options...
    parserOptions: {
      project: ['./tsconfig.node.json', './tsconfig.app.json'],
      tsconfigRootDir: import.meta.dirname,
    },
  },
})
```

You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:

```js
// eslint.config.js
import reactX from 'eslint-plugin-react-x'
import reactDom from 'eslint-plugin-react-dom'

export default tseslint.config({
  plugins: {
    // Add the react-x and react-dom plugins
    'react-x': reactX,
    'react-dom': reactDom,
  },
  rules: {
    // other rules...
    // Enable its recommended typescript rules
    ...reactX.configs['recommended-typescript'].rules,
    ...reactDom.configs.recommended.rules,
  },
})
```

## Detected evidence (automated analysis)

Indexed codebase: 24 recognized source files, 60 KB.
- CSS (language) — detected in the code
- Express (technology) — detected in the code
- Firebase (technology) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- React (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code
- TypeScript (language) — detected in the code
- Node.js (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (28 of 28)

```
eslint.config.js
index.html
package.json
README.md
server/index.js
src/App.css
src/App.tsx
src/firebase.ts
src/globals.d.ts
src/index.css
src/main.tsx
src/pages/FillInTheBlanks.css
src/pages/FillInTheBlanks.tsx
src/pages/FlashCards.css
src/pages/FlashCards.tsx
src/pages/Homepage.css
src/pages/Homepage.tsx
src/pages/Login.css
src/pages/Login.tsx
src/pages/MultipleChoice.css
src/pages/MultipleChoice.tsx
src/pages/Notes.css
src/pages/Notes.tsx
src/vite-env.d.ts
tsconfig.app.json
tsconfig.json
tsconfig.node.json
vite.config.ts
```

### Dependencies

- package.json: @eslint/js@^9.21.0, @tailwindcss/vite@^4.1.3, @types/react@^19.0.10, @types/react-dom@^19.0.4, @vitejs/plugin-react@^4.3.4, assemblyai@^4.9.0, cors@^2.8.5, dotenv@^17.2.3, eslint@^9.21.0, eslint-plugin-react-hooks@^5.1.0, eslint-plugin-react-refresh@^0.4.19, express@^5.2.1, firebase@^12.8.0, globals@^15.15.0, node-fetch@^3.3.2, react@^19.0.0, react-dom@^19.0.0, react-router-dom@^7.5.3, tailwindcss@^4.1.3, typescript@~5.7.2, typescript-eslint@^8.24.1, vite@^6.2.0

### Recent commits (newest first)

- Add files via upload
- Added project files

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

### package.json

```
{
  "name": "ace-my-classes",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite --host",
    "build": "tsc -b && vite build",
    "lint": "eslint .",
    "preview": "vite preview"
  },
  "dependencies": {
    "assemblyai": "^4.9.0",
    "cors": "^2.8.5",
    "dotenv": "^17.2.3",
    "express": "^5.2.1",
    "firebase": "^12.8.0",
    "node-fetch": "^3.3.2",
    "react": "^19.0.0",
    "react-dom": "^19.0.0",
    "react-router-dom": "^7.5.3"
  },
  "devDependencies": {
    "@eslint/js": "^9.21.0",
    "@tailwindcss/vite": "^4.1.3",
    "@types/react": "^19.0.10",
    "@types/react-dom": "^19.0.4",
    "@vitejs/plugin-react": "^4.3.4",
    "eslint": "^9.21.0",
    "eslint-plugin-react-hooks": "^5.1.0",
    "eslint-plugin-react-refresh": "^0.4.19",
    "globals": "^15.15.0",
    "tailwindcss": "^4.1.3",
    "typescript": "~5.7.2",
    "typescript-eslint": "^8.24.1",
    "vite": "^6.2.0"
  }
}

```

### src/main.tsx

```typescript
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.tsx'

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <App />
  </StrictMode>,
)

```

### src/App.tsx

```typescript
// import { useState } from "react";
// import reactLogo from "./assets/react.svg";
// import viteLogo from "/vite.svg";
import "./App.css";
import Homepage from "./pages/Homepage.tsx";
import Notes from "./pages/Notes.tsx";
import FlashCards from "./pages/FlashCards.tsx";
import Login from "./pages/Login.tsx";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import FillInTheBlanks from "./pages/FillInTheBlanks.tsx";
import MultipleChoice from "./pages/MultipleChoice.tsx";

export interface IApplicationProps {}

const App: React.FunctionComponent<IApplicationProps> = (props) => {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Homepage />} />
        <Route path="/login" element={<Login />} />      
        <Route path="/Notes" element={<Notes />} />
        <Route path="/Flashcards" element={<FlashCards />} />
        <Route path="/MCQ" element={<MultipleChoice />} />
        <Route path="/FillInTheBlanks" element={<FillInTheBlanks />} />
      </Routes>
    </BrowserRouter>
  );
};

export default App;

```

### server/index.js

```javascript
import express from "express";
import cors from "cors";
import dotenv from "dotenv";
import fetch from "node-fetch";

dotenv.config();

const app = express();
app.use(cors());
app.use(express.json());

app.post("/api/flashcards", async (req, res) => {
  try {
    // 1. EXTRACT prompt FROM req.body
    // We expect the frontend to send { transcript: "...", prompt: "..." }
    const { transcript, prompt } = req.body;

    // 2. Validation
    if (!transcript || !prompt) {
        return res.status(400).json({ error: "Transcript or Prompt is missing" });
    }

    const response = await fetch(
      "https://api.groq.com/openai/v1/chat/completions",
      {
        method: "POST",
        headers: {
          Authorization: `Bearer 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`, 
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          model: "llama-3.3-70b-versatile",
          temperature: 0,
          messages: [
            {
              role: "user",
              // 3. USE THE RECEIVED PROMPT VARIABLE
              content: prompt, 
            },
          ],
        }),
      }
    );

    const data = await response.json();

    if (!response.ok) {
        console.error("Groq API Error:", data); 
        return res.status(response.status).json({ error: data.error || "Groq API error" });
    }

    res.json(data);
  } catch (err) {
    console.error("Backend error:", err);
    res.status(500).json({ error: "Internal Server Error" });
  }
});



app.listen(3001, () => {
  console.log("Backend running on http://localhost:3001");
});
```

### vite.config.ts

```typescript
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

// https://vite.dev/config/
export default defineConfig({
  plugins: [react()],
})
```

### index.html

```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite + React + TS</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>
```

### eslint.config.js

```javascript
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from 'typescript-eslint'

export default tseslint.config(
  { ignores: ['dist'] },
  {
    extends: [js.configs.recommended, ...tseslint.configs.recommended],
    files: ['**/*.{ts,tsx}'],
    languageOptions: {
      ecmaVersion: 2020,
      globals: globals.browser,
    },
    plugins: {
      'react-hooks': reactHooks,
      'react-refresh': reactRefresh,
    },
    rules: {
      ...reactHooks.configs.recommended.rules,
      'react-refresh/only-export-components': [
        'warn',
        { allowConstantExport: true },
      ],
    },
  },
)
```

### src/vite-env.d.ts

```typescript
/// <reference types="vite/client" />

```

### src/App.css

```css
#root{
  max-width: 100vw;
  margin: 0 auto;
  padding: 2rem;
  text-align: center;
}

.logo {
  height: 6em;
  padding: 1.5em;
  will-change: filter;
  transition: filter 300ms;
}
.logo:hover {
  filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.react:hover {
  filter: drop-shadow(0 0 2em #61dafbaa);
}

@keyframes logo-spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

@media (prefers-reduced-motion: no-preference) {
  a:nth-of-type(2) .logo {
    animation: logo-spin infinite 20s linear;
  }
}

.card {
  padding: 2em;
}

.read-the-docs {
  color: #888;
}


```

### src/firebase.ts

```typescript
import { initializeApp } from "firebase/app";
import { 
  getAuth, 
  GoogleAuthProvider, 
  signInWithPopup, 
  signInWithEmailAndPassword, 
  createUserWithEmailAndPassword, 
  signOut 
} from "firebase/auth";

const firebaseConfig = {
  apiKey: "AIzaSyCL6hreumjGbqdLJaKHps01q4b7RM8jFrM",
  authDomain: "studybuddy-auth-638f9.firebaseapp.com",
  projectId: "studybuddy-auth-638f9",
  storageBucket: "studybuddy-auth-638f9.firebasestorage.app",
  messagingSenderId: "386516254236",
  appId: "1:386516254236:web:cde6aa8e7e87ef74e569d9",
  measurementId: "G-D90E05Q154"
};

const app = initializeApp(firebaseConfig);

// 1. Export the Auth instance
export const auth = getAuth(app);

// 2. Export the Google Provider
export const googleProvider = new GoogleAuthProvider();

// 3. Google Sign-In Function
export const signInWithGoogle = async () => {
  try {
    const result = await signInWithPopup(auth, googleProvider);
    return result.user;
  } catch (error) {
    console.error("Error signing in with Google", error);
  }
};

// 4. Export Email/Password Functions directly
export { signInWithEmailAndPassword, createUserWithEmailAndPassword };

// 5. Logout Function
export const logout = () => {
  signOut(auth);
};
```

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