# Project export: AutoCart

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: Your copilot for meal-prep and grocery shopping
- Devpost: https://devpost.com/software/autocart-0o8qup
- GitHub: https://github.com/jchao01/treehacks-mealprep.git
- Demo: https://github.com/jchao01/treehacks-mealprep-python
- Team: 1 GitHub contributor(s) — Jason Chao (1 commits)

## Devpost submission (written by the team)

No Devpost description available.

## README (from the GitHub repository)

# YakGPT

A simple, locally running ChatGPT UI that makes your text generation faster and chatting even more engaging!

## Features

- **GPT 3.5 & GPT 4** via OpenAI API
- **Speech-to-Text** via Azure & OpenAI Whisper
- **Text-to-Speech** via Azure & Eleven Labs
- Run locally on browser – no need to install any applications
- Faster than the official UI – connect directly to the API
- Easy mic integration – no more typing!
- Use your own API key – ensure your data privacy and security
- Data submitted via the API is not used for training and stored for 30 days only
- All state stored locally in localStorage – no analytics or external service calls
- Access on https://yakgpt.vercel.app or run locally!

> Note that GPT-4 API access is needed to use it. GPT 3.5 is enabled for all users.

## Screenshots

| Mobile                                                                                                           | Voice Mode                                                                                                       | Light Theme                                                                                                      | Dark Theme                                                                                                       |
| ---------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| ![image](https://user-images.githubusercontent.com/129409586/229259007-ec4e0a27-cb5e-42fb-91b1-8e4efde99689.png) | ![image](https://user-images.githubusercontent.com/129409586/229259076-b29fe1e6-78a6-47c5-a330-fa34845a0e5f.png) | ![image](https://user-images.githubusercontent.com/129409586/229259145-0dd24f32-ea01-47f5-beab-68b80bfb1bb9.png) | ![image](https://user-images.githubusercontent.com/129409586/229259112-6e7223f8-d92d-49a7-9551-50276bf32089.png) |

## 🚀 Getting Started

Visit [YakGPT](https://yakgpt.vercel.app) to try it out without installing, or follow these steps to run it locally:

### Prerequisites

You'll need the following tools installed on your computer to run YakGPT locally.

- [Git](https://git-scm.com/)
- [Yarn](https://yarnpkg.com/) (or npm or pnpm)
- Any modern web browser like Google Chrome, Mozilla Firefox, or Microsoft Edge

### Installation

1. Clone the repository:

```
$ git clone https://github.com/yakGPT/YakGPT.git
```

2. Install dependencies, build the bundle and run the server

```
$ yarn
$ yarn build
$ yarn start
```

Then navigate to http://localhost:3000

Congratulations! 🎉 You are now running YakGPT locally on your machine.

## 🔑 API Key Configuration

To utilize YakGPT, you'll need to acquire an API key for OpenAI. The app should prompt you to insert you key.

### Add to .env.local(⚠️ Local use only)

If you want the keys to persist across app builds, you can add it to the .env.local.

```
$ echo "NEXT_PUBLIC_OPENAI_API_KEY=<your-open-ai-key-here>" > .env.local
$ echo "NEXT_PUBLIC_11LABS_API_KEY=<your-eleven-labs-key-here>" >> .env.local
```

## 🐳 Docker

To use the pre-built Docker image from Docker Hub (only for amd64), run:

```
$ docker run -it -p 3000:3000 yakgpt/yakgpt:latest
```

---

To build the Docker image yourself (such as if you're on arm64), run:

```
$ docker build -t yakgpt:latest .
$ docker run -it -p 3000:3000 yakgpt:latest
```

## 🎤 Microphone Integration

YakGPT makes chatting a breeze with its microphone integration! Activate your microphone using your browser's permissions, and YakGPT will automatically convert your speech into text.

You can also toggle the mic integration as needed by clicking on the microphone icon in the app.

Remember to use a supported web browser and ensure your microphone is functioning properly.

## 🛡️ Data Privacy and Security

YakGPT ensures your data privacy and security by letting you use your own API key. Your conversation with YakGPT takes place directly between your browser and OpenAI's GPT-3 API, with no intermediary servers.

## 📃 License

This project is licensed under the MIT License - see the [`LICENSE`](LICENSE) file for details

## 🙌 Acknowledgments

- [OpenAI](https://openai.com/) for building such amazing models and making them cheap as chips.
- [Mantine UI](https://ui.mantine.dev/) just an all-around amazing UI library.
- [opus-media-recorder](https://github.com/kbumsik/opus-media-recorder) A real requirement for me was to be able to walk-and-talk. OpenAI's Whisper API is unable to accept the audio generated by Safari, and so I went back to wav recording which due to lack of compression makes things incredibly slow on mobile networks. `opus-media-recorder` saved my butt by allowing cross-platform compressed audio recording via web worker magic. 🤗

Got feedback, questions or ideas? Feel free to submit an issue!


## Detected evidence (automated analysis)

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

## Codebase structure (from repository index)

### Files (52 of 52)

```
.dockerignore
.eslintrc.json
.gitattributes
.gitignore
components/AssistantIcon.tsx
components/AudioPlayer.tsx
components/AutoResizingTextarea.tsx
components/azureLangs.ts
components/BGCard.tsx
components/ChatDisplay.tsx
components/ChatInput.tsx
components/ChatMessage.tsx
components/ChatTextInput.tsx
components/ClearChatsButton.tsx
components/Code.tsx
components/custom-env.d.ts
components/Hero.tsx
components/KeyModal.tsx
components/MessageDisplay.tsx
components/MuHeader.tsx
components/Nav.tsx
components/NewChat.tsx
components/SettingsModal.tsx
components/ThemeToggle.tsx
components/UIController.tsx
components/UIControllerSettings.tsx
components/UserIcon.tsx
Dockerfile
LICENSE
next.config.js
package.json
pages/_app.tsx
pages/_document.tsx
pages/chat/[chatId].tsx
pages/index.tsx
README.md
stores/AzureRecorderActions.ts
stores/AzureSDK.ts
stores/Chat.ts
stores/ChatActions.ts
stores/ChatStore.ts
stores/ElevenLabs.ts
stores/Message.ts
stores/Model.ts
stores/OpenAI.ts
stores/PlayerActions.ts
stores/RecorderActions.ts
stores/SubmitMessage.ts
stores/utils.ts
styles/globals.css
styles/Home.module.css
tsconfig.json
```

### Dependencies

- package.json: @emotion/react@^11.10.6, @emotion/server@^11.10.0, @mantine/carousel@^6.0.21, @mantine/core@^6.0.21, @mantine/form@^6.0.21, @mantine/hooks@^6.0.21, @mantine/next@^6.0.21, @mantine/notifications@^6.0.21, @nem035/gpt-3-encoder@^1.1.7, @tabler/icons-react@^2.42.0, @types/lodash@^4.14.191, @types/markdown-it@^12.2.3, @types/node@18.15.3, @types/react@18.0.28, @types/react-copy-to-clipboard@^5.0.7, @types/react-dom@18.0.11, @types/react-syntax-highlighter@^15.5.10, @types/recordrtc@^5.6.10, @types/uuid@^9.0.1, axios@^1.3.4, embla-carousel-react@^7.1.0, eslint@8.36.0, eslint-config-next@13.2.4, form-data@^4.0.0, highlight.js@^11.7.0, iso-639-1@^2.1.15, lodash@^4.17.21, markdown-to-jsx@^7.3.2, microsoft-cognitiveservices-speech-sdk@^1.26.0, next@13.2.4, react@18.2.0, react-copy-to-clipboard@^5.1.0, react-dom@18.2.0, react-syntax-highlighter@^15.5.0, sharp@^0.32.0, typescript@4.9.5, uuid@^9.0.0, zustand@^4.3.6

### Recent commits (newest first)

- Initial commit

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

### package.json

```
{
  "name": "yakgpt",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "@emotion/react": "^11.10.6",
    "@emotion/server": "^11.10.0",
    "@mantine/carousel": "^6.0.21",
    "@mantine/core": "^6.0.21",
    "@mantine/form": "^6.0.21",
    "@mantine/hooks": "^6.0.21",
    "@mantine/next": "^6.0.21",
    "@mantine/notifications": "^6.0.21",
    "@nem035/gpt-3-encoder": "^1.1.7",
    "@tabler/icons-react": "^2.42.0",
    "@types/node": "18.15.3",
    "@types/react": "18.0.28",
    "@types/react-dom": "18.0.11",
    "axios": "^1.3.4",
    "embla-carousel-react": "^7.1.0",
    "eslint": "8.36.0",
    "eslint-config-next": "13.2.4",
    "form-data": "^4.0.0",
    "highlight.js": "^11.7.0",
    "iso-639-1": "^2.1.15",
    "lodash": "^4.17.21",
    "markdown-to-jsx": "^7.3.2",
    "microsoft-cognitiveservices-speech-sdk": "^1.26.0",
    "next": "13.2.4",
    "react": "18.2.0",
    "react-copy-to-clipboard": "^5.1.0",
    "react-dom": "18.2.0",
    "react-syntax-highlighter": "^15.5.0",
    "sharp": "^0.32.0",
    "typescript": "4.9.5",
    "uuid": "^9.0.0",
    "zustand": "^4.3.6"
  },
  "devDependencies": {
    "@types/lodash": "^4.14.191",
    "@types/markdown-it": "^12.2.3",
    "@types/react-copy-to-clipboard": "^5.0.7",
    "@types/react-syntax-highlighter": "^15.5.10",
    "@types/recordrtc": "^5.6.10",
    "@types/uuid": "^9.0.1"
  }
}

```

### Dockerfile

```
FROM node:18.3.0-alpine3.15 AS base

# Install dependencies only when needed
FROM base AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app

# Install dependencies based on the preferred package manager
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
RUN \
  if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
  elif [ -f package-lock.json ]; then npm ci; \
  elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i --frozen-lockfile; \
  else echo "Lockfile not found." && exit 1; \
  fi


# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .

# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry during the build.
# ENV NEXT_TELEMETRY_DISABLED 1

RUN yarn build

# If using npm comment out above and use below instead
# RUN npm run build

# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app

ENV NODE_ENV production
# Uncomment the following line in case you want to disable telemetry during runtime.
# ENV NEXT_TELEMETRY_DISABLED 1

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

COPY --from=builder /app/public ./public

# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

USER nextjs

EXPOSE 3000

ENV PORT 3000

CMD ["node", "server.js"]

```

### pages/index.tsx

```typescript
import ChatDisplay from "@/components/ChatDisplay";
import Hero from "@/components/Hero";
import { useChatStore } from "@/stores/ChatStore";

export default function Home() {
  const apiKey = useChatStore((state) => state.apiKey);

  return apiKey ? <ChatDisplay /> : <Hero />;
}

```

### next.config.js

```javascript
/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: false,
  output: 'standalone',
};

module.exports = nextConfig;

```

### components/custom-env.d.ts

```typescript
// custom-env.d.ts
declare module "*.mp3" {
  const src: string;
  export default src;
}

```

### stores/Chat.ts

```typescript
import { Message } from "./Message";

export interface Chat {
  id: string;
  title?: string | undefined;
  messages: Message[];
  chosenCharacter?: string | undefined;
  createdAt?: Date | undefined;
  promptTokensUsed?: number;
  completionTokensUsed?: number;
  costIncurred?: number;
}

```

### stores/utils.ts

```typescript
import { Chat } from "./Chat";
import { Message } from "./Message";

export const getChatById = (
  chats: Chat[],
  chatId: string | undefined
): Chat | undefined => {
  return chats.find((c) => c.id === chatId);
};

export const updateChatMessages = (
  chats: Chat[],
  chatId: string,
  updateFunc: (messages: Message[]) => Message[]
): Chat[] => {
  return chats.map((c) => {
    if (c.id === chatId) {
      c.messages = updateFunc(c.messages);
    }
    return c;
  });
};

```

### components/AudioPlayer.tsx

```typescript
import { useEffect, useRef } from "react";
import { useChatStore } from "@/stores/ChatStore";
import { initPlayback } from "@/stores/PlayerActions";

const AudioStreamPlayer = () => {
  const playerRef = useChatStore((state) => state.playerRef);

  const ttsID = useChatStore((state) => state.ttsID);

  const initialRender = useRef(true);
  useEffect(() => {
    // Do not play audio on initial render
    if (initialRender.current) {
      initialRender.current = false;
      return;
    }
    return initPlayback();
  }, [ttsID]);

  return <audio ref={playerRef} playsInline />;
};

export default AudioStreamPlayer;

```

### components/AssistantIcon.tsx

```typescript
import * as React from "react";

const SvgComponent = (props: React.SVGProps<SVGSVGElement>) => (
  <svg
    xmlns="http://www.w3.org/2000/svg"
    viewBox="0 0 100 100"
    fill="none"
    {...props}
  >
    <mask id="a">
      <rect width={100} height={100} rx={0} ry={0} fill="#fff" />
    </mask>
    <g mask="url(#a)">
      <path fill="#0a5b83" d="M0 0h100v100H0z" />
      <path
        d="M-60.32 87.478A60 60 0 1 1 40.32 22.122 60 60 0 0 1-60.32 87.478Z"
        fill="#69d2e7"
      />
      <path
        d="M10.4 97.962 2.038 18.4 81.6 10.038 89.962 89.6 10.4 97.962Z"
        fill="#f1f4dc"
      />
      <path
        d="M26.246 41.671a20 20 0 1 1 39.508 6.258 20 20 0 0 1-39.508-6.258Z"
        fill="#f88c49"
      />
    </g>
  </svg>
);

export default SvgComponent;

```

### components/ChatInput.tsx

```typescript
import { createStyles, MantineTheme } from "@mantine/core";
import ChatTextInput from "./ChatTextInput";

const styles = createStyles((theme: MantineTheme) => ({
  inputWrapper: {
    flexShrink: 0,
    // Always stick to the bottom of the chat
    position: "fixed",
    bottom: 0,
    left: 0,
    [`@media (min-width: ${theme.breakpoints.sm})`]: {
      left: 200,
    },
    [`@media (min-width: ${theme.breakpoints.md})`]: {
      left: 250,
    },

    right: 0,
    zIndex: 1,
    maxWidth: 820,
    margin: "0 auto",
    padding: theme.spacing.md,
  },
  input: {
    // Always stick to the bottom of the chat
    position: "relative",
  },
}));

export default function ChatInput() {
  const { classes } = styles();

  return (
    <div className={classes.inputWrapper}>
      <ChatTextInput />
    </div>
  );
}

```

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