# Project export: ScoutIT

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: UC Berkeley AI Hackathon 2025
- Tagline: We're revolutionizing scouting by combining Moneyball analytics to AI computer vision. Our system spots talent by analyzing player mechanics & movements, turning visual data into actionable insights.
- Devpost: https://devpost.com/software/vision-scout
- GitHub: https://github.com/EmperorAry/vision-scout.git
- Demo: http://scoutit.tech/
- Video: https://www.youtube.com/embed/bWs5Uo1_y-Y?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 1 GitHub contributor(s) — Aryan (1 commits)

## Devpost submission (written by the team)

### Inspiration

"What started with a winning strategy —finding undervalued players while others chased the obvious choices—evolved into a bigger revelation. Like Moneyball revolutionized baseball through data, we saw an opportunity to transform scouting itself. But we're going beyond just statistics. Through computer vision and AI, we're capturing the intangibles: the perfect arc of a shot, the millisecond decisions, the biomechanics that make athletes exceptional. This isn't just an iteration of scouting—it's a complete reimagining." What It Does ScoutIT combines cutting-edge AI with sports science to deliver two game-changing features: Quick Evaluation: Upload any player's footage, and our AI instantly compares their mechanics against a database of elite athletes, providing immediate insights and improvement areas. Potential Predictor: Using our proprietary Differences in Differences Model powered by GenAI, we analyze a player's progression over time to forecast their peak potential, considering factors traditional scouts might miss. How We Built It Our development approach combined the following key technologies Real-time Tracking and Masking: Implementing YOLO object detection models to follow ball movement and player interactions based on which we perform our image masking. Movement Analysis through Pose Estimation: Leveraging OpenPose and MediaPipe to extract precise skeletal data enabling us to analyze deeper biomechanics Vector Image Reconstruction: Developing diffusion models into our processing pipeline reconstructing uploading videos to create an "ideal shot video" path based on which our LLM models are finetuned Performance Scoring: Creating a standardized 100-point scoring system based on Hall of Famers like Stephen Curry and LeBron James Growth Prediction through Vision Models: Using the finetuned GenAI vision models to generate feature importance arrays that project a player's development trajectory Challenges We Ran Into Our biggest hurdles became our greatest innovations: Data Variability: Developed adaptive preprocessing algorithms to handle diverse video qualities and conditions Player Tracking and Masking: Created a ball-focused tracking system that maintains player identification in crowded situations by incorporating Convex Hull masking techniques Insight Generation: Implemented GenAI to translate complex metrics into actionable basketball insights" What's Next for ScoutIT? ScoutIT is set to transform sports scouting across three dimensions: Multi-Sport Evolution: Adapting our AI to analyze sport-specific mechanics across basketball, soccer, baseball, and esports Real-Time Intelligence: Developing instant analysis capabilities for in-game strategic adjustments Democratizing Development: Creating personalized training insights accessible to athletes at all levels" We believe the sky is the limit for ScoutIT! Impact ScoutIT isn't just changing how we scout talent—it's democratizing access to professional-level analysis. By making advanced biomechanical analysis accessible to teams and athletes at all levels, we're helping uncover hidden talent and potential that traditional scouting might miss. This technology could be particularly transformative for under-resourced programs and emerging sports markets.

## README (from the GitHub repository)

No README available.

## Detected evidence (automated analysis)

Indexed codebase: 1262 recognized source files, 26454 KB.
- C (language) — detected in the code
- C++ (language) — detected in the code
- CSS (language) — detected in the code
- FastAPI (technology) — detected in the code
- Firebase (technology) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- LangChain (technology) — detected in the code
- Python (language) — detected in the code
- PyTorch (technology) — detected in the code
- React (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code
- TypeScript (language) — detected in the code
- Google Gemini (technology) — claimed on Devpost, not found in the code
- Streamlit (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (120 of 1999)

```
.gitignore
backend/.python-version
backend/agents/improvement_vector_pro_agent.py
backend/agents/quick_analysis_agent.py
backend/agents/score_agent.py
backend/agents/talent_scout_agent.py
backend/agents/video_reconstruction_agent.py
backend/agents/visual_agent.py
backend/basketball.v1i.yolov8/data.yaml
backend/basketball.v1i.yolov8/README.dataset.txt
backend/basketball.v1i.yolov8/README.roboflow.txt
backend/basketball.v1i.yolov8/test/labels/image_1073_jpg.rf.a3caa1979b941d20704bdf87a047e2e9.txt
backend/basketball.v1i.yolov8/test/labels/image_1074_jpg.rf.b23681e27a6b0216469532d5b605d017.txt
backend/basketball.v1i.yolov8/test/labels/image_1083_jpg.rf.e401906518d2076cd5bcf9e2ea48d448.txt
backend/basketball.v1i.yolov8/test/labels/image_1090_jpg.rf.fa5ec8a46e61981187bc405ca517b68e.txt
backend/basketball.v1i.yolov8/test/labels/image_1094_jpg.rf.e746aa566383e23d31cd51ef93829b10.txt
backend/basketball.v1i.yolov8/test/labels/image_1117_jpg.rf.911dd7c65f2f7a06fb7f7be76b84a593.txt
backend/basketball.v1i.yolov8/test/labels/image_1129_jpg.rf.1774788914ad87806784ee8b87004281.txt
backend/basketball.v1i.yolov8/test/labels/image_1197_jpg.rf.ff914b3a9bc26195f50b6e4bef970fa9.txt
backend/basketball.v1i.yolov8/test/labels/image_1203_jpg.rf.30c6089396a905bd458455ba501f4359.txt
backend/basketball.v1i.yolov8/test/labels/image_1204_jpg.rf.483ebeb9248886f581e8f0dd0d43ae51.txt
backend/basketball.v1i.yolov8/test/labels/image_1207_jpg.rf.1f3fb3224f1709195df8dbf2346f87ec.txt
backend/basketball.v1i.yolov8/test/labels/image_1226_jpg.rf.6c23ceb90a758597683fac98b96507f0.txt
backend/basketball.v1i.yolov8/test/labels/image_1227_jpg.rf.071c13fdb4e7fc0fee333468357206ad.txt
backend/basketball.v1i.yolov8/test/labels/image_1265_jpg.rf.960e597aa18d8465a55cacc26ee354bc.txt
backend/basketball.v1i.yolov8/test/labels/image_1266_jpg.rf.134fe4d5713747ff7d1af9a3819c1fe4.txt
backend/basketball.v1i.yolov8/test/labels/image_1269_jpg.rf.1ac0db2fb237b5dc9db63fa84112aaae.txt
backend/basketball.v1i.yolov8/test/labels/image_1275_jpg.rf.466d43cdb268c0d6f8aff631acad0052.txt
backend/basketball.v1i.yolov8/test/labels/image_1295_jpg.rf.1c3da4907c1c3a1463af76d617da78af.txt
backend/basketball.v1i.yolov8/test/labels/image_1305_jpg.rf.aad8ec8d75cd0ef604e7581aa543d7ac.txt
backend/basketball.v1i.yolov8/test/labels/image_1316_jpg.rf.1d69fab0ba63fb3775a8d0f159f3ef22.txt
backend/basketball.v1i.yolov8/test/labels/image_1320_jpg.rf.e5afe00d6e0fa7c9a09ccbfba51c27f3.txt
backend/basketball.v1i.yolov8/test/labels/image_1321_jpg.rf.c9e40267ded43dc5cd26d36a269f7fdb.txt
backend/basketball.v1i.yolov8/test/labels/image_1335_jpg.rf.daeade5ebca997e90c88670d557f5289.txt
backend/basketball.v1i.yolov8/test/labels/image_1347_jpg.rf.9bb6c32c5ab9eeee01e721f835ed5089.txt
backend/basketball.v1i.yolov8/test/labels/image_1379_jpg.rf.77702bc7d7f5c57e5a47b7ca87c3447c.txt
backend/basketball.v1i.yolov8/test/labels/image_1381_jpg.rf.516cc13e0aa7e2652f59489212249f83.txt
backend/basketball.v1i.yolov8/test/labels/image_1400_jpg.rf.9edde72be13d8f1165d39d262ab16aa4.txt
backend/basketball.v1i.yolov8/test/labels/image_1403_jpg.rf.eb5868097133942f6d3e08a53ab57479.txt
backend/basketball.v1i.yolov8/test/labels/image_1416_jpg.rf.7d0aad8e43e77263a55451a63f3d7d53.txt
backend/basketball.v1i.yolov8/test/labels/image_1429_jpg.rf.0d52222028ba3560477a492dd66f6a96.txt
backend/basketball.v1i.yolov8/train/labels/image_1055_jpg.rf.47e118cb06994f8f29a4f54b348bb83e.txt
backend/basketball.v1i.yolov8/train/labels/image_1058_jpg.rf.6aa5687b676d5cd6f22d03b9f6861d85.txt
backend/basketball.v1i.yolov8/train/labels/image_1059_jpg.rf.4741ec6a93e163af54fcca5db2c4a37d.txt
backend/basketball.v1i.yolov8/train/labels/image_1061_jpg.rf.06de9611f90aaa8245ade8b1adaeaa5f.txt
backend/basketball.v1i.yolov8/train/labels/image_1062_jpg.rf.cdf82aa6ee28537fd2c59be423d42292.txt
backend/basketball.v1i.yolov8/train/labels/image_1063_jpg.rf.414141207b44f0ba042fd2310d6bddf6.txt
backend/basketball.v1i.yolov8/train/labels/image_1064_jpg.rf.c7eac055015c58be14902599e158f18a.txt
backend/basketball.v1i.yolov8/train/labels/image_1066_jpg.rf.a521dcdb66d7a753d1b5965109a254e0.txt
backend/basketball.v1i.yolov8/train/labels/image_1069_jpg.rf.98f4735869ae079524430ebb352ade40.txt
backend/basketball.v1i.yolov8/train/labels/image_1070_jpg.rf.2e518dae64e4ccdc60319efcdd255b85.txt
backend/basketball.v1i.yolov8/train/labels/image_1071_jpg.rf.f930400af1af68fac2cc0f57969322e9.txt
backend/basketball.v1i.yolov8/train/labels/image_1075_jpg.rf.1a06444b936d330b30dcda9f44d0c510.txt
backend/basketball.v1i.yolov8/train/labels/image_1076_jpg.rf.8a8e3d93fd70736a87980dae149b985c.txt
backend/basketball.v1i.yolov8/train/labels/image_1077_jpg.rf.bf1c425ef72846b91974359674209c87.txt
backend/basketball.v1i.yolov8/train/labels/image_1079_jpg.rf.259d65299e5bcba58387d2c852d55547.txt
backend/basketball.v1i.yolov8/train/labels/image_1081_jpg.rf.4338263ccf0f70d0d330f4e171188704.txt
backend/basketball.v1i.yolov8/train/labels/image_1084_jpg.rf.e1b2e1fa63c110cd3a53124b01d781e4.txt
backend/basketball.v1i.yolov8/train/labels/image_1086_jpg.rf.4ae5ff8cdfc9304cf686bc614396324b.txt
backend/basketball.v1i.yolov8/train/labels/image_1088_jpg.rf.d9c3ad2eb9ba156236895bec7c05405f.txt
backend/basketball.v1i.yolov8/train/labels/image_1091_jpg.rf.ce9366ebf693bc5d0bf4b4146863d4fb.txt
backend/basketball.v1i.yolov8/train/labels/image_1092_jpg.rf.3f2ea439b1c1f2ee592b11eed6da01ac.txt
backend/basketball.v1i.yolov8/train/labels/image_1093_jpg.rf.e8f7365417234ed3399f6960ee42348f.txt
backend/basketball.v1i.yolov8/train/labels/image_1095_jpg.rf.3ff628109c11b738b3afb92f45d96b44.txt
backend/basketball.v1i.yolov8/train/labels/image_1096_jpg.rf.6ae6df2530a88d45e6a646928b0645cb.txt
backend/basketball.v1i.yolov8/train/labels/image_1097_jpg.rf.572bde348be63022c7e313f7a089c3df.txt
backend/basketball.v1i.yolov8/train/labels/image_1100_jpg.rf.81e58d296841234c966977b1457f747d.txt
backend/basketball.v1i.yolov8/train/labels/image_1103_jpg.rf.c70e3c1a2d95401cefd08fa82caf5256.txt
backend/basketball.v1i.yolov8/train/labels/image_1104_jpg.rf.8dbf0ab62913191aaaf65cfb0d0dcc96.txt
backend/basketball.v1i.yolov8/train/labels/image_1105_jpg.rf.7b609e26bfd5378e28fc3a7493b42ba6.txt
backend/basketball.v1i.yolov8/train/labels/image_1109_jpg.rf.d351aaf12e93512fc2f228fafdf5667f.txt
backend/basketball.v1i.yolov8/train/labels/image_1112_jpg.rf.13023549f5c9c2f4e4adf8f79a75d476.txt
backend/basketball.v1i.yolov8/train/labels/image_1114_jpg.rf.7d6799341a499f923668354cba2427f7.txt
backend/basketball.v1i.yolov8/train/labels/image_1115_jpg.rf.fb46567346f7d89d01827a6d3605d0c7.txt
backend/basketball.v1i.yolov8/train/labels/image_1118_jpg.rf.1f64cda69d263f08c951b3a1321bd3d0.txt
backend/basketball.v1i.yolov8/train/labels/image_1120_jpg.rf.67312cc4c13f90d424d5e0596041ae1a.txt
backend/basketball.v1i.yolov8/train/labels/image_1121_jpg.rf.44652ef39201e82eb8a225c4845c86c8.txt
backend/basketball.v1i.yolov8/train/labels/image_1124_jpg.rf.968703ec9a829b360058f51a691d2b7d.txt
backend/basketball.v1i.yolov8/train/labels/image_1126_jpg.rf.2da7e31fe8644134fe32a42718a3623f.txt
backend/basketball.v1i.yolov8/train/labels/image_1127_jpg.rf.d387cc671451ae2991a65e70f1db1f53.txt
backend/basketball.v1i.yolov8/train/labels/image_1132_jpg.rf.9f8c955927e76a470a6b9ca1e70d156d.txt
backend/basketball.v1i.yolov8/train/labels/image_1134_jpg.rf.944c303597c17367bcc2be5eb918b0a1.txt
backend/basketball.v1i.yolov8/train/labels/image_1135_jpg.rf.08d58a85a32d05dfb0ad29c7f0b5dcee.txt
backend/basketball.v1i.yolov8/train/labels/image_1137_jpg.rf.d828b98ee5573184850c33f7e77d35d6.txt
backend/basketball.v1i.yolov8/train/labels/image_1140_jpg.rf.f401ae988c16cd15178f91bfba820aa1.txt
backend/basketball.v1i.yolov8/train/labels/image_1143_jpg.rf.b2aef234907d1d37886334924c2cb6c1.txt
backend/basketball.v1i.yolov8/train/labels/image_1144_jpg.rf.dd76006908b51253f2b8b8f1e5263d03.txt
backend/basketball.v1i.yolov8/train/labels/image_1145_jpg.rf.c1b3e384d10eba2ff9fe104d15c0c2d8.txt
backend/basketball.v1i.yolov8/train/labels/image_1146_jpg.rf.f3b711ac4b866ec17d3faa476e5ad171.txt
backend/basketball.v1i.yolov8/train/labels/image_1147_jpg.rf.fc694f670e3e64702ddf38a13cee80f0.txt
backend/basketball.v1i.yolov8/train/labels/image_1149_jpg.rf.5e82726854c3a64ae43829a84b1dfbfb.txt
backend/basketball.v1i.yolov8/train/labels/image_1151_jpg.rf.3e805ab66d1c83b360803812f98bcd2e.txt
backend/basketball.v1i.yolov8/train/labels/image_1153_jpg.rf.c76e2b41880ad7ff7eded033b3dffe74.txt
backend/basketball.v1i.yolov8/train/labels/image_1156_jpg.rf.2cbead9dcdc73053ba6669365c48edbf.txt
backend/basketball.v1i.yolov8/train/labels/image_1157_jpg.rf.abeb8aa8841382413eec607b3969db15.txt
backend/basketball.v1i.yolov8/train/labels/image_1159_jpg.rf.e2b88a23cdfc1a9f70503e0ce409761c.txt
backend/basketball.v1i.yolov8/train/labels/image_1160_jpg.rf.5773d5ee8e9a8d4df246a51df7b1b44b.txt
backend/basketball.v1i.yolov8/train/labels/image_1162_jpg.rf.9b901073d8d60ba9ba53530b8ae48d33.txt
backend/basketball.v1i.yolov8/train/labels/image_1163_jpg.rf.c26b4f8d1b2d5da3891a9bd1eddba54d.txt
backend/basketball.v1i.yolov8/train/labels/image_1165_jpg.rf.d0b486d8cdc55c2d8f497b43d6670973.txt
backend/basketball.v1i.yolov8/train/labels/image_1166_jpg.rf.1089184488caac449dcb3ec8c58e7c7a.txt
backend/basketball.v1i.yolov8/train/labels/image_1167_jpg.rf.cd7b240c101d68efdf76b2418eb622a4.txt
backend/basketball.v1i.yolov8/train/labels/image_1168_jpg.rf.7b8814361c2cfbf722c51dbe59ab979a.txt
backend/basketball.v1i.yolov8/train/labels/image_1169_jpg.rf.4e7bde6c28f4653a41476986d44a265a.txt
backend/basketball.v1i.yolov8/train/labels/image_1170_jpg.rf.5d42bc1317c98d5b8092a5b9757a9b22.txt
backend/basketball.v1i.yolov8/train/labels/image_1174_jpg.rf.eda78479bb7984e8327a47e0c51706b1.txt
backend/basketball.v1i.yolov8/train/labels/image_1175_jpg.rf.b62a78044e7a3119dde9360e5fc85a93.txt
backend/basketball.v1i.yolov8/train/labels/image_1177_jpg.rf.4c39dfabbbbb450c97e5290c6895ed1d.txt
backend/basketball.v1i.yolov8/train/labels/image_1179_jpg.rf.34353b14529f66503e4623ae4d13c88f.txt
backend/basketball.v1i.yolov8/train/labels/image_1183_jpg.rf.7582a14a1ae7015e217dba2d33e1727c.txt
backend/basketball.v1i.yolov8/train/labels/image_1184_jpg.rf.22a7ab421365875b6733d9753f5b5e64.txt
backend/basketball.v1i.yolov8/train/labels/image_1185_jpg.rf.790f01e70be29313da05a00ba21b055f.txt
backend/basketball.v1i.yolov8/train/labels/image_1186_jpg.rf.05c458cabf581f6bbc36f36b9f3fb983.txt
backend/basketball.v1i.yolov8/train/labels/image_1188_jpg.rf.d560e19e3f54444462ec79b7a25b6d9a.txt
backend/basketball.v1i.yolov8/train/labels/image_1189_jpg.rf.4b66648c4b717b6b32aacfaed0c8ba8a.txt
backend/basketball.v1i.yolov8/train/labels/image_1192_jpg.rf.244a7b735f1d36bcd84c63673ac201a0.txt
backend/basketball.v1i.yolov8/train/labels/image_1194_jpg.rf.1491b7270d90057e04fba7d7caa9a6be.txt
backend/basketball.v1i.yolov8/train/labels/image_1195_jpg.rf.0cbb04bb913a18057fcd7e3ae426576b.txt
backend/basketball.v1i.yolov8/train/labels/image_1196_jpg.rf.04c9eea3457eb6e2d143bec8daef3aa5.txt
backend/basketball.v1i.yolov8/train/labels/image_1198_jpg.rf.502c052edb107e86694f6399e7aa7847.txt
[1879 more files omitted for size]
```

### Dependencies

- backend/pyproject.toml: aiohttp@>=3.12.13, cvzone@>=1.6.1, fastapi[standard]@>=0.115.13, firebase-admin@>=6.9.0, google-generativeai@>=0.8.5, langchain@>=0.3.26, langgraph@>=0.4.8, mediapipe@>=0.10.21, ultralytics@>=8.3.158
- backend/requirements.txt: absl-py@==1.4.0, annotated-types@==0.7.0, antlr4-python3-runtime@==4.9.3, anyio@==4.8.0, appnope@==0.1.3, asttokens@==2.2.1, attrs@==23.1.0, backcall@==0.2.0, cachetools@==5.3.1, certifi, cffi@==1.15.1, charset-normalizer@==3.2.0, click@==8.1.8, contourpy@==1.1.0, cvzone@==1.5.6, cycler@==0.11.0, decorator@==5.1.1, dnspython@==2.7.0, email_validator@==2.2.0, exceptiongroup@==1.2.2, executing@==1.2.0, fastapi@==0.115.8, fastapi-cli@==0.0.7, filelock@==3.12.2, filterpy@==1.4.5, firebase-admin, flatbuffers@==23.5.26, fonttools@==4.41.0, google-auth@==2.22.0, google-auth-oauthlib@==1.0.0, google-generativeai, grpcio@==1.56.2, h11@==0.14.0, httpcore@==1.0.7, httptools@==0.6.4, httpx@==0.28.1, hydra-core@==1.3.2, idna@==3.10, imageio@==2.31.1, ipython@==8.14.0, jedi@==0.18.2, Jinja2@==3.1.5, kiwisolver@==1.4.4, langchain, langchain-core, langchain-openai, langgraph, Markdown@==3.4.3, markdown-it-py@==3.0.0, MarkupSafe@==3.0.2, matplotlib@==3.7.2, matplotlib-inline@==0.1.6, mdurl@==0.1.2, mediapipe@==0.10.20, mpmath@==1.3.0, networkx@==3.1, numpy@>=1.24.0, oauthlib@==3.2.2, omegaconf@==2.3.0, opencv-contrib-python@==4.8.0.74, opencv-python@==4.8.0.74, packaging@==23.1, pandas@==2.0.3, parso@==0.8.3, pexpect@==4.8.0, pickleshare@==0.7.5, Pillow@==10.0.0, prompt-toolkit@==3.0.39, psutil@==5.9.5, ptyprocess@==0.7.0, pure-eval@==0.2.2, py-cpuinfo@==9.0.0, pyasn1@==0.5.0, pyasn1-modules@==0.3.0, pycparser@==2.21, pydantic@==2.10.6, pydantic_core@==2.27.2, Pygments@==2.19.1, pymongo@==4.11.1, pyparsing@==3.0.9, python-dateutil@==2.8.2, python-dotenv@==1.0.1, python-multipart@==0.0.20, pytz@==2023.3, PyWavelets@==1.4.1, PyYAML, requests@==2.31.0, requests-oauthlib@==1.3.1, rich@==13.9.4, rich-toolkit@==0.13.2, rsa@==4.9, scikit-image@==0.19.3, scipy@==1.11.1, seaborn@==0.12.2, sentry-sdk@==1.28.1, shellingham@==1.5.4, six@==1.16.0, sniffio@==1.3.1, sounddevice@==0.4.6, stack-data@==0.6.2, starlette@==0.45.3, sympy@==1.12, tensorboard@==2.13.0, tensorboard-data-server@==0.7.1, thop@==0.1.1.post2209072238, tifffile@==2023.7.18, torch@==2.0.1, torchvision@==0.15.2, tqdm@==4.65.0, traitlets@==5.9.0, typer@==0.15.1, typing_extensions, tzdata@==2023.3, ultralytics@==8.0.145, urllib3@==1.26.16, uvicorn@==0.34.0, uvloop@==0.21.0, watchfiles@==1.0.4, wcwidth@==0.2.6, websockets@==15.0, Werkzeug@==2.3.6
- frontend-abandoned-idea/package.json: @eslint/js@^9.9.1, @reduxjs/toolkit@^2.2.1, @vitejs/plugin-react@^4.3.1, autoprefixer@^10.4.18, esbuild@^0.25.0, eslint@^9.9.1, eslint-plugin-react-hooks@^5.1.0-rc.0, eslint-plugin-react-refresh@^0.4.11, firebase@^10.8.0, globals@^15.9.0, lucide-react@^0.344.0, postcss@^8.4.35, react@^18.3.1, react-dom@^18.3.1, react-redux@^9.1.0, react-router-dom@^6.22.2, tailwindcss@^3.4.1, vite@^5.4.2
- frontend/package.json: @eslint/js@^9.9.1, @tailwindcss/typography@^0.5.16, @types/react@^18.3.5, @types/react-dom@^18.3.0, @vitejs/plugin-react@^4.3.1, autoprefixer@^10.4.18, clsx@^2.1.0, eslint@^9.9.1, eslint-plugin-react-hooks@^5.1.0-rc.0, eslint-plugin-react-refresh@^0.4.11, firebase@^11.3.1, globals@^15.9.0, lucide-react@^0.344.0, postcss@^8.4.35, react@^18.3.1, react-dom@^18.3.1, react-router-dom@^7.2.0, tailwindcss@^3.4.1, typescript@^5.5.3, typescript-eslint@^8.3.0, vite@^5.4.2

### Recent commits (newest first)

- fixes
- frontend ui up
- change
- changes
- push
- backend
- changes
- frontend changes
- Quick analysis agent
- Prompting changes to quick analysis
- prompting changes to quick analysis
- Merge branch 'main' of https://github.com/Khagendra01/Hacklytic-2025
- improvement pro agent
- works
- video reconstruction
- wip
- wip
- frontend changes
- update reqs
- push

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

### backend/pyproject.toml

```
[project]
name = "backend"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
    "aiohttp>=3.12.13",
    "cvzone>=1.6.1",
    "fastapi[standard]>=0.115.13",
    "firebase-admin>=6.9.0",
    "google-generativeai>=0.8.5",
    "langchain>=0.3.26",
    "langgraph>=0.4.8",
    "mediapipe>=0.10.21",
    "ultralytics>=8.3.158",
]

```

### frontend-abandoned-idea/package.json

```
{
  "name": "microbet",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "lint": "eslint .",
    "preview": "vite preview"
  },
  "dependencies": {
    "@reduxjs/toolkit": "^2.2.1",
    "esbuild": "^0.25.0",
    "firebase": "^10.8.0",
    "lucide-react": "^0.344.0",
    "react": "^18.3.1",
    "react-dom": "^18.3.1",
    "react-redux": "^9.1.0",
    "react-router-dom": "^6.22.2"
  },
  "devDependencies": {
    "@eslint/js": "^9.9.1",
    "@vitejs/plugin-react": "^4.3.1",
    "autoprefixer": "^10.4.18",
    "eslint": "^9.9.1",
    "eslint-plugin-react-hooks": "^5.1.0-rc.0",
    "eslint-plugin-react-refresh": "^0.4.11",
    "globals": "^15.9.0",
    "postcss": "^8.4.35",
    "tailwindcss": "^3.4.1",
    "vite": "^5.4.2"
  }
}

```

### frontend/package.json

```
{
  "name": "court-vision-ai",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
    "preview": "vite preview"
  },
  "dependencies": {
    "clsx": "^2.1.0",
    "firebase": "^11.3.1",
    "lucide-react": "^0.344.0",
    "react": "^18.3.1",
    "react-dom": "^18.3.1",
    "react-router-dom": "^7.2.0"
  },
  "devDependencies": {
    "@eslint/js": "^9.9.1",
    "@tailwindcss/typography": "^0.5.16",
    "@types/react": "^18.3.5",
    "@types/react-dom": "^18.3.0",
    "@vitejs/plugin-react": "^4.3.1",
    "autoprefixer": "^10.4.18",
    "eslint": "^9.9.1",
    "eslint-plugin-react-hooks": "^5.1.0-rc.0",
    "eslint-plugin-react-refresh": "^0.4.11",
    "globals": "^15.9.0",
    "postcss": "^8.4.35",
    "tailwindcss": "^3.4.1",
    "typescript": "^5.5.3",
    "typescript-eslint": "^8.3.0",
    "vite": "^5.4.2"
  }
}

```

### backend/requirements.txt

```
annotated-types==0.7.0
anyio==4.8.0
click==8.1.8
dnspython==2.7.0
email_validator==2.2.0
exceptiongroup==1.2.2
fastapi==0.115.8
fastapi-cli==0.0.7
h11==0.14.0
httpcore==1.0.7
httptools==0.6.4
httpx==0.28.1
idna==3.10
Jinja2==3.1.5
markdown-it-py==3.0.0
MarkupSafe==3.0.2
mdurl==0.1.2
pydantic==2.10.6
pydantic_core==2.27.2
Pygments==2.19.1
pymongo==4.11.1
python-dotenv==1.0.1
python-multipart==0.0.20
rich==13.9.4
rich-toolkit==0.13.2
shellingham==1.5.4
sniffio==1.3.1
starlette==0.45.3
typer==0.15.1
typing_extensions
uvicorn==0.34.0
uvloop==0.21.0
watchfiles==1.0.4
websockets==15.0
numpy>=1.24.0
absl-py==1.4.0
antlr4-python3-runtime==4.9.3
appnope==0.1.3
asttokens==2.2.1
attrs==23.1.0
backcall==0.2.0
cachetools==5.3.1
certifi
cffi==1.15.1
charset-normalizer==3.2.0
contourpy==1.1.0
cvzone==1.5.6
cycler==0.11.0
decorator==5.1.1
executing==1.2.0
filelock==3.12.2
filterpy==1.4.5
flatbuffers==23.5.26
fonttools==4.41.0
google-auth==2.22.0
google-auth-oauthlib==1.0.0
grpcio==1.56.2
hydra-core==1.3.2
imageio==2.31.1
ipython==8.14.0
jedi==0.18.2
kiwisolver==1.4.4
# lap==0.4.0  # temporarily commented out
Markdown==3.4.3
matplotlib==3.7.2
matplotlib-inline==0.1.6
mediapipe==0.10.20
mpmath==1.3.0
networkx==3.1
oauthlib==3.2.2
omegaconf==2.3.0
opencv-contrib-python==4.8.0.74
opencv-python==4.8.0.74
packaging==23.1
pandas==2.0.3
parso==0.8.3
pexpect==4.8.0
pickleshare==0.7.5
Pillow==10.0.0
prompt-toolkit==3.0.39
# protobuf==3.20.3
psutil==5.9.5
ptyprocess==0.7.0
pure-eval==0.2.2
py-cpuinfo==9.0.0
pyasn1==0.5.0
pyasn1-modules==0.3.0
pycparser==2.21
pyparsing==3.0.9
python-dateutil==2.8.2
pytz==2023.3
PyWavelets==1.4.1
PyYAML
requests==2.31.0
requests-oauthlib==1.3.1
rsa==4.9
scikit-image==0.19.3
scipy==1.11.1
seaborn==0.12.2
sentry-sdk==1.28.1
six==1.16.0
sounddevice==0.4.6
stack-data==0.6.2
sympy==1.12
tensorboard==2.13.0
tensorboard-data-server==0.7.1
thop==0.1.1.post2209072238
tifffile==2023.7.18
torch==2.0.1
torchvision==0.15.2
tqdm==4.65.0
traitlets==5.9.0
tzdata==2023.3
ultralytics==8.0.145
urllib3==1.26.16
wcwidth==0.2.6
Werkzeug==2.3.6
firebase-admin
langchain
langchain-core
langchain-openai
google-generativeai
langgraph

```

### backend/main.py

```python
from typing import Union
from agents.quick_analysis_agent import get_quick_analysis
from shot_detector import ShotDetector
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
import aiohttp
import os
import uuid
from preprocessing.noise_masking import NoiseReducer, MaskingConfig
from firebase.firebase_storage import FirebaseStorageManager
import asyncio
from pydantic import BaseModel

app = FastAPI()

# Initialize Firebase Storage Manager
firebase_manager = FirebaseStorageManager(
    bucket_name='hacklytic2025.firebasestorage.app'
)

# Initialize NoiseReducer
noise_reducer = NoiseReducer(MaskingConfig())

# Configure CORS
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"], 
    allow_credentials=True,
    allow_methods=["*"], 
    allow_headers=["*"], 
)

# Add this class before the endpoint
class VideoRequest(BaseModel):
    video_url: str

# Add this class for talent scout endpoint
class VideoComparisonRequest(BaseModel):
    video1_url: str
    video2_url: str

@app.get("/")
def read_root():
    return {"Hello": "World"}


@app.get("/items/{item_id}")
async def read_item(item_id: int, q: Union[str, None] = None):
    return {"item_id": item_id, "q": q}

@app.post("/api/mask_video")
async def mask_video(request: VideoRequest):
    try:
        # Create temporary directory if it doesn't exist
        temp_dir = "temp_videos"
        os.makedirs(temp_dir, exist_ok=True)
        print(f"Created/verified temp directory at: {os.path.abspath(temp_dir)}")
        
        video_url = request.video_url
        
        # Generate unique filenames
        input_video_path = os.path.join(temp_dir, f"input_{uuid.uuid4()}.mp4")
        print(f"Will save video to: {os.path.abspath(input_video_path)}")
        
        # Download the video
        async with aiohttp.ClientSession() as session:
            async with session.get(video_url) as response:
                if response.status != 200:
                    raise HTTPException(status_code=400, detail="Failed to download video")
                
                content = await response.read()
                print(f"Downloaded video content size: {len(content)} bytes")
                
                with open(input_video_path, 'wb') as f:
                    f.write(content)
                
                print(f"Video saved. File exists: {os.path.exists(input_video_path)}")
                print(f"File size: {os.path.getsize(input_video_path)} bytes")

        print(f"Input video path: {input_video_path}")
        
        # Process the video

        video_id = uuid.uuid4()
        unmasked_video_path = os.path.join(temp_dir, f"masked_{video_id}.mp4")
        await noise_reducer.process_video(input_video_path, unmasked_video_path)

        print(f"Output video path: {unmasked_video_path}")
        
        # Upload masked video to Firebase
        try:
            firebase_unmasked_path = f"masked_videos/{os.path.basename(unmasked_video_path)}"
            firebase_unmasked_url = firebase_manager.upload_file(unmasked_video_path, firebase_unmasked_path)
        except Exception as e:
            raise HTTPException(status_code=500, detail=f"Failed to upload masked video: {str(e)}")
        
        print(f"Masked video uploaded to Firebase: {firebase_unmasked_url}")

        # Process with shot detector
        try:
            output_file_dir = os.path.join(temp_dir, f"processed_{video_id}.mp4")
            detector = ShotDetector(unmasked_video_path=unmasked_video_path, output_file_dir=output_file_dir)
            shot_metrics = detector.shot_metrics

            # Upload processed video
            firebase_processed_path = f"processed_videos/{os.path.basename(output_file_dir)}"
            firebase_processed_url = firebase_manager.upload_file(output_file_dir, firebase_processed_path)
        except Exception as e:
            raise HTTPException(status_code=500, detail=f"Failed to process or upload analyzed video: {str(e)}")
        
        analysis = get_quick_analysis(metrics_data=shot_metrics, video_url=output_file_dir)
        
        return {
            "masked_video_url": firebase_unmasked_url,
            "processed_video_url": firebase_processed_url,
            "shot_metrics": shot_metrics,
            "analysis": analysis
        }
        
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))
        
    finally:
        # Clean up temporary files
        for path in [input_video_path, unmasked_video_path, output_file_dir]:
            if path and os.path.exists(path):
                try:
                    os.remove(path)
                except Exception as e:
                    print(f"Failed to remove temporary file {path}: {e}")

@app.get("/test_firebase")
async def test_firebase():
    try:
        test_file = "output_video.mp4"
        if not os.path.exists(test_file):
            raise HTTPException(status_code=404, detail="Test file not found")
            
        # Try uploading to Firebase
        firebase_path = f"test_uploads/{os.path.basename(test_file)}"
        public_url = firebase_manager.upload_file(test_file, firebase_path)
        
        return {
            "status": "success",
            "message": "Test file uploaded successfully",
            "url": public_url
        }
        
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Firebase test failed: {str(e)}")

@app.post("/api/talent_scout")
async def analyze_talent(request: VideoComparisonRequest):
    try:
        # Create temporary directory if it doesn't exist
        temp_dir = "temp_videos"
        os.makedirs(temp_dir, exist_ok=True)
        
        # Generate unique filenames for both videos
        video1_path = os.path.join(temp_dir, f"video1_{uuid.uuid4()}.mp4")
        video2_path = os.path.join(temp_dir, f"video2_{uuid.uuid4()}.mp4")
        
        # Download both videos
        async with aiohttp.ClientSes
[truncated — 2985 more characters]
```

### frontend-abandoned-idea/src/main.jsx

```javascript
import { createRoot } from 'react-dom/client';
import App from './App';
import './index.css';

createRoot(document.getElementById('root')).render(<App />);
```

### frontend/src/main.tsx

```typescript
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import App from './App.tsx';
import './index.css';

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <App />
  </StrictMode>
);

```

### frontend-abandoned-idea/src/App.jsx

```javascript
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
import { Provider } from 'react-redux';
import { store } from './store';
import Layout from './components/Layout';
import Home from './pages/Home';
import Login from './pages/Login';
import Register from './pages/Register';
import Dashboard from './pages/Dashboard';
import Profile from './pages/Profile';

// Protected Route component
const ProtectedRoute = ({ children }) => {
  const isAuthenticated = store.getState().auth.isAuthenticated;
  return isAuthenticated ? children : <Navigate to="/login" />;
};

function App() {
  return (
    <Provider store={store}>
      <Router>
        <Routes>
          <Route path="/" element={<Layout />}>
            <Route index element={<Home />} />
            <Route path="login" element={<Login />} />
            <Route path="register" element={<Register />} />
            <Route
              path="dashboard"
              element={
                <ProtectedRoute>
                  <Dashboard />
                </ProtectedRoute>
              }
            />
            <Route
              path="profile"
              element={
                <ProtectedRoute>
                  <Profile />
                </ProtectedRoute>
              }
            />
          </Route>
        </Routes>
      </Router>
    </Provider>
  );
}

export default App;
```

### frontend/src/App.tsx

```typescript
import React, { useState } from 'react';
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';
import { Activity } from 'lucide-react';
import { VideoUploader } from './components/VideoUploader';
import { VideoPlayer } from './components/VideoPlayer';
import { uploadVideo } from './api';
import { VideoAnalysis } from './types';
import { ProPage } from './pages/ProPage';

function App() {
  const [isUploading, setIsUploading] = useState(false);
  const [analysis, setAnalysis] = useState<VideoAnalysis | null>(null);
  const [error, setError] = useState<string | null>(null);

  const handleUpload = async (file: File) => {
    try {
      setError(null);
      setIsUploading(true);
      const result = await uploadVideo(file);
      setAnalysis(result);
      
      // Poll for updates
      const interval = setInterval(() => {
        if (result.status === 'completed') {
          setAnalysis({ ...result });
          clearInterval(interval);
        }
      }, 1000);
      
    } catch (err) {
      setError('Failed to upload video. Please try again.');
      console.error('Upload failed:', err);
    } finally {
      setIsUploading(false);
    }
  };

  return (
    <BrowserRouter>
      <div className="min-h-screen bg-gradient-to-b from-blue-50 to-white">
        {/* Header */}
        <header className="bg-white/80 backdrop-blur-sm border-b sticky top-0 z-10">
          <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
            <div className="flex items-center justify-between">
              <Link to="/" className="flex items-center gap-3">
                <Activity className="w-8 h-8 text-blue-600" />
                <h1 className="text-2xl font-bold bg-gradient-to-r from-blue-600 to-blue-800 text-transparent bg-clip-text">
                  Scout It
                </h1>
              </Link>
              <div className="flex items-center gap-4">
                {error && (
                  <div className="text-red-500 text-sm flex items-center gap-2">
                    <span className="w-2 h-2 bg-red-500 rounded-full animate-pulse"></span>
                    {error}
                  </div>
                )}
                <Link
                  to="/pro"
                  className="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors"
                >
                  Pro
                </Link>
              </div>
            </div>
          </div>
        </header>

        {/* Main Content */}
        <Routes>
          <Route path="/" element={<HomePage analysis={analysis} isUploading={isUploading} handleUpload={handleUpload} />} />
          <Route path="/pro" element={<ProPage />} />
        </Routes>

        {/* Footer */}
        <footer className="bg-white/80 backdrop-blur-sm border-t mt-auto">
          <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
            <p className="text-center text-gray-500">
              © 2025 Scout It. All rights reserved.
            </p>
          </div>
        </footer>
      </div>
    </BrowserRouter>
  );
}

// HomePage Component
function HomePage({ analysis, isUploading, handleUpload }) {
  return (
    <main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
      <div className="max-w-4xl mx-auto space-y-8">
        <div className="text-center space-y-4">
          <h2 className="text-4xl font-bold text-gray-900 sm:text-5xl">
            Basketball Video Analysis
          </h2>
          <p className="text-xl text-gray-600 max-w-2xl mx-auto">
            Upload your basketball footage and let our AI analyze player movements,
            shot accuracy, and game patterns in real-time.
          </p>
        </div>

        <div className="bg-white rounded-2xl shadow-xl p-8 border">
          {!analysis ? (
            <VideoUploader onUpload={handleUpload} isUploading={isUploading} />
          ) : (
            <VideoPlayer analysis={analysis} />
          )}
        </div>
      </div>
    </main>
  );
}

export default App;
```

### frontend-abandoned-idea/src/store/index.js

```javascript
import { configureStore } from '@reduxjs/toolkit';
import authReducer from './slices/authSlice';
import themeReducer from './slices/themeSlice';
import betsReducer from './slices/betsSlice';

export const store = configureStore({
  reducer: {
    auth: authReducer,
    theme: themeReducer,
    bets: betsReducer,
  },
});
```

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