# Project export: Scrapbook

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: Cal Hacks 10.0
- Tagline: While conducting research at UCSF, a grandfather with Alzheimers had access to a Google Doc, filled with hundreds of memories his family wanted him to remember. I decided to make him a site instead.
- Devpost: https://devpost.com/software/scrapbook-5h0f4v
- GitHub: https://github.com/garvcodes/nailfungus
- Result: winner (Best Designed Human-Computer Interaction)
- Team: 3 GitHub contributor(s) — Garv (13 commits), Yash Jain (3 commits), ronitjain10 (3 commits)

## Devpost submission (written by the team)

### Inspiration

While a member of my team was conducting research at UCSF, he noticed a family partaking in a beautiful, albeit archaic, practice. They gave their grandfather access to a google doc, where each family member would write down the memories that they have with him. Nearly every day, the grandfather would scroll through the doc and look at the memories that him and his family wanted him to remember.

### What it does

Much like the Google Doc does, our site stores memories inputted by either the main account holder themself, or other people who have access to the account, perhaps through a shared family email. From there, the memories show up on the users feed and are tagged with the emotion they indicate. Someone with Alzheimers can easily search through their memories to find what they are looking for. In addition, our Chatbot feature trained on their memories also allows users to easily talk to the app directly, asking what they are looking for.

### How we built it

Next.js, React, Node.js, Tailwind, etc.

### Challenges we ran into

It was difficult implementing our chatbot in a way where it is automatically update with data that our user inputs into the site. Moreover, we were working with React for the first time and faced many challenges trying to build out and integrate the different technologies into our website including setting up MongoDB, Flask, and different APIs.

### Accomplishments we're proud of

Getting this done! Our site is polished and carries out our desired functions well!

### What we learned

As beginners, we were introduced to full-stack development!

### What's next

We'd like to introduce Scrapbook to medical professionals at UCSF and see their thoughts on it.

## README (from the GitHub repository)

# Scrapbook

Scrapbook is meant as a memory database for families affected by Alzheimer's. Active recall has proven to be helpful in slowing/improving the progress of the disease, so Scrapbook was created in the hopes that those afflicted would be able to look at their memories and, well, recall them.


## Detected evidence (automated analysis)

Indexed codebase: 30 recognized source files, 36 KB.
- CSS (language) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- MongoDB (technology) — detected in the code
- Next.js (technology) — detected in the code
- OpenAI (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
- Node.js (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (41 of 41)

```
.env
.eslintrc.json
.gitignore
app/api/answer/openai.js
app/api/auth/[...nextauth]/route.js
app/api/create-pmpt/page.jsx
app/api/prompt/new/route.js
app/api/prompt/route.js
app/chatbot/page.html
app/create-prompt/page.jsx
app/Functions/GPT/chatgpt.py
app/Functions/GPT/constants.py
app/Functions/GPT/data/_Users_yashjain_Documents_Zoom_myMemories (1).txt
app/Functions/GPT/data/_Users_yashjain_Documents_Zoom_myMemories.txt
app/Functions/GPT/data/data.txt
app/Functions/OCR/reader.py
app/layout.jsx
app/mindsdb/mindsdb.js
app/page.jsx
app/tell-story/page.jsx
cache/webpack/client-development/index.pack.gz.old
cache/webpack/server-development/index.pack.gz.old
components/Feed.jsx
components/Form.jsx
components/Nav.jsx
components/Profile.jsx
components/PromptCard.jsx
components/Provider.jsx
components/Story.jsx
jsconfig.json
models/prompt.js
models/user.js
next.config.js
package.json
postcss.config.js
README.md
styles/globals.css
tailwind.config.js
tailwind.config.ts
tsconfig.json
utils/database.js
```

### Dependencies

- package.json: @types/node@^20, @types/react@^18, @types/react-dom@^18, autoprefixer@^10, axios@^1.6.0, bcrypt@^5.1.1, chatgpt@^5.2.5, eslint@^8, eslint-config-next@13.5.6, lamejs@^1.2.1, mongodb@^6.2.0, mongoose@^7.6.3, next@13.5.6, next-auth@^4.24.3, openai@^4.14.1, postcss@^8, react@^18.2.0, react-dom@^18, tailwindcss@^3.3.3, typescript@^5

### Recent commits (newest first)

- Update README.md
- Update README.md
- ye
- done
- what
- flaskk
- adding
- chatbot
- adding tell-story functionality
- erge branch 'main' of https://github.com/garvcodes/nailfungus
- Created pipeline
- adding tell-story functionality
- mindsDB connected
- search done
- yer
- sleep time
- luh twizz
- search bar and feed done
- luh tweak
- data connected

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

### package.json

```
{
  "name": "authapp",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "axios": "^1.6.0",
    "bcrypt": "^5.1.1",
    "chatgpt": "^5.2.5",
    "lamejs": "^1.2.1",
    "mongodb": "^6.2.0",
    "mongoose": "^7.6.3",
    "next": "13.5.6",
    "next-auth": "^4.24.3",
    "openai": "^4.14.1",
    "react": "^18.2.0",
    "react-dom": "^18"
  },
  "devDependencies": {
    "@types/node": "^20",
    "@types/react": "^18",
    "@types/react-dom": "^18",
    "autoprefixer": "^10",
    "eslint": "^8",
    "eslint-config-next": "13.5.6",
    "postcss": "^8",
    "tailwindcss": "^3.3.3",
    "typescript": "^5"
  }
}

```

### app/page.jsx

```javascript
import Feed from "@components/Feed";

const Home = () => (
  <section className='w-full flex-center flex-col'>
    <h1 className='head_text text-center'>
      Use Modern AI to 
      <br className='max-md:hidden' />
      <span className='orange_gradient text-center'> Take Back Control from Alzheimers</span>
    </h1>
    <p className='desc text-center'>
      Where your brain falters, we pick up the slack. Live your life and make some memories, let us worry about keeping them. 
    </p>


    <Feed />

    
  </section>
);

export default Home;
```

### app/layout.jsx

```javascript
import "@styles/globals.css";

import Nav from "@components/Nav";
import Provider from "@components/Provider";

export const metadata = {
  title: "Scrapbook",
  description: "Talk, Memorize, Remember",
};

const RootLayout = ({ children }) => (
  <html lang='en'>
    <body className = 'bg-gradient-to-r from-indigo-200 via-red-200 to-yellow-100'>
      <Provider>
        <div className='main'>
          <div className='background' />
        </div>

        <main className='app'>
          <Nav />
          {children}
        </main>
      </Provider>
    </body>
  </html>
);

export default RootLayout;
```

### app/create-prompt/page.jsx

```javascript
"use client";

import { useState } from "react";
import { useSession } from "next-auth/react";
import { useRouter } from "next/navigation";

import Form from "@components/Form";

const CreatePrompt = () => {
  const router = useRouter();
  const { data: session } = useSession();

  const [submitting, setIsSubmitting] = useState(false);
  const [post, setPost] = useState({ prompt: "", tag: "" });

  const createPrompt = async (e) => {
    e.preventDefault();
    setIsSubmitting(true);

    try {
      const response = await fetch("/api/prompt/new", {
        method: "POST",
        body: JSON.stringify({
          prompt: post.prompt,
          userId: session?.user.id,
          tag: post.tag,
        }),
      });

      if (response.ok) {
        router.push("/");
      }
    } catch (error) {
      console.log(error);
    } finally {
      setIsSubmitting(false);
    }
  };

  return (
    <Form
      type='Create'
      post={post}
      setPost={setPost}
      submitting={submitting}
      handleSubmit={createPrompt}
    />
  );
};

export default CreatePrompt;
```

### app/tell-story/page.jsx

```javascript
"use client";

import { useState } from "react";
import { useSession } from "next-auth/react";
import { useRouter } from "next/navigation";

import Form from "@components/Story";

const CreatePrompt = () => {
  const router = useRouter();
  const { data: session } = useSession();

  const [submitting, setIsSubmitting] = useState(false);
  const [post, setPost] = useState({ prompt: "", tag: "" });

  const createPrompt = async (e) => {
    e.preventDefault();
    setIsSubmitting(true);

    try {
      const response = await fetch("/api/prompt/new", {
        method: "POST",
        body: JSON.stringify({
          prompt: post.prompt,
          userId: session?.user.id,
          tag: post.tag,
        }),
      });

      if (response.ok) {
        router.push("/");
      }
    } catch (error) {
      console.log(error);
    } finally {
      setIsSubmitting(false);
    }
  };

  return (
    <Form
      type='Create'
      post={post}
      setPost={setPost}
      submitting={submitting}
      handleSubmit={createPrompt}
    />
  );
};

export default CreatePrompt;
```

### app/api/prompt/route.js

```javascript
import { connectToDB } from '@utils/database';
import Prompt from '@models/prompt';

export const GET = async (request) => {
    try {
        await connectToDB();

        const prompts = await Prompt.find({}).populate
        ('creator');

        return new Response(JSON.stringify(prompts), {
            status: 200})
    } catch(error) {
        return new Response ("Failed to get memories", {status: 500})
    }
}
```

### app/api/create-pmpt/page.jsx

```javascript
'use client';

import { useState } from 'react';
import { useSession } from 'next-auth/react'
import { useRouter } from 'next/navigation'

import Form from '@components/Form'
import Router from 'next/router';



const CreatePmpt = () => {

    const [submitting, setSubmitting] = useState(false);
    const [post, setPost] = useState({
        prompt: '',
        tag: '',
    });

    const createPmpt = async (e) =>{
      e.preventDefault();
      setSubmitting(true);

      try{

        const response = await fetch('api/prompt/new',
        {
          method: 'POST',
          body: JSON.stringify({
            prompt: post.prompt,
            userId: session?.user.id,
            tag:post.tag
          })
        })

        if(response.ok) {
          Router.push('/')
        }

      } catch(error) {
        console.log(error);
      } finally {
        setSubmitting(false);
      }

    }

  return (
    <Form
        type = "Create"
        post = {post}
        setPost = {setPost}
        submitting = {submitting}
        handleSubmit = {createPmpt}
        />
  )
}

export default CreatePmpt
```

### app/api/prompt/new/route.js

```javascript
import Prompt from "@models/prompt";
import { connectToDB } from "@utils/database";

export const POST = async (req) => {
    const { userId, prompt, tag } = await req.json();

    try {
        await connectToDB();
        const newPrompt = new Prompt ({
            creator: userId,
            prompt,
            tag
        })

        await newPrompt.save();

        return new Response(JSON.stringify(newPrompt), {
            status: 201})


    }catch (error){
        return new Response("Failed to create new prompt", {status: 500})
    }
}
```

### app/api/auth/[...nextauth]/route.js

```javascript
import NextAuth from 'next-auth';
import GoogleProvider from 'next-auth/providers/google';

import User from '@models/user';
import { connectToDB } from '@utils/database';

const handler = NextAuth({
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
    })
  ],
  callbacks: {
    async session({ session }) {
      // store the user id from MongoDB to session
      const sessionUser = await User.findOne({ email: session.user.email });
      session.user.id = sessionUser._id.toString();

      return session;
    },
    async signIn({ account, profile, user, credentials }) {
      try {
        await connectToDB();

        // check if user already exists
        const userExists = await User.findOne({ email: profile.email });

        // if not, create a new document and save user in MongoDB
        if (!userExists) {
          await User.create({
            email: profile.email,
            username: profile.name.replace(" ", "").toLowerCase(),
            image: profile.picture,
          });
        }

        return true
      } catch (error) {
        console.log("Error checking if user exists: ", error.message);
        return false
      }
    },
  }
})

export { handler as GET, handler as POST }

```

### postcss.config.js

```javascript
module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
}

```

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