# Project export: git.ar

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: Spatial computing can be more than games. We present a development tool on Snap Spectacles that visualizes git trees, with hand tracking to merge commits, and Google Gemini to summarize code diffs.
- Devpost: https://devpost.com/software/git-ar
- GitHub: https://github.com/MrCroesus/calhacks11.0
- Video: https://www.youtube.com/embed/VMPTAIHiXwI?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 4 GitHub contributor(s) — Rohan Virmani (32 commits), Amol Budhiraja (10 commits), Harris Thai (9 commits), Gregory Shklovski (2 commits)

## Devpost submission (written by the team)

### Inspiration

While working on an internship project this summer, one of our members spent 2 weeks on a large commit. Meanwhile, their teammate merged an 18-commit MR to the same codebase. Unfortunately, Gitlab forced them to rebase their 2 weeks of work onto 18 commits, where we had to resolve merge conflicts one-by-one, while remembering changes from the previous countless decisions. This distasteful experience wasn't a one time thing. At various hackathons, version control issues have resulted in an unfairly large amount of lost time, often taking up 4-6 hours of everyones time. We decided to take that time back, by visualizing version control conflicts, and leveraging LLMs to resolve the tedious rebase conflicts without relying on a sleepless hacker's strained memory.

### What it does

We have created a development tool that represents git trees in the AR environment of the Snap Spectacles. Using its hand tracking, we enable the user to move commits around with their hands, even creating merge requests when the user brings two commits together. To make the commits more understandable, we incorporated Google Gemini to summarize code differences between commits, making complex Git visualization tasks easier, to the point where you can consider it an educational tool.

### How we built it

We built our app for Snapchat AR Spectacles using Snap AR’s Lens Studio. Our backend is powered by Python and FastAPI, ensuring fast and reliable data processing. We integrated Google Gemini to generate natural language representations of the code changes that we are modeling in addition to generating descriptions for the pull requests that our tool creates. We also connected our backend to the GitHub API for real-time repository interactions and command handling. To optimize our development workflow, we leveraged other dev tools like Perplexity for efficient research and Warp for streamlined terminal operations.

### Challenges we ran into

The largest hurdle was working with the newly released Snap AR 2024 Spectacles, the lack of up-to-date tutorials and incomplete documentation made it difficult to fully understand and use certain features, slowing down our progress as we navigated the new toolset. Almost all of us were new to AR/VR/XR development, and none of us had ever used Snap's Lens Studio. Learning and implementing a new Lens was challenging under the tight deadlines, we had hours of trial and error on the most trivial tasks... Fortunately, there were tons of great people at the Snap booth and on Slack that were very helpful. Our application also had to manage synchronous environment while ensuring the system maintained low latency, making real-time requests to Github's API and Gemini to fetch content live. We also spent a lot of time trying to use voice APIs. Although voice commands would have been an intuitive feature for an AR-based tool, the development environment for our hardware didn’t support sending voice data or raw audio over network traffic. This lack of support prevented us from incorporating voice-based inputs, forcing us to stick to purely gesture-based controls. It was a significant design constraint, as integrating voice interactions could have streamlined the user experience. Finally, creating a tree-like data structure using GitHub’s API posed its own complexities. While GitHub offers powerful tools, mapping repositories into a format that could be visualized in AR as a Git tree was no easy task. It involved handling complex

### Accomplishments we're proud of

As it was our first time working with Snapchat Spectacles and Snap AR’s Lens Studio, FastAPI, GitHub API, and Google Gemini, we had a steep learning curve but gained invaluable experience and built out an amazing product. We explored various AR components of the glasses, such as hand tracking and gesture recognition, which enabled us to create an intuitive and interactive user experience. One of our proudest accomplishments is simplifying the merging operation by automating the pull request workflow, addressing one of the more tedious and complex aspects of development. This app not only solves a significant problem but also has the potential to greatly enhance our own development workflows. We’re proud to have brought this innovative solution to life!

### What we learned

We gained invaluable experience in developing for 3D environments, specifically in AR human-computer interaction (HCI) design, a first for all of us. We learned how to create intuitive, gesture-based interfaces that seamlessly integrate into the physical world. On the backend, we deepened our understanding of designing APIs for efficient handling of both synchronous and asynchronous requests, ensuring smooth performance even in an AR setting. Our dive into Git internals helped us master the complexities of version control, giving us a new appreciation for how Git operates under the hood.

### What's next

We hope to continue adding support for other git commands like rebasing and stashing commits in the future. We also would love the opportunity to integrate voice command handling in our product once it can support both voice commands and network requests together! Finally, we would love to get more developers to try our tool and add further support for other types of git tools like bitbucket and gitlab. Eventually we would love to port this application to the consumer ready Snap AR Spectacles for use in training junior engineers as well as new developers with access to AR hardware.

## README (from the GitHub repository)

# real


## Detected evidence (automated analysis)

Indexed codebase: 638 recognized source files, 3931 KB.
- FastAPI (technology) — detected in the code
- JavaScript (language) — detected in the code
- Python (language) — detected in the code
- TypeScript (language) — detected in the code
- Google Gemini (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (120 of 2224)

```
.gitignore
Gesture Detection/.gitattributes
Gesture Detection/.gitignore
Gesture Detection/Assets/Audio Analyzer/.hidden/beats_material.ss_graph
Gesture Detection/Assets/Audio Analyzer/.hidden/beats_material.ss_graph.meta
Gesture Detection/Assets/Audio Analyzer/Audio Analyzer Resources/Audio Tracks/Surprises To Dance To 16K - FIle Audio Track.mp3.meta
Gesture Detection/Assets/Audio Analyzer/Audio Analyzer Resources/Beats/Materials/beats_material.mat
Gesture Detection/Assets/Audio Analyzer/Audio Analyzer Resources/Beats/Materials/beats_material.mat.meta
Gesture Detection/Assets/Audio Analyzer/Audio Analyzer Resources/Beats/Meshes/Sphere.mesh
Gesture Detection/Assets/Audio Analyzer/Audio Analyzer Resources/Beats/Meshes/Sphere.mesh.meta
Gesture Detection/Assets/Audio Analyzer/Audio Analyzer Resources/Scripts/AudioAnalyzer.js
Gesture Detection/Assets/Audio Analyzer/Audio Analyzer Resources/Scripts/AudioAnalyzer.js.meta
Gesture Detection/Assets/Audio Analyzer/Audio Analyzer Resources/Scripts/AudioAnalyzerHelper.js
Gesture Detection/Assets/Audio Analyzer/Audio Analyzer Resources/Scripts/AudioAnalyzerHelper.js.meta
Gesture Detection/Assets/Audio Analyzer/Audio_Analyzer__PLACE_IN_OBJECTS_PANEL.prefab
Gesture Detection/Assets/Audio Analyzer/Audio_Analyzer__PLACE_IN_OBJECTS_PANEL.prefab.meta
Gesture Detection/Assets/Base.png.meta
Gesture Detection/Assets/Commit.prefab
Gesture Detection/Assets/Commit.prefab.meta
Gesture Detection/Assets/Device Camera Texture.deviceCameraTexture
Gesture Detection/Assets/Device Camera Texture.deviceCameraTexture.meta
Gesture Detection/Assets/Echopark.hdr
Gesture Detection/Assets/Echopark.hdr.meta
Gesture Detection/Assets/Gesture Triggers.lspkg
Gesture Detection/Assets/Gesture Triggers.lspkg.meta
Gesture Detection/Assets/GestureClassification.js
Gesture Detection/Assets/GestureClassification.js.meta
Gesture Detection/Assets/MaterialParams.png.meta
Gesture Detection/Assets/Normal.png.meta
Gesture Detection/Assets/PBR 1.mat
Gesture Detection/Assets/PBR 1.mat.meta
Gesture Detection/Assets/PBR.mat
Gesture Detection/Assets/PBR.mat.meta
Gesture Detection/Assets/pbr.ss_graph
Gesture Detection/Assets/pbr.ss_graph.meta
Gesture Detection/Assets/Render Target.renderTarget
Gesture Detection/Assets/Render Target.renderTarget.meta
Gesture Detection/Assets/rovirmani_currgoatify_data.json
Gesture Detection/Assets/rovirmani_currgoatify_data.json.meta
Gesture Detection/Assets/Scene.scene
Gesture Detection/Assets/Scene.scene.meta
Gesture Detection/Assets/Simple Transcribe.js
Gesture Detection/Assets/Simple Transcribe.js.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Audio/HoverAudioTrack.wav.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Audio/TriggerEndAudioTrack.wav.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Audio/TriggerStartAudioTrack.wav.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/BaseHandVisualsMaterials/PaintedGlow_Left.mat
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/BaseHandVisualsMaterials/PaintedGlow_Left.mat.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/BaseHandVisualsMaterials/PaintedGlow_Right.mat
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/BaseHandVisualsMaterials/PaintedGlow_Right.mat.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/BaseHandVisualsMaterials/RadialGradientOcclusion.mat
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/BaseHandVisualsMaterials/RadialGradientOcclusion.mat.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/BaseHandVisualsMaterials/TipGlowMaterial.mat
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/BaseHandVisualsMaterials/TipGlowMaterial.mat.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/BitmojiMaterial.mat
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/BitmojiMaterial.mat.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/ContainerImageMaterial.mat
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/ContainerImageMaterial.mat.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/LogoMaterial.mat
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/LogoMaterial.mat.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/NormalBasedTargetOutline.mat
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/NormalBasedTargetOutline.mat.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/PinchButtonDarkInactive.mat
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/PinchButtonDarkInactive.mat.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/PinchButtonDarkRadial.mat
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/PinchButtonDarkRadial.mat.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/PinchButtonToggleOffIcon.mat
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/PinchButtonToggleOffIcon.mat.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/PinchButtonToggleOnDefault.mat
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/PinchButtonToggleOnDefault.mat.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/PinchButtonToggleOnIcon.mat
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/PinchButtonToggleOnIcon.mat.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/PinchButtonToggleOnSelect.mat
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/PinchButtonToggleOnSelect.mat.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/ScaleBasedTargetOutline.mat
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/ScaleBasedTargetOutline.mat.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/ScrollBarButton.mat
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/ScrollBarButton.mat.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/ScrollBarSlider.mat
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/ScrollBarSlider.mat.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/SimplePBRMaterial.mat
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/SimplePBRMaterial.mat.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/SliderMat/PinchButtonDarkDefault.mat
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/SliderMat/PinchButtonDarkDefault.mat.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/SliderMat/PinchButtonOnSelect.mat
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/SliderMat/PinchButtonOnSelect.mat.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/SliderMat/SliderMat.mat
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/SliderMat/SliderMat.mat.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/SliderMat/TargetOutlineMaterial.mat
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/SliderMat/TargetOutlineMaterial.mat.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/SpritePreset.mat
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/SpritePreset.mat.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/TargetOutlineMaterial.mat
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/TargetOutlineMaterial.mat.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/Text3DDefault.mat
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Materials/Text3DDefault.mat.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Meshes/BoxMesh.mesh
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Meshes/BoxMesh.mesh.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Meshes/ButtonCapsuleMesh.mesh
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Meshes/ButtonCapsuleMesh.mesh.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Meshes/ButtonSphereMesh.mesh
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Meshes/ButtonSphereMesh.mesh.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Meshes/Check.mesh
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Meshes/Check.mesh.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Meshes/LeftHandMesh.mesh
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Meshes/LeftHandMesh.mesh.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Meshes/PlaneMesh.mesh
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Meshes/PlaneMesh.mesh.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Meshes/RightHandMesh.mesh
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Meshes/RightHandMesh.mesh.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Meshes/ScrollBarSlider.mesh
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Meshes/ScrollBarSlider.mesh.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Meshes/SliderSphereKnob.mesh
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Meshes/SliderSphereKnob.mesh.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Meshes/SliderTrack.mesh
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Meshes/SliderTrack.mesh.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Meshes/SnapGhost_Mesh.mesh
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Meshes/SnapGhost_Mesh.mesh.meta
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Meshes/SphereMesh.mesh
Gesture Detection/Assets/SpectaclesInteractionKit/Assets/Meshes/SphereMesh.mesh.meta
[2104 more files omitted for size]
```

### Dependencies

- requirements.txt: annotated-types@==0.7.0, anyio@==4.6.2.post1, anytree@==2.12.1, beautifulsoup4@==4.12.3, cachetools@==5.5.0, certifi@==2024.8.30, charset-normalizer@==3.4.0, click@==8.1.7, DateTime@==5.5, dnspython@==2.7.0, email_validator@==2.2.0, fastapi@==0.115.2, fastapi-cli@==0.0.5, google@==3.0.0, 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, h11@==0.14.0, httpcore@==1.0.6, httplib2@==0.22.0, httptools@==0.6.4, httpx@==0.27.2, idna@==3.10, Jinja2@==3.1.4, markdown-it-py@==3.0.0, MarkupSafe@==3.0.2, mdurl@==0.1.2, proto-plus@==1.24.0, protobuf@==5.28.2, pyasn1@==0.6.1, pyasn1_modules@==0.4.1, pydantic@==2.9.2, pydantic_core@==2.23.4, Pygments@==2.18.0, pyparsing@==3.2.0, python-dotenv@==1.0.1, python-multipart@==0.0.12, pytz@==2024.2, PyYAML@==6.0.2, requests@==2.32.3, rich@==13.9.2, rsa@==4.9, setuptools@==75.2.0, shellingham@==1.5.4, six@==1.16.0, sniffio@==1.3.1, soupsieve@==2.6, starlette@==0.40.0, tqdm@==4.66.5, typer@==0.12.5, typing_extensions@==4.12.2, uritemplate@==4.1.1, urllib3@==2.2.3, uvicorn@==0.32.0, uvloop@==0.21.0, watchfiles@==0.24.0, websockets@==13.1, zope.interface@==7.1.0
- src/requirements.txt: annotated-types@==0.7.0, anyio@==4.6.2.post1, anytree@==2.12.1, beautifulsoup4@==4.12.3, cachetools@==5.5.0, certifi@==2024.8.30, charset-normalizer@==3.4.0, click@==8.1.7, DateTime@==5.5, dnspython@==2.7.0, email_validator@==2.2.0, fastapi@==0.115.2, fastapi-cli@==0.0.5, google@==3.0.0, 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, h11@==0.14.0, httpcore@==1.0.6, httplib2@==0.22.0, httptools@==0.6.4, httpx@==0.27.2, idna@==3.10, Jinja2@==3.1.4, markdown-it-py@==3.0.0, MarkupSafe@==3.0.2, mdurl@==0.1.2, proto-plus@==1.24.0, protobuf@==5.28.2, pyasn1@==0.6.1, pyasn1_modules@==0.4.1, pydantic@==2.9.2, pydantic_core@==2.23.4, Pygments@==2.18.0, pyparsing@==3.2.0, python-dotenv@==1.0.1, python-multipart@==0.0.12, pytz@==2024.2, PyYAML@==6.0.2, requests@==2.32.3, rich@==13.9.2, rsa@==4.9, setuptools@==75.2.0, shellingham@==1.5.4, six@==1.16.0, sniffio@==1.3.1, soupsieve@==2.6, starlette@==0.40.0, tqdm@==4.66.5, typer@==0.12.5, typing_extensions@==4.12.2, uritemplate@==4.1.1, urllib3@==2.2.3, uvicorn@==0.32.0, uvloop@==0.21.0, watchfiles@==0.24.0, websockets@==13.1, zope.interface@==7.1.0

### Recent commits (newest first)

- added commit descs
- more words for gemini
- Fixed UI Sizes
- Integrated Git Merge and PR Functionality into Snapchat AR Interface
- refactor
- request for commit analysis ready
- Created pull request confirmation window
- Merge branch 'main' of https://github.com/MrCroesus/calhacks11.0
- Created endpoint to create pull requests with commit parsing and gemini-driven description generation
- added UI for picking a repo as RepoPickerUI
- Tree Generation with API call complete
- remove os calls
- Merge branch 'main' of github.com:MrCroesus/calhacks11.0
- removed saving to filesystem to stop vercel/aws errors
- Merge branch 'main' of https://github.com/MrCroesus/calhacks11.0
- Fixed sorting of commits
- reqs?
- real cook
- cook?
- Merge branch 'main' of https://github.com/MrCroesus/calhacks11.0

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

### requirements.txt

```
annotated-types==0.7.0
anyio==4.6.2.post1
anytree==2.12.1
beautifulsoup4==4.12.3
cachetools==5.5.0
certifi==2024.8.30
charset-normalizer==3.4.0
click==8.1.7
DateTime==5.5
dnspython==2.7.0
email_validator==2.2.0
fastapi==0.115.2
fastapi-cli==0.0.5
google==3.0.0
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
h11==0.14.0
httpcore==1.0.6
httplib2==0.22.0
httptools==0.6.4
httpx==0.27.2
idna==3.10
Jinja2==3.1.4
markdown-it-py==3.0.0
MarkupSafe==3.0.2
mdurl==0.1.2
proto-plus==1.24.0
protobuf==5.28.2
pyasn1==0.6.1
pyasn1_modules==0.4.1
pydantic==2.9.2
pydantic_core==2.23.4
Pygments==2.18.0
pyparsing==3.2.0
python-dotenv==1.0.1
python-multipart==0.0.12
pytz==2024.2
PyYAML==6.0.2
requests==2.32.3
rich==13.9.2
rsa==4.9
setuptools==75.2.0
shellingham==1.5.4
six==1.16.0
sniffio==1.3.1
soupsieve==2.6
starlette==0.40.0
tqdm==4.66.5
typer==0.12.5
typing_extensions==4.12.2
uritemplate==4.1.1
urllib3==2.2.3
uvicorn==0.32.0
uvloop==0.21.0
watchfiles==0.24.0
websockets==13.1
zope.interface==7.1.0

```

### src/requirements.txt

```
annotated-types==0.7.0
anyio==4.6.2.post1
anytree==2.12.1
beautifulsoup4==4.12.3
cachetools==5.5.0
certifi==2024.8.30
charset-normalizer==3.4.0
click==8.1.7
DateTime==5.5
dnspython==2.7.0
email_validator==2.2.0
fastapi==0.115.2
fastapi-cli==0.0.5
google==3.0.0
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
h11==0.14.0
httpcore==1.0.6
httplib2==0.22.0
httptools==0.6.4
httpx==0.27.2
idna==3.10
Jinja2==3.1.4
markdown-it-py==3.0.0
MarkupSafe==3.0.2
mdurl==0.1.2
proto-plus==1.24.0
protobuf==5.28.2
pyasn1==0.6.1
pyasn1_modules==0.4.1
pydantic==2.9.2
pydantic_core==2.23.4
Pygments==2.18.0
pyparsing==3.2.0
python-dotenv==1.0.1
python-multipart==0.0.12
pytz==2024.2
PyYAML==6.0.2
requests==2.32.3
rich==13.9.2
rsa==4.9
setuptools==75.2.0
shellingham==1.5.4
six==1.16.0
sniffio==1.3.1
soupsieve==2.6
starlette==0.40.0
tqdm==4.66.5
typer==0.12.5
typing_extensions==4.12.2
uritemplate==4.1.1
urllib3==2.2.3
uvicorn==0.32.0
uvloop==0.21.0
watchfiles==0.24.0
websockets==13.1
zope.interface==7.1.0

```

### src/index.py

```python
import sys
from pathlib import Path

# Add the parent directory (which contains 'src') to the Python path
from main import app

# This is necessary for Vercel serverless deployment
app = app

```

### src/main.py

```python
import json
from fastapi import FastAPI
from fastapi.responses import JSONResponse
from fastapi.encoders import jsonable_encoder
from dotenv import load_dotenv
import os
from commit import Commit


# #TODO:
from grab_repo import get_repository_data, process_data
from rate import check_rate_limit
from tree_vis import process_repo_data

# Load environment variables
dotenv_path = os.path.join(os.path.dirname(__file__), '..', '.env')
load_dotenv(dotenv_path)

app = FastAPI()

@app.get("/")
async def root():
    return {"message": "Github API Procesing"}

@app.get("/rate-limit")
async def rate_limit():
    return check_rate_limit()

@app.get("/repo/{owner}/{repo}")
async def get_repo_data(owner: str, repo: str):
    branches, commits = get_repository_data(owner, repo)
    processed_data = process_data(branches, commits)
    
    #os.makedirs('repo_data', exist_ok=True)
    
    # Save the data to a JSON file
    filename = f"repo_data/{owner}_{repo}_data.json"
    # with open(filename, 'w') as f:
    #     json.dump(processed_data, f, indent=2)
    
    # Print the formatted JSON to the terminal
    #print(json.dumps(processed_data, indent=2))
    
    content = jsonable_encoder(processed_data)
    return JSONResponse(
        content=content, 
        headers={
            "Content-Type": "application/json",
            "X-JSON-File": filename
        }
    )

@app.get("/repo/{owner}/{repo}/tree")
async def get_repo_tree(owner: str, repo: str):
    branches, commits = get_repository_data(owner, repo)
    processed_data = process_data(branches, commits)
    tree_data = process_repo_data(processed_data)
    
    #os.makedirs('repo_data', exist_ok=True)
    
    # Save the tree data to a JSON file
    filename = f"repo_data/{owner}_{repo}_tree_data.json"
    # with open(filename, 'w') as f:
    #     json.dump(tree_data, f, indent=2)
    
    # Print the formatted JSON to the terminal
    #print(json.dumps(tree_data, indent=2))
    
    content = jsonable_encoder(tree_data)
    return JSONResponse(
        content=content, 
        headers={
            "Content-Type": "application/json",
            "X-JSON-File": filename
        }
    )

@app.get("/commit/{owner}/{repo}/get/{hash}")
async def get_commit_info(owner: str, repo: str, hash: str):
    """Get the information about a given commit."""
    commit_obj = Commit(owner, repo)
    return commit_obj.get_commit(hash=hash)

@app.get("/createpr/{owner}/{repo}/{branch1}/{branch2}")
async def get_commit_info(owner: str, repo: str, branch1: str, branch2: str):
    """Create a pull request to merge branches BRANCH1 and BRANCH2."""
    commit_obj = Commit(owner, repo)
    return commit_obj.create_pr(branch1, branch2)
    
if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

```

### src/rate.py

```python
import os
from dotenv import load_dotenv
import requests
from datetime import datetime, timezone

# Load .env from the parent directory
dotenv_path = os.path.join(os.path.dirname(__file__), '..', '.env')
load_dotenv(dotenv_path)

GITHUB_TOKEN = os.getenv("GITHUB_TOKEN")

headers = {
    "Authorization": f"token {GITHUB_TOKEN}",
    "Accept": "application/vnd.github.v3+json"
}
API_BASE_URL = "https://api.github.com"

def check_rate_limit():
    rate_limit_url = f"{API_BASE_URL}/rate_limit"
    response = requests.get(rate_limit_url, headers=headers)
    if response.status_code == 200:
        data = response.json()
        core_limit = data['resources']['core']
        print(f"API Rate Limit:")
        print(f"  Limit: {core_limit['limit']}")
        print(f"  Remaining: {core_limit['remaining']}")
        print(f"  Reset Time: {datetime.fromtimestamp(core_limit['reset'], timezone.utc).strftime('%Y-%m-%d %H:%M:%S UTC')}")
    else:
        print(f"Failed to fetch rate limit info: {response.status_code} - {response.text}")

if __name__ == "__main__":
    check_rate_limit()
```

### src/tree_vis.py

```python
from anytree import Node, RenderTree
from anytree.exporter import DotExporter
from typing import Dict, List
import io
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def build_commit_tree(data: Dict) -> Node:
    commits = {commit['sha']: commit for commit in data['commits']}
    relationships = data['relationships']

    if not commits:
        logger.error("No commits found in the repository data")
        raise ValueError("No commits found in the repository data")

    # Use the first commit as the root
    root_sha = next(iter(commits))
    logger.info(f"Using commit {root_sha} as the root")

    # Dictionary to store created nodes
    nodes = {}

    def build_tree(sha: str, parent=None) -> Node:
        if sha in nodes:
            return nodes[sha]

        commit = commits[sha]
        node = Node(f"{sha[:7]}: {commit['message']}", parent=parent)
        nodes[sha] = node

        for rel in relationships:
            if rel['to'] == sha and rel['from'] in commits:
                child = build_tree(rel['from'], parent=node)
                if child not in node.children:
                    node.children += (child,)

        return node

    return build_tree(root_sha)

def generate_tree_visualization(root: Node) -> str:
    tree_viz = io.StringIO()
    for pre, _, node in RenderTree(root):
        tree_viz.write(f"{pre}{node.name}\n")
    return tree_viz.getvalue()

def export_tree_to_dot(root: Node, filename: str = "tree.dot"):
    DotExporter(root).to_dotfile(filename)
    return filename

def process_repo_data(data: Dict) -> Dict:
    root = build_commit_tree(data)
    tree_visualization = generate_tree_visualization(root)
    dot_filename = export_tree_to_dot(root)
    
    return {
        "original_data": data,
        "tree_visualization": tree_visualization,
        "dot_file": dot_filename
    }

```

### src/grab_repo.py

```python
import os
from dotenv import load_dotenv
import requests
from datetime import datetime, timezone
from pprint import pformat, pprint
from collections import defaultdict
from datetime import datetime


# Load .env from the parent directory
dotenv_path = os.path.join(os.path.dirname(__file__), '..', '.env')
load_dotenv(dotenv_path)

GITHUB_TOKEN = os.getenv("GITHUB_TOKEN")

headers = {
    "Authorization": f"token {GITHUB_TOKEN}",
    "Accept": "application/vnd.github.v3+json"
}
API_BASE_URL = "https://api.github.com"


def get_repository_data(owner, repo):
    branches_url = f"{API_BASE_URL}/repos/{owner}/{repo}/branches"
    branches_response = requests.get(branches_url, headers=headers)
    branches = branches_response.json()

    def datetime_sort_key(date_string):
        print(date_string)
        return datetime.strptime(date_string, "%Y-%m-%dT%H:%M:%SZ")


    all_commits = []
    for branch in branches:
        branch_name = branch['name']
        commits_url = f"{API_BASE_URL}/repos/{owner}/{repo}/commits"
        params = {"sha": branch_name, "per_page": 100}  # Limit to 100 commits per branch
        commits_response = requests.get(commits_url, headers=headers, params=params)
        branch_commits = commits_response.json()
        for commit in branch_commits:
            commit['branch'] = branch_name
        all_commits.extend(branch_commits)
    all_commits.sort(key=lambda commit: commit['commit']['author']['date'])
    return branches, all_commits

def process_data(branches, all_commits):
    processed_data = {
        "branches": [],
        "commits": [],
        "relationships": []
    }

    commit_to_branch = {}
    commit_data = {}

    # Process branches
    for branch in branches:
        processed_data["branches"].append({
            "name": branch['name'],
            "sha": branch['commit']['sha']
        })

    # First pass: associate commits with branches
    for commit in all_commits:
        sha = commit['sha']
        if sha not in commit_to_branch:
            commit_to_branch[sha] = commit['branch']
        
        if sha not in commit_data:
            commit_data[sha] = {
                "sha": sha,
                "message": commit['commit']['message'],
                "author": commit['commit']['author']['name'],
                "date": commit['commit']['author']['date'],
                "parents": [parent['sha'] for parent in commit['parents']],
                "branch": commit['branch']
            }

    # Second pass: handle merge commits
    for sha, data in commit_data.items():
        if len(data['parents']) > 1:  # This is a merge commit
            data['branch'] = commit_to_branch[sha]  # Use the branch it's being merged into

    # Populate processed_data
    for sha, data in commit_data.items():
        processed_data["commits"].append(data)
        for parent_sha in data['parents']:
            processed_data["relationships"].append({
                "from": sha,
                "to": parent_sha
            })

    return processed_data

def main(owner, repo):
    branches, all_commits = get_repository_data(owner, repo)
    processed_data = process_data(branches, all_commits)
    return processed_data

# temp repo for test #TODO: GENERALIZE FOR FASTAPI
if __name__ == "__main__":
    owner = "rovirmani"
    repo = "currgoatify"
    result = main(owner, repo)
    # pprint(result)
```

### src/commit.py

```python
import os
import requests
import google.generativeai as genai
import re

class Commit:
    def __init__(self, owner: str, repo: str):
        self.owner = owner
        self.repo = repo
        _GITHUB_TOKEN = os.getenv("GITHUB_TOKEN")
        self.HEADERS = {
            "Authorization": f"token {_GITHUB_TOKEN}",
            "Accept": "application/vnd.github.v3+json"
        }
        self.API_BASE_URL = "https://api.github.com"
        
        # Configure Gemini
        genai.configure(api_key=os.getenv("GEMINI_TOKEN"))
        self.gemini = genai.GenerativeModel("gemini-1.5-flash")

    def get_commit(self, hash: str):
        """Return the COMMIT associated to the SHA HASH: hash."""
        url = f"{self.API_BASE_URL}/repos/{self.owner}/{self.repo}/commits/{hash}"
        
        response = requests.get(url, headers=self.HEADERS)


        if response.status_code == 200:
            commit_data = response.json()
            code_changes = self.extract_code_changes(commit_data)
            code_description_response = self.gemini.generate_content(f"40 WORDS MAX. Given the following commit message and code changes please generate a description of the changes done in the commit: COMMIT MESSAGE: {commit_data['commit']['message']} CODE CHANGES: {code_changes}")

            code_changes_description = str(code_description_response.candidates[0].content.parts[0].text)

            commit_info = f"""{commit_data['commit']['message']}
            By {commit_data['commit']['author']['name']}
            Committed on: {commit_data['commit']['author']['date']}
            + {commit_data['stats']['additions']} - {commit_data['stats']['deletions']} lines
            Commit Hash: {commit_data['sha']}

            Diff Analysis:
            {code_changes_description}"""

            # Remove all newlines and extra whitespace
            commit_info = re.sub(r'\s+', ' ', commit_info)

            return commit_info.strip()
        return {"error": f"Failed to fetch commit info. Status code: {response.status_code}"}

    def extract_code_changes(self, commit_data):
        """Parse out the code changes done in the commit."""
        changes = []
        for file in commit_data.get('files', []):
            filename = file['filename']
            patch = file.get('patch', '')
            changes.append(f"File: {filename}\n{patch}\n")
        return "\n".join(changes)

    def analyze_commit(self, commit_info):
        """Analyze the commit using Gemini."""
        prompt = f"""Analyze the following commit:
        SHA: {commit_info['sha']}
        Author: {commit_info['author']}
        Date: {commit_info['date']}
        Message: {commit_info['message']}
        Code Changes:
        {commit_info['code_changes']}

        Provide a brief summary of the changes and their potential impact."""

        response = self.gemini.generate_content(prompt)
        return response.text

    def create_pr(self, branch1: str, branch2: str):
        
        branch1_url = f"{self.API_BASE_URL}/repos/{self.owner}/{self.repo}/git/refs/heads/{branch1}"
        branch2_url = f"{self.API_BASE_URL}/repos/{self.owner}/{self.repo}/git/refs/heads/{branch2}"

        branch1_commit = requests.get(branch1_url, headers=self.HEADERS)
        branch2_commit = requests.get(branch2_url, headers=self.HEADERS)

        def get_commit_sha(commit):
            return commit.json()['object']['sha']
        
        hash1, hash2 = get_commit_sha(branch1_commit), get_commit_sha(branch2_commit)

        commit1, commit2 = self.get_commit(hash1), self.get_commit(hash2)

        code_description_response = self.gemini.generate_content(f"We are currently merging COMMIT1 into COMMIT2. Can you generate a description of this merge and the changes that we are merging together. This will serve as the body of a pull request and displayed to the user so keep in natural language. Here is COMMIT1: {commit1}. Here is COMMIT2: {commit2}.")

        code_changes_description = str(code_description_response.candidates[0].content.parts[0].text)

        code_title_response = self.gemini.generate_content(f"We are currently merging COMMIT1 into COMMIT2. Can you generate a title for the pull request of this merge. Please just return the title and nothing else. Here is COMMIT1: {commit1}. Here is COMMIT2: {commit2}.")

        code_title = str(code_title_response.candidates[0].content.parts[0].text)
        
        pr_data = {
            "title": code_title,
            "head": branch1,
            "base": branch2,
            "body": code_changes_description,
            "owner": 'OWNER',
            "repo": 'REPO',
        }

        pr_response = requests.post(f"{self.API_BASE_URL}/repos/{self.owner}/{self.repo}/pulls", headers=self.HEADERS, json=pr_data)

        return pr_response.text


# Usage example
commit = Commit("owner", "repo")
commit_info = commit.get_commit("commit_hash")
if "error" not in commit_info:
    analysis = commit.analyze_commit(commit_info)
    print(analysis)
else:
    print(commit_info["error"])
```

### RepoPickerUI/Assets/repoSelectionFuncitons.js

```javascript

script.onRepoSelection1 = function () {
    print("Name: ")
    print("Repo 1 Selected! ");
};

script.onRepoSelection2 = function () {
    print("Name: ")
    print("Repo 2 Selected! ");
};

script.onRepoSelection3 = function () {
    print("Name: ")
    print("Repo 3 Selected! ");
};

```

### Gesture Detection/Assets/TreeGeneration.js

```javascript
//@input Component.Camera camera
//@input Asset.ObjectPrefab myPrefab

function onTouchStart() {
  if (script.camera) {
//    var touchPosition = e.getTouchPosition();
//    var worldPosition = script.camera.screenSpaceToWorldSpace(
//      touchPosition,
//      200
//    );
    var mySceneObject = createObjectFromPrefab();
//    mySceneObject.getTransform().setWorldPosition(worldPosition);
  }
}
function createObjectFromPrefab() {
  if (script.myPrefab) {
    var instanceObject = script.myPrefab.instantiate(script.getSceneObject());
    return instanceObject;
  } else {
    return undefined;
  }
}

onTouchStart();
```

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