# Project export: Project Montgomery

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 11.0
- Tagline: Project Montgomery addresses the gap for visual learners in Math and Physics by offering an interactive, real-time animation tool using Manim, enabling clearer visualizations for complex concepts.
- Devpost: https://devpost.com/software/project-montgomery
- GitHub: https://github.com/JonOuyang/CalHacks-Project
- Demo: https://github.com/Lasereyepop/CalHacks-Project-Frontend
- Video: https://www.youtube.com/embed/NOIgRXWWNo0?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 3 GitHub contributor(s) — Jonathan (16 commits), Lasereyepop (8 commits), Johnny Zheng (4 commits)

## Devpost submission (written by the team)

### Inspiration

As math students for most of our lives, we’ve often struggled with not fully understanding a formula or an example problem given by a teacher in class. This can lead to frustration and a feeling of being lost. We wanted to solve this problem by providing students with a more engaging way to visualize math problems and formulas, allowing for a deeper understanding through animated representations.

### What it does

Project Montgomery transforms a simple math problem into an animation video using the Manim library in Python (developed by the famous YouTuber 3Blue1Brown) and Google Gemini to help math students better visualize the problem that they are given. Users can input what to be displayed and be able to see the changes happening to the equations in real time.

### How we built it

We built the frontend using the Next.JS framework and Chakra UI, allowing users to input math problems through text and visualize them easily. The backend is powered by Python and the Manim library, which processes the math problem inputs, generates animations, and delivers them back to the frontend for display. The backend also includes a scraper tool developed to gather documentation from the official Manim community website. To do the actual animation generation, we send input prompts from the frontend to the backend, where Google generative AI writes Manim scripts to generate the .mp4 animations.

### Challenges we ran into

One challenge we ran into was downloading dependencies needed for the project. This occurred for the scraper tool we developed to gather documentation from the official Manim community website, but also getting Manim to install and run on different devices. On top of this, we struggled to manage dependencies mainly in Manim and our AI tools due to the multitude of frameworks and libraries. The differences of these between our devices further created issues along with compatibility problems.

### Accomplishments we're proud of

We’re proud of having developed a tool that can bring abstract math concepts to life in such a visually engaging way. One of our biggest achievements was successfully integrating Manim with our backend, allowing real-time input from users to be turned into animated outputs. Later on into the hackathon, we were able to have our AI memorize previous prompting, making for a more comprehensive animation. It was hard to correctly download the libraries for our different devices, and connecting the front end to the backend was not very clear. We solved these issues by searching for help online and watching youtube setup tutorials, respectively.

### What we learned

We effectively learned the Manim library and fed documentation to Google Gemini for animation generation. We also learned newer web development technologies like NextJS and ChakraUI, as well as FastAPI for a python backend. As mentioned above, we struggle with dependency management which led to a lot of trouble shooting, especially for Gemini. We were, however, able to fix this with containerization, namely through Docker which provided a more uniform environment for us despite our different operating systems. All together, we learned a lot about the importance of dependency management.

### What's next

We plan to optimize Project Montgomery’s speed in generating more complex prompts of equations by using Groq. Instead of prompting Gemini API, we will prompt Groq. Furthermore, we intend to integrate this with Learned Management Systems (such as Canvas) which would allow instructors to show their thought process more clearly for problems. We further had the plan of potentially adding in an analytic feature that would allow instructors to view data on how their students interacted with the animation. This can, for example, can be used to find out where students are struggling the most in (e,g by showing at what point the animation is paused the most).

## README (from the GitHub repository)

# Project Montgomery

In honor of Ms. Julie Montgomery. A truly admirable AP Calculus teacher from Leland High School who has inspired and taught many of us for multiple years.

## Inspiration

As math students for most of our lives, we’ve often struggled with not fully understanding a formula or an example problem given by a teacher in class. This can lead to frustration and a feeling of being lost. We wanted to solve this problem by providing students with a more engaging way to visualize math problems and formulas, allowing for a deeper understanding through animated representations.

## What it does

Project Montgomery transforms a simple math problem into an animation video that plays seamlessly using the Manim library in Python (developed by the famous YouTuber 3Blue1Brown) and Google Gemini to help math students better visualize the problem that they are given.

![Image of Montgomery's home page](display_images/image.png)

Users can input what to be displayed and be able to see the changes happening to the equations in real time. We also conveniently included some sample use cases on the left hand side to demonstrate quickly what Montgomery is capable of doing!

![Image of Montgomery's ability to generate animations](display_images/image-1.png)

Built by Team Recursive Bruins at CalHacks 11.0

- Jonathan Ouyang
- Johnny Zheng
- Justin Osbey
- Eric Zhou

# Installation

1. Clone github repository
   `git clone https://github.com/JonOuyang/CalHacks-Project`

2. Create environment for project using command:
   `conda env create -f environment.yml`

3. Install required modules for Google Gemini API:
   `pip install -q -U google-generativeai`

4. Install required modules for rest of project:
   `pip install -r requirements.txt'


## Detected evidence (automated analysis)

Indexed codebase: 19 recognized source files, 41 KB.
- CSS (language) — detected in the code
- FastAPI (technology) — detected in the code
- JavaScript (language) — detected in the code
- Next.js (technology) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- Google Gemini (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (43 of 43)

```
.gitignore
backend/.gitattributes
backend/fastapi/api/external_functions.py
backend/fastapi/api/gemini_call.py
backend/fastapi/api/main2.py
backend/fastapi/api/manim_script.py
backend/fastapi/api/media/Tex/09c6f3b24f69ddf3.tex
backend/fastapi/api/media/Tex/0af837a888bb5693.tex
backend/fastapi/api/media/Tex/321aed5c98da09d7.tex
backend/fastapi/api/media/Tex/39916e23eedf48bb.tex
backend/fastapi/api/media/Tex/3b9984e08a330438.tex
backend/fastapi/api/media/Tex/5908b05a77a0d185.tex
backend/fastapi/api/media/Tex/5a7244d07cea3c89.tex
backend/fastapi/api/media/Tex/8e2b57278869bcbf.tex
backend/fastapi/api/media/Tex/aaf3c1a970d63f8f.tex
backend/fastapi/api/media/Tex/ae4ba11bf84f1d49.tex
backend/fastapi/api/media/Tex/b2de671fca4ff9b7.tex
backend/fastapi/api/media/Tex/dbb89a5d4f2408fe.tex
backend/fastapi/api/media/Tex/e4be163a00cf424f.tex
backend/fastapi/api/media/videos/manim_script/1080p60/partial_movie_files/video/partial_movie_file_list.txt
backend/fastapi/requirements.txt
backend/frames.py
backend/pixi.lock
backend/pixi.toml
backend/playground.py
backend/requirements.txt
environment.yml
frontend/.eslintrc.json
frontend/jsconfig.json
frontend/next.config.mjs
frontend/package.json
frontend/src/components/sidebar.js
frontend/src/components/theme.js
frontend/src/components/typewriter.js
frontend/src/components/userinput.js
frontend/src/components/video.js
frontend/src/pages/_app.js
frontend/src/pages/_document.js
frontend/src/pages/api/hello.js
frontend/src/pages/index.js
frontend/src/styles/globals.css
frontend/src/styles/Home.module.css
README.md
```

### Dependencies

- backend/fastapi/requirements.txt: aiofiles@==23.2.1, annotated-types@==0.6.0, anyio@==4.3.0, bcrypt@==4.0.1, click@==8.1.7, ecdsa@==0.19.0, fastapi@==0.110.1, h11@==0.14.0, idna@==3.7, passlib@==1.7.4, pyasn1@==0.6.0, pydantic@==2.7.0, pydantic_core@==2.18.1, python-dotenv, python-jose@==3.3.0, python-multipart@==0.0.9, rsa@==4.9, six@==1.16.0, sniffio@==1.3.1, SQLAlchemy@==2.0.29, starlette@==0.37.2, typing_extensions@==4.11.0, uvicorn@==0.29.0
- backend/requirements.txt: annotated-types@==0.7.0, Brotli@@ file:///private/var/folders/k1/30mswbxs7r1g6zwn8y4fyt500000gp/T/abs_27zk0eqdh0/croot/brotli-split_1714483157007/work, build@@ file:///home/conda/feedstock_root/build_artifacts/python-build_1728263384570/work, CacheControl@@ file:///home/conda/feedstock_root/build_artifacts/cachecontrol-split_1718811419212/work, cachetools@==5.5.0, certifi@@ file:///private/var/folders/k1/30mswbxs7r1g6zwn8y4fyt500000gp/T/abs_0ecs_ou28u/croot/certifi_1725551740278/work/certifi, cffi@@ file:///private/var/folders/nz/j6p8yfhx1mv_0grj5xl4650h0000gp/T/abs_06ndtibm2c/croot/cffi_1726856446111/work, charset-normalizer@@ file:///home/conda/feedstock_root/build_artifacts/charset-normalizer_1728479282467/work, cleo@@ file:///home/conda/feedstock_root/build_artifacts/cleo_1698693584261/work, click@@ file:///home/conda/feedstock_root/build_artifacts/click_1692311806742/work, click-default-group@@ file:///home/conda/feedstock_root/build_artifacts/click-default-group_1691239292067/work, cloup@@ file:///home/conda/feedstock_root/build_artifacts/cloup_1709560247175/work, colorama@@ file:///home/conda/feedstock_root/build_artifacts/colorama_1666700638685/work, crashtest@@ file:///home/conda/feedstock_root/build_artifacts/crashtest_1667467006729/work, Cython@@ file:///private/var/folders/nz/j6p8yfhx1mv_0grj5xl4650h0000gp/T/abs_4atm69qksw/croot/cython_1727769803539/work, decorator@@ file:///home/conda/feedstock_root/build_artifacts/decorator_1641555617451/work, distlib@@ file:///home/conda/feedstock_root/build_artifacts/distlib_1728557174656/work, dulwich@@ file:///private/var/folders/nz/j6p8yfhx1mv_0grj5xl4650h0000gp/T/abs_73rnypnk3v/croot/dulwich_1679420046310/work, fastjsonschema@@ file:///home/conda/feedstock_root/build_artifacts/python-fastjsonschema_1718477020893/work/dist, filelock@@ file:///home/conda/feedstock_root/build_artifacts/filelock_1726613473834/work, future@@ file:///home/conda/feedstock_root/build_artifacts/future_1708610096684/work, glcontext@@ file:///Users/runner/miniforge3/conda-bld/glcontext_1725374166539/work, google-ai-generativelanguage@==0.6.10, google-api-core@==2.21.0, google-api-python-client@==2.149.0, google-auth@==2.35.0, google-auth-httplib2@==0.2.0, google-generativeai@==0.8.3, googleapis-common-protos@==1.65.0, grpcio@==1.67.0, grpcio-status@==1.67.0, h2@@ file:///home/conda/feedstock_root/build_artifacts/h2_1634280454336/work, hpack@==4.0.0, httplib2@==0.22.0, hyperframe@@ file:///home/conda/feedstock_root/build_artifacts/hyperframe_1619110129307/work, idna@@ file:///home/conda/feedstock_root/build_artifacts/idna_1726459485162/work, importlib_metadata@@ file:///home/conda/feedstock_root/build_artifacts/importlib-metadata_1726082825846/work, importlib_resources@@ file:///home/conda/feedstock_root/build_artifacts/importlib_resources_1725921340658/work, installer@@ file:///home/conda/feedstock_root/build_artifacts/python-installer_1679300325491/work, isosurfaces@@ file:///home/conda/feedstock_root/build_artifacts/isosurfaces_1709087510374/work, jaraco.classes@@ file:///home/conda/feedstock_root/build_artifacts/jaraco.classes_1713939306738/work, keyring@@ file:///Users/runner/miniforge3/conda-bld/keyring_1728574836527/work, manim@@ file:///home/conda/feedstock_root/build_artifacts/manim_1714385482207/work, ManimPango@@ file:///Users/runner/miniforge3/conda-bld/manimpango_1726487398111/work, mapbox_earcut@@ file:///Users/runner/miniforge3/conda-bld/mapbox_earcut_1721669871579/work, markdown-it-py@@ file:///home/conda/feedstock_root/build_artifacts/markdown-it-py_1686175045316/work, mdurl@@ file:///home/conda/feedstock_root/build_artifacts/mdurl_1704317613764/work, moderngl@@ file:///Users/runner/miniforge3/conda-bld/moderngl_1727269728818/work, moderngl-window@@ file:///home/conda/feedstock_root/build_artifacts/moderngl-window_1640877011710/work, more-itertools@@ file:///home/conda/feedstock_root/build_artifacts/more-itertools_1725630081114/work, msgpack@@ file:///private/var/folders/nz/j6p8yfhx1mv_0grj5xl4650h0000gp/T/abs_b1f960af-3408-459c-81e6-6c3b55c6bc85wsdgof__/croots/recipe/msgpack-python_1652362662498/work, multipledispatch@@ file:///home/conda/feedstock_root/build_artifacts/multipledispatch_1721907546485/work, networkx@@ file:///private/var/folders/nz/j6p8yfhx1mv_0grj5xl4650h0000gp/T/abs_797xfkx_y7/croot/networkx_1717597499877/work, numpy@@ file:///private/var/folders/k1/30mswbxs7r1g6zwn8y4fyt500000gp/T/abs_a51i_mbs7m/croot/numpy_and_numpy_base_1708638620867/work/dist/numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl#sha256=829e20a6c33ce51c1a93497d06cb4af22d84caa54a431ea062765da3134e5287, packaging@@ file:///home/conda/feedstock_root/build_artifacts/packaging_1718189413536/work, pexpect@@ file:///home/conda/feedstock_root/build_artifacts/pexpect_1706113125309/work, pillow@@ file:///Users/runner/miniforge3/conda-bld/pillow_1729065742992/work, pkginfo@@ file:///home/conda/feedstock_root/build_artifacts/pkginfo_1728616516923/work, platformdirs@@ file:///home/conda/feedstock_root/build_artifacts/platformdirs_1726613481435/work, poetry@@ file:///Users/runner/miniforge3/conda-bld/poetry_1728951545926/work, poetry-core@@ file:///home/conda/feedstock_root/build_artifacts/poetry-core_1728873002994/work, poetry-plugin-export@@ file:///home/conda/feedstock_root/build_artifacts/poetry-plugin-export_1715458131259/work, proto-plus@==1.24.0, protobuf@==5.28.2, ptyprocess@@ file:///home/conda/feedstock_root/build_artifacts/ptyprocess_1609419310487/work/dist/ptyprocess-0.7.0-py2.py3-none-any.whl, pyasn1@==0.6.1, pyasn1_modules@==0.4.1, pycairo@==1.23.0, pycparser@@ file:///home/conda/feedstock_root/build_artifacts/pycparser_1711811537435/work, pydantic@==2.9.2, pydantic_core@==2.23.4, pydub@@ file:///home/conda/feedstock_root/build_artifacts/pydub_1615612442567/work, pyglet@@ file:///Users/runner/miniforge3/conda-bld/pyglet_1695497694594/work, Pygments@@ file:///home/conda/feedstock_root/build_artifacts/pygments_1714846767233/work, PyGObject@==3.50.0, pyobjc-core@@ file:///private/var/folders/k1/30mswbxs7r1g6zwn8y4fyt500000gp/T/abs_342uq4g0a3/croot/pyobjc-core_1710189033492/work, pyobjc-framework-Cocoa@@ file:///private/var/folders/k1/30mswbxs7r1g6zwn8y4fyt500000gp/T/abs_157_nv38zo/croot/pyobjc-framework-cocoa_1710191895205/work, pyparsing@==3.2.0, pyproject_hooks@@ file:///home/conda/feedstock_root/build_artifacts/pyproject_hooks_1727644064167/work, pyrr@==0.10.3, PySocks@@ file:///home/conda/feedstock_root/build_artifacts/pysocks_1661604839144/work, python-dotenv@==1.0.1, PyYAML@@ file:///private/var/folders/nz/j6p8yfhx1mv_0grj5xl4650h0000gp/T/abs_faoex52hrr/croot/pyyaml_1728657970485/work, rapidfuzz@@ file:///private/var/folders/k1/30mswbxs7r1g6zwn8y4fyt500000gp/T/abs_8blzybzt1p/croot/rapidfuzz_1700060090583/work, requests@@ file:///home/conda/feedstock_root/build_artifacts/requests_1717057054362/work, requests-toolbelt@@ file:///home/conda/feedstock_root/build_artifacts/requests-toolbelt_1682953341151/work, rich@@ file:///home/conda/feedstock_root/build_artifacts/rich_1728057819683/work/dist, rsa@==4.9, scipy@@ file:///private/var/folders/nz/j6p8yfhx1mv_0grj5xl4650h0000gp/T/abs_b9t0odioph/croot/scipy_1717521487325/work/dist/scipy-1.13.1-cp39-cp39-macosx_11_0_arm64.whl#sha256=989d301f853749cc445d0988e25daf1c6d8ed97675ca33599e66b89c23e6af1b, screeninfo@@ file:///Users/runner/miniforge3/conda-bld/screeninfo_1715463965091/work, shellingham@@ file:///home/conda/feedstock_root/build_artifacts/shellingham_1698144360966/work, six@@ file:///home/conda/feedstock_root/build_artifacts/six_1620240208055/work, skia-pathops@@ file:///Users/runner/miniforge3/conda-bld/skia-pathops_1725518760258/work, srt@@ file:///Users/runner/miniforge3/conda-bld/srt_1695880309338/work, svgelements@@ file:///home/conda/feedstock_root/build_artifacts/svgelements_1692252260255/work, tomli@@ file:///home/conda/feedstock_root/build_artifacts/tomli_1727974628237/work, tomlkit@@ file:///home/conda/feedstock_root/build_artifacts/tomlkit_1723631480657/work, tqdm@@ file:///home/conda/feedstock_root/build_artifacts/tqdm_1722737464726/work, trove-classifiers@@ file:///home/conda/feedstock_root/build_artifacts/trove-classifiers_1729123849340/work, typing_extensions@@ file:///home/conda/feedstock_root/build_artifacts/typing_extensions_1717802530399/work, uritemplate@==4.1.1, urllib3@@ file:///home/conda/feedstock_root/build_artifacts/urllib3_1726496430923/work, virtualenv@@ file:///home/conda/feedstock_root/build_artifacts/virtualenv_1729243766698/work, watchdog@@ file:///Users/builder/cbouss/crwatchdog/watchdog_1717177010913/work, xattr@@ file:///Users/runner/miniforge3/conda-bld/xattr_1728410232903/work, zipp@@ file:///home/conda/feedstock_root/build_artifacts/zipp_1726248574750/work, zstandard@@ file:///private/var/folders/k1/30mswbxs7r1g6zwn8y4fyt500000gp/T/abs_cairdg5u3o/croot/zstandard_1728569200438/work
- frontend/package.json: @chakra-ui/icons@^2.2.4, @chakra-ui/next-js@^2.4.2, @chakra-ui/react@^2.10.2, @emotion/react@^11.13.3, @emotion/styled@^11.13.0, @fontsource/inter@^5.1.0, @react-icons/all-files@^4.1.0, @splinetool/react-spline@^4.0.0, axios@^1.7.7, eslint@^8, eslint-config-next@14.2.15, framer-motion@^11.11.8, icons@^1.0.0, next@^14.2.15, react@^18, react-dom@^18

### Recent commits (newest first)

- update readme
- reinit
- test
- merge frontend and backend repositories
- set up commit
- update
- bug fixes
- added clear screen and bug fix
- bug fixes
- backend bug fixes
- Managed to connect video
- Return video file
- backend bug fixes
- backend update
- update prompt engineering
- update gitigonre
- Connected front and backend
- Merge branch 'main' of https://github.com/JonOuyang/CalHacks-Project
- Gitignored
- Delete .env

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

### frontend/package.json

```
{
  "name": "calhacks",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "@chakra-ui/icons": "^2.2.4",
    "@chakra-ui/next-js": "^2.4.2",
    "@chakra-ui/react": "^2.10.2",
    "@emotion/react": "^11.13.3",
    "@emotion/styled": "^11.13.0",
    "@fontsource/inter": "^5.1.0",
    "@react-icons/all-files": "^4.1.0",
    "@splinetool/react-spline": "^4.0.0",
    "axios": "^1.7.7",
    "framer-motion": "^11.11.8",
    "icons": "^1.0.0",
    "next": "^14.2.15",
    "react": "^18",
    "react-dom": "^18"
  },
  "devDependencies": {
    "eslint": "^8",
    "eslint-config-next": "14.2.15"
  }
}

```

### backend/requirements.txt

```
annotated-types==0.7.0
Brotli @ file:///private/var/folders/k1/30mswbxs7r1g6zwn8y4fyt500000gp/T/abs_27zk0eqdh0/croot/brotli-split_1714483157007/work
build @ file:///home/conda/feedstock_root/build_artifacts/python-build_1728263384570/work
CacheControl @ file:///home/conda/feedstock_root/build_artifacts/cachecontrol-split_1718811419212/work
cachetools==5.5.0
certifi @ file:///private/var/folders/k1/30mswbxs7r1g6zwn8y4fyt500000gp/T/abs_0ecs_ou28u/croot/certifi_1725551740278/work/certifi
cffi @ file:///private/var/folders/nz/j6p8yfhx1mv_0grj5xl4650h0000gp/T/abs_06ndtibm2c/croot/cffi_1726856446111/work
charset-normalizer @ file:///home/conda/feedstock_root/build_artifacts/charset-normalizer_1728479282467/work
cleo @ file:///home/conda/feedstock_root/build_artifacts/cleo_1698693584261/work
click @ file:///home/conda/feedstock_root/build_artifacts/click_1692311806742/work
click-default-group @ file:///home/conda/feedstock_root/build_artifacts/click-default-group_1691239292067/work
cloup @ file:///home/conda/feedstock_root/build_artifacts/cloup_1709560247175/work
colorama @ file:///home/conda/feedstock_root/build_artifacts/colorama_1666700638685/work
crashtest @ file:///home/conda/feedstock_root/build_artifacts/crashtest_1667467006729/work
Cython @ file:///private/var/folders/nz/j6p8yfhx1mv_0grj5xl4650h0000gp/T/abs_4atm69qksw/croot/cython_1727769803539/work
decorator @ file:///home/conda/feedstock_root/build_artifacts/decorator_1641555617451/work
distlib @ file:///home/conda/feedstock_root/build_artifacts/distlib_1728557174656/work
dulwich @ file:///private/var/folders/nz/j6p8yfhx1mv_0grj5xl4650h0000gp/T/abs_73rnypnk3v/croot/dulwich_1679420046310/work
fastjsonschema @ file:///home/conda/feedstock_root/build_artifacts/python-fastjsonschema_1718477020893/work/dist
filelock @ file:///home/conda/feedstock_root/build_artifacts/filelock_1726613473834/work
future @ file:///home/conda/feedstock_root/build_artifacts/future_1708610096684/work
glcontext @ file:///Users/runner/miniforge3/conda-bld/glcontext_1725374166539/work
google-ai-generativelanguage==0.6.10
google-api-core==2.21.0
google-api-python-client==2.149.0
google-auth==2.35.0
google-auth-httplib2==0.2.0
google-generativeai==0.8.3
googleapis-common-protos==1.65.0
grpcio==1.67.0
grpcio-status==1.67.0
h2 @ file:///home/conda/feedstock_root/build_artifacts/h2_1634280454336/work
hpack==4.0.0
httplib2==0.22.0
hyperframe @ file:///home/conda/feedstock_root/build_artifacts/hyperframe_1619110129307/work
idna @ file:///home/conda/feedstock_root/build_artifacts/idna_1726459485162/work
importlib_metadata @ file:///home/conda/feedstock_root/build_artifacts/importlib-metadata_1726082825846/work
importlib_resources @ file:///home/conda/feedstock_root/build_artifacts/importlib_resources_1725921340658/work
installer @ file:///home/conda/feedstock_root/build_artifacts/python-installer_1679300325491/work
isosurfaces @ file:///home/conda/feedstock_root/build_artifacts/isosurfaces_1709087510374/work
jaraco.classes @ file:///home/conda/feedstock_root/build_artifacts/jaraco.classes_1713939306738/work
keyring @ file:///Users/runner/miniforge3/conda-bld/keyring_1728574836527/work
manim @ file:///home/conda/feedstock_root/build_artifacts/manim_1714385482207/work
ManimPango @ file:///Users/runner/miniforge3/conda-bld/manimpango_1726487398111/work
mapbox_earcut @ file:///Users/runner/miniforge3/conda-bld/mapbox_earcut_1721669871579/work
markdown-it-py @ file:///home/conda/feedstock_root/build_artifacts/markdown-it-py_1686175045316/work
mdurl @ file:///home/conda/feedstock_root/build_artifacts/mdurl_1704317613764/work
moderngl @ file:///Users/runner/miniforge3/conda-bld/moderngl_1727269728818/work
moderngl-window @ file:///home/conda/feedstock_root/build_artifacts/moderngl-window_1640877011710/work
more-itertools @ file:///home/conda/feedstock_root/build_artifacts/more-itertools_1725630081114/work
msgpack @ file:///private/var/folders/nz/j6p8yfhx1mv_0grj5xl4650h0000gp/T/abs_b1f960af-3408-459c-81e6-6c3b55c6bc85wsdgof__/croots/recipe/msgpack-python_1652362662498/work
multipledispatch @ file:///home/conda/feedstock_root/build_artifacts/multipledispatch_1721907546485/work
networkx @ file:///private/var/folders/nz/j6p8yfhx1mv_0grj5xl4650h0000gp/T/abs_797xfkx_y7/croot/networkx_1717597499877/work
numpy @ file:///private/var/folders/k1/30mswbxs7r1g6zwn8y4fyt500000gp/T/abs_a51i_mbs7m/croot/numpy_and_numpy_base_1708638620867/work/dist/numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl#sha256=829e20a6c33ce51c1a93497d06cb4af22d84caa54a431ea062765da3134e5287
packaging @ file:///home/conda/feedstock_root/build_artifacts/packaging_1718189413536/work
pexpect @ file:///home/conda/feedstock_root/build_artifacts/pexpect_1706113125309/work
pillow @ file:///Users/runner/miniforge3/conda-bld/pillow_1729065742992/work
pkginfo @ file:///home/conda/feedstock_root/build_artifacts/pkginfo_1728616516923/work
platformdirs @ file:///home/conda/feedstock_root/build_artifacts/platformdirs_1726613481435/work
poetry @ file:///Users/runner/miniforge3/conda-bld/poetry_1728951545926/work
poetry-core @ file:///home/conda/feedstock_root/build_artifacts/poetry-core_1728873002994/work
poetry-plugin-export @ file:///home/conda/feedstock_root/build_artifacts/poetry-plugin-export_1715458131259/work
proto-plus==1.24.0
protobuf==5.28.2
ptyprocess @ file:///home/conda/feedstock_root/build_artifacts/ptyprocess_1609419310487/work/dist/ptyprocess-0.7.0-py2.py3-none-any.whl
pyasn1==0.6.1
pyasn1_modules==0.4.1
pycairo==1.23.0
pycparser @ file:///home/conda/feedstock_root/build_artifacts/pycparser_1711811537435/work
pydantic==2.9.2
pydantic_core==2.23.4
pydub @ file:///home/conda/feedstock_root/build_artifacts/pydub_1615612442567/work
pyglet @ file:///Users/runner/miniforge3/conda-bld/pyglet_1695497694594/work
Pygments @ file:///home/conda/feedstock_root/build_artifacts/pygments_1714846767233/work
PyGObject==3.50.0
pyobjc-core @ file:///private/var/folders/k1/30mswbxs7r1g6zwn8y4fyt500000gp/T/abs_342uq4g0a3/croot/pyobjc-core_17101
[truncated — 2723 more characters]
```

### backend/fastapi/requirements.txt

```
aiofiles==23.2.1
annotated-types==0.6.0
anyio==4.3.0
bcrypt==4.0.1
click==8.1.7
ecdsa==0.19.0
fastapi==0.110.1
h11==0.14.0
idna==3.7
passlib==1.7.4
pyasn1==0.6.0
pydantic==2.7.0
pydantic_core==2.18.1
python-jose==3.3.0
python-multipart==0.0.9
rsa==4.9
six==1.16.0
sniffio==1.3.1
SQLAlchemy==2.0.29
starlette==0.37.2
typing_extensions==4.11.0
uvicorn==0.29.0
python-dotenv
```

### frontend/src/pages/index.js

```javascript
import { useState } from "react";
import { Box, Flex } from "@chakra-ui/react";
import SideBar from "@/components/sidebar";
import UserInput from "@/components/userinput";
import Spline from "@splinetool/react-spline";
import TypewriterText from "@/components/typewriter";
import VideoComponent from "@/components/video";  // Import VideoComponent

export default function Home() {
  const [videoUrl, setVideoUrl] = useState(null);  // State to store the video URL
  const [showTypewriter, setShowTypewriter] = useState(false);  // State to toggle TypewriterText visibility
  const [userInputValue, setUserInputValue] = useState("");  // State for the user input field

  // Function to update the user input value when an item from the sidebar is clicked
  const handleAutoFill = (value) => {
    setUserInputValue(value);  // Autofill the user input with the clicked value
  };

  // Function passed to UserInput to handle the API response (the video blob URL)
  const handleUserInputResponse = (url) => {
    setVideoUrl(url);  // Update the state with the video URL
    setShowTypewriter(false);  // Hide the Typewriter when video is displayed
  };

  // Toggle the visibility of the TypewriterText when Spline is clicked
  const handleSplineClick = () => {
    setShowTypewriter((prev) => !prev);  // Toggle showTypewriter state
  };

  // Reset the state to show Spline without TypewriterText when EditIcon is clicked
  const handleReset = () => {
    setVideoUrl(null);  // Reset the video URL
    setShowTypewriter(false);  // Keep Typewriter hidden on reset
  };

  return (
    <Flex minHeight="100vh" width="100%">
      {/* Sidebar */}
      <Box
        width="25%"
        bg="gray.100"
        p="4"
        boxShadow="md"
        position="fixed"
        height="100vh"
        left={0}
        top={0}
      >
        {/* Pass the handleAutoFill function to the sidebar */}
        <SideBar onReset={handleReset} onAutoFill={handleAutoFill} />
      </Box>

      {/* Main content area for Spline or Video */}
      <Box
        flex="1"
        ml="25%"
        display="flex"
        flexDirection="column"
        justifyContent="center"
        alignItems="center"
        height="100vh"
        position="relative"
        overflow="hidden"
      >
        {!videoUrl ? (
          <Box width="100%" height="100%" position="relative">
            {/* Spline Component */}
            <Spline 
              scene="https://prod.spline.design/NiiiQrjNKkVNlTYO/scene.splinecode" 
              onClick={handleSplineClick}
            />

            {/* Conditionally render TypewriterText based on showTypewriter */}
            {showTypewriter && (
              <Box
                position="absolute"
                top="45%"
                left="50%"
                transform="translate(-50%, -50%)"
              >
                <TypewriterText />
              </Box>
            )}
          </Box>
        ) : (
          <Box flex="1" width="100%" height="100%" position="relative">
            {/* Pass the blob URL to VideoComponent */}
            <VideoComponent videoUrl={videoUrl} />
          </Box>
        )}

        {/* UserInput component at the bottom */}
        <Box
          position="absolute"
          bottom="0"
          left="0"
          width="100%"
          zIndex="10"
          height="10vh"
        >
          <UserInput 
            onApiResponse={handleUserInputResponse} 
            inputValue={userInputValue}  // Pass the input value for autofill
            setInputValue={setUserInputValue}  // Pass function to update input value
          />
        </Box>
      </Box>
    </Flex>
  );
}

```

### environment.yml

```yaml
name: calhacks
channels:
  - conda-forge
  - defaults
dependencies:
  - aom=3.6.1=hb765f3a_0
  - blas=1.0=openblas
  - brotli-python=1.0.9=py39h313beb8_8
  - bzip2=1.0.8=h99b78c6_7
  - ca-certificates=2024.9.24=hca03da5_0
  - cachecontrol=0.14.0=pyhd8ed1ab_1
  - cachecontrol-with-filecache=0.14.0=pyhd8ed1ab_1
  - cairo=1.18.0=hb4a6bf7_3
  - certifi=2024.8.30=py39hca03da5_0
  - cffi=1.17.1=py39h3eb5a62_0
  - charset-normalizer=3.4.0=pyhd8ed1ab_0
  - cleo=2.1.0=pyhd8ed1ab_0
  - click=8.1.7=unix_pyh707e725_0
  - click-default-group=1.2.4=pyhd8ed1ab_0
  - cloup=3.0.5=pyhd8ed1ab_0
  - colorama=0.4.6=pyhd8ed1ab_0
  - crashtest=0.4.1=pyhd8ed1ab_0
  - cython=3.0.11=py39h80987f9_0
  - dav1d=1.2.1=hb547adb_0
  - decorator=5.1.1=pyhd8ed1ab_0
  - distlib=0.3.9=pyhd8ed1ab_0
  - dulwich=0.21.3=py39h80987f9_0
  - expat=2.6.3=hf9b8971_0
  - ffmpeg=5.1.2=gpl_h9861f02_112
  - filelock=3.16.1=pyhd8ed1ab_0
  - font-ttf-dejavu-sans-mono=2.37=hab24e00_0
  - font-ttf-inconsolata=3.000=h77eed37_0
  - font-ttf-source-code-pro=2.038=h77eed37_0
  - font-ttf-ubuntu=0.83=h77eed37_3
  - fontconfig=2.14.2=h82840c6_0
  - fonts-conda-ecosystem=1=0
  - fonts-conda-forge=1=0
  - freetype=2.12.1=hadb7bae_2
  - fribidi=1.0.10=h27ca646_0
  - future=1.0.0=pyhd8ed1ab_0
  - gettext=0.22.5=h8414b35_3
  - gettext-tools=0.22.5=h8414b35_3
  - glcontext=3.0.0=py39hfa9831e_1
  - glib=2.82.2=hb1db9eb_0
  - glib-tools=2.82.2=h25d4a46_0
  - gmp=6.3.0=h7bae524_2
  - gnutls=3.7.9=hd26332c_0
  - graphite2=1.3.13=hebf3989_1003
  - h2=4.1.0=pyhd8ed1ab_0
  - harfbuzz=9.0.0=h997cde5_1
  - hpack=4.0.0=pyh9f0ad1d_0
  - hyperframe=6.0.1=pyhd8ed1ab_0
  - icu=75.1=hfee45f7_0
  - idna=3.10=pyhd8ed1ab_0
  - importlib-metadata=8.5.0=pyha770c72_0
  - importlib_resources=6.4.5=pyhd8ed1ab_0
  - isosurfaces=0.1.2=pyhd8ed1ab_0
  - jaraco.classes=3.4.0=pyhd8ed1ab_1
  - keyring=24.3.1=pyh534df25_1
  - lame=3.100=h1a8c8d9_1003
  - lcms2=2.16=ha0e7c42_0
  - lerc=4.0.0=h9a09cb3_0
  - libasprintf=0.22.5=h8414b35_3
  - libasprintf-devel=0.22.5=h8414b35_3
  - libass=0.17.1=hf20b609_2
  - libblas=3.9.0=24_osxarm64_openblas
  - libcblas=3.9.0=24_osxarm64_openblas
  - libcxx=19.1.2=ha82da77_0
  - libdeflate=1.22=hd74edd7_0
  - libexpat=2.6.3=hf9b8971_0
  - libffi=3.4.2=h3422bc3_5
  - libgd=2.3.3=hac1b3a8_10
  - libgettextpo=0.22.5=h8414b35_3
  - libgettextpo-devel=0.22.5=h8414b35_3
  - libgfortran=5.0.0=13_2_0_hd922786_3
  - libgfortran5=13.2.0=hf226fd6_3
  - libgirepository=1.82.0=h607895c_0
  - libglib=2.82.2=h07bd6cf_0
  - libiconv=1.17=h0d3ecfb_2
  - libidn2=2.3.7=h93a5062_0
  - libintl=0.22.5=h8414b35_3
  - libintl-devel=0.22.5=h8414b35_3
  - libjpeg-turbo=3.0.0=hb547adb_1
  - liblapack=3.9.0=24_osxarm64_openblas
  - libopenblas=0.3.27=openmp_h517c56d_1
  - libopus=1.3.1=h27ca646_1
  - libpng=1.6.44=hc14010f_0
  - libsqlite=3.46.1=hc14010f_0
  - libtasn1=4.19.0=h1a8c8d9_0
  - libtiff=4.7.0=hfce79cd_1
  - libunistring=0.9.10=h3422bc3_0
  - libvpx=1.13.1=hb765f3a_0
  - libwebp-base=1.4.0=h93a5062_0
  - libxcb=1.17.0=hdb1d25a_0
  - libxml2=2.12.7=h01dff8b_4
  - libzlib=1.3.1=h8359307_2
  - llvm-openmp=19.1.2=hb52a8e5_0
  - manim=0.18.1=pyhd8ed1ab_0
  - manimpango=0.6.0=py39h37b299c_0
  - mapbox_earcut=1.0.1=py39hb3a5b6b_1
  - markdown-it-py=3.0.0=pyhd8ed1ab_0
  - mdurl=0.1.2=pyhd8ed1ab_0
  - moderngl=5.11.1=py39hc5ad87a_0
  - moderngl-window=2.4.1=pyhd8ed1ab_0
  - more-itertools=10.5.0=pyhd8ed1ab_0
  - msgpack-python=1.0.3=py39h525c30c_0
  - multipledispatch=0.6.0=pyhd8ed1ab_1
  - ncurses=6.5=h7bae524_1
  - nettle=3.9.1=h40ed0f5_0
  - networkx=3.2.1=py39hca03da5_0
  - numpy=1.26.4=py39h3b2db8e_0
  - numpy-base=1.26.4=py39ha9811e2_0
  - openh264=2.3.1=hb7217d7_2
  - openjpeg=2.5.2=h9f1df11_0
  - openssl=3.3.2=h8359307_0
  - p11-kit=0.24.1=h29577a5_0
  - packaging=24.1=pyhd8ed1ab_0
  - pango=1.54.0=h9ee27a3_2
  - pcre2=10.44=h297a79d_2
  - pexpect=4.9.0=pyhd8ed1ab_0
  - pillow=11.0.0=py39h4ac03e3_0
  - pip=24.2=pyh8b19718_1
  - pixman=0.43.4=hebf3989_0
  - pkginfo=1.11.2=pyhd8ed1ab_0
  - platformdirs=4.3.6=pyhd8ed1ab_0
  - poetry=1.8.4=osx_pyh534df25_0
  - poetry-core=1.9.1=pyhd8ed1ab_0
  - poetry-plugin-export=1.8.0=pyhd8ed1ab_0
  - pthread-stubs=0.4=hd74edd7_1002
  - ptyprocess=0.7.0=pyhd3deb0d_0
  - pybind11-abi=4=hd3eb1b0_1
  - pycairo=1.23.0=py39hc7d53f0_0
  - pycparser=2.22=pyhd8ed1ab_0
  - pydub=0.25.1=pyhd8ed1ab_0
  - pyglet=1.5.27=py39h2804cbe_4
  - pygments=2.18.0=pyhd8ed1ab_0
  - pygobject=3.50.0=py39h3b16522_1
  - pyobjc-core=10.1=py39h80987f9_0
  - pyobjc-framework-cocoa=10.1=py39hb094c41_0
  - pyproject_hooks=1.2.0=pyh7850678_0
  - pyrr=0.10.3=py_0
  - pysocks=1.7.1=pyha2e5f31_6
  - python=3.9.20=h9e33284_1_cpython
  - python-build=1.2.2.post1=pyhff2d567_0
  - python-fastjsonschema=2.20.0=pyhd8ed1ab_0
  - python-installer=0.7.0=pyhd8ed1ab_0
  - python_abi=3.9=5_cp39
  - pyyaml=6.0.2=py39h80987f9_0
  - rapidfuzz=3.5.2=py39h313beb8_0
  - readline=8.2=h92ec313_1
  - requests=2.32.3=pyhd8ed1ab_0
  - requests-toolbelt=1.0.0=pyhd8ed1ab_0
  - rich=13.9.2=pyhd8ed1ab_0
  - scipy=1.13.1=py39hd336fd7_0
  - screeninfo=0.8.1=py39h2804cbe_2
  - setuptools=75.1.0=pyhd8ed1ab_0
  - shellingham=1.5.4=pyhd8ed1ab_0
  - six=1.16.0=pyh6c4a22f_0
  - skia-pathops=0.8.0.post1=py39h157d57c_3
  - srt=3.5.3=py39h2804cbe_0
  - svgelements=1.9.6=pyhd8ed1ab_0
  - svt-av1=1.4.1=h7ea286d_0
  - tk=8.6.13=h5083fa2_1
  - tomli=2.0.2=pyhd8ed1ab_0
  - tomlkit=0.13.2=pyha770c72_0
  - tqdm=4.66.5=pyhd8ed1ab_0
  - trove-classifiers=2024.10.16=pyhd8ed1ab_0
  - typing-extensions=4.12.2=hd8ed1ab_0
  - typing_extensions=4.12.2=pyha770c72_0
  - tzdata=2024b=hc8b5060_0
  - urllib3=2.2.3=pyhd8ed1ab_0
  - virtualenv=20.27.0=pyhd8ed1ab_0
  - watchdog=4.0.1=py39h80987f9_0
  - wheel=0.44.0=pyhd8ed1ab_0
  - x264=1!164.3095=h57fd34a_2
  - x265=3.5=hbc6ce65_3
  - xattr=1.1.0=py39h06df861_1
  - xorg-libxau=1.0.11=hd74edd7_1
  - xorg-libxdmcp=1.1.5=hd74edd7_0
  - xz=5.2.6=h57fd34a_0
  - yaml=0.2.5=h3422bc3_2
  - zipp=3.20.2=pyhd8ed1ab_0
  - zlib=1.3.1=h8359307_2
  - zstandard=0.23.0=py39h1a4646a_0
  - zstd=1.
[truncated — 711 more characters]
```

### backend/frames.py

```python
# split the mp4 of the video that we get into many frames

import cv2
import os

video_path = 'example1.mp4'
output_dir = './animation_assets/'

if not os.path.exists(output_dir):
    os.makedirs(output_dir)

cap = cv2.VideoCapture(video_path)

frame_count = 0

while True: 
    # loop through each frame of the video
    ret, frame = cap.read()

    if not ret: 
        break

    frame_name = os.path.join(output_dir, f'frame_{frame_count:04d}.png')
    cv2.imwrite(frame_name, frame)

    print(f'saved {frame_name}')

    frame_count += 1

cap.release()

print("all frames extracted successfully")





```

### backend/playground.py

```python
print("executing file")

# in order to execute code live, pass the code in as a string to a variable and use the python exec() function to run it

code = """
print('test 1')
"""

code2 = """
print('test 2')
"""

exec(code + code2)

import os
from dotenv import load_dotenv
import google.generativeai as genai
from google.api_core.exceptions import (ResourceExhausted, FailedPrecondition, 
                                        InvalidArgument, ServiceUnavailable, 
                                        InternalServerError)

from external_functions import speak_to_user, animate_with_manim
# Load API keys
load_dotenv()
genai.configure(api_key=os.getenv("GEMINI_API_KEY"))

import subprocess

result = subprocess.run(["ls", "-l"], capture_output=True, text=True)
#print(result.stdout)
```

### frontend/src/styles/globals.css

```css
:root {
  
}
```

### frontend/src/styles/Home.module.css

```css
  .main {
    align-items: center;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    padding: 6rem;
    min-height: 20vh;
  }

```

### backend/fastapi/api/manim_script.py

```python
from manim import *
class video(Scene):
    def construct(self):
        matrix = Matrix([
            [1, 0, 0],
            [0, 1, 0],
            [0, 0, 1]
        ]).scale(2)
        self.play(Write(matrix))


```

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