# Project export: Fridge

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 12.0
- Tagline: Stay cool and join a community of poets! A playful platform to arrange magnetic words on your own virtual fridge - find words that stick and poems that click!
- Devpost: https://devpost.com/software/fridge-wi3pos
- GitHub: https://github.com/m3v113/poetry-game
- Video: https://www.youtube.com/embed/XuW4OF-9XS8?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 2 GitHub contributor(s) — Mehvish-B (9 commits), m3v113 (1 commits)

## Devpost submission (written by the team)

### Inspiration

Poetry Magnets! Walking by a fridge, rearranging some word magnets, and having a poem to share!

### What it does

Poetry Game! A user will be given an assortment of fridge magnets, with each magnet containing a word. Using each "word magnet", the user will create their own unique poem using those magnets. Users are able to share their own poem with other users, engage (like) other user's poems, decorate their own fridge with stickers depending on the amount of likes they receive, and have AI text-to-speech read the poem.

### How we built it

Claude was used for AI analysis, Fish Audio API was used for text-to-speech to bring poems into life! Firebase was used as a login authenticator & a database of words in which the fridge magnets will be initialised. React was connected with Firebase for user authentication & ScapY was used for word categorization (to ensure proper distribution of words)

### Challenges we ran into

Using an appropriate database (Firebase API) which manages & categorizes the words properly Implementing Fish Audio AI and Claude AI into implementing Text-To-Speech and AI analysis of poems

### Accomplishments we're proud of

We're proud of creating a project as beginner programmers in which we are able to interact with other users

### What we learned

APIS + AI + Databases

### What's next

Better UI + More features!

## README (from the GitHub repository)

No README available.

## Detected evidence (automated analysis)

Indexed codebase: 31 recognized source files, 66 KB.
- Anthropic (technology) — 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
- Python (language) — detected in the code
- React (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code

## Codebase structure (from repository index)

### Files (42 of 42)

```
.DS_Store
.gitignore
backend/.env.example
backend/app/__init__.py
backend/app/core/__init__.py
backend/app/core/config.py
backend/app/models/__init__.py
backend/app/models/schemas.py
backend/app/routes/__init__.py
backend/app/routes/analysis.py
backend/app/routes/audio.py
backend/app/routes/diagnostics.py
backend/app/routes/tts.py
backend/app/services/__init__.py
backend/app/services/analysis_service.py
backend/app/services/diagnostics_service.py
backend/app/services/tts_service.py
backend/main.py
backend/README.md
backend/requirements.txt
database_stuff/categorize_and_upload.py
database_stuff/words.txt
frontend/.DS_Store
frontend/my-app/.gitignore
frontend/my-app/eslint.config.js
frontend/my-app/index.html
frontend/my-app/package.json
frontend/my-app/postcss.config.cjs
frontend/my-app/README.md
frontend/my-app/src/App.css
frontend/my-app/src/App.jsx
frontend/my-app/src/components/Feed.jsx
frontend/my-app/src/components/Fridge.css
frontend/my-app/src/components/FridgeMagnetPoetry.jsx
frontend/my-app/src/components/Login.jsx
frontend/my-app/src/components/TitleScreen.jsx
frontend/my-app/src/firebase.js
frontend/my-app/src/index.css
frontend/my-app/src/main.jsx
frontend/my-app/tailwind.config.cjs
frontend/my-app/vite.config.js
frontend/package.json
```

### Dependencies

- backend/requirements.txt: anthropic@==0.39.0, fastapi@==0.115.5, httpx@==0.27.2, pydantic@==2.10.3, python-dotenv@==1.0.0, python-multipart@==0.0.20, uvicorn@==0.32.1
- frontend/my-app/package.json: @eslint/js@^9.36.0, @tailwindcss/postcss@^4.1.16, @tailwindcss/vite@^4.1.16, @types/react@^19.1.16, @types/react-dom@^19.1.9, @vitejs/plugin-react@^5.0.4, autoprefixer@^10.4.21, eslint@^9.36.0, eslint-plugin-react-hooks@^5.2.0, eslint-plugin-react-refresh@^0.4.22, firebase@^12.4.0, framer-motion@^12.23.24, globals@^16.4.0, html2canvas@^1.4.1, lucide-react@^0.548.0, postcss@^8.5.6, react@^19.1.1, react-dom@^19.1.1, tailwind@^4.0.0, tailwindcss@^4.1.16, vite@^7.1.12
- frontend/package.json: firebase@^12.4.0

### Recent commits (newest first)

- update tts
- im so done
- env files
- api please
- lowkey idk
- api is secret :
- backend is structured, AI analysis,
- Merge branch 'main' of https://github.com/m3v113/poetry-game
- feed
- changed past poems name to gallery
- changed word ratio again
- fixed word ratio
- stylings, fixed word ratio, title screen
- made history for poems
- pastpoems
- word count fixed, random word fixed
- Merge branch 'main' of https://github.com/m3v113/poetry-game
- deleted
- proper commit
- random words

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

### frontend/package.json

```
{
  "dependencies": {
    "firebase": "^12.4.0"
  }
}

```

### backend/requirements.txt

```
fastapi==0.115.5
uvicorn==0.32.1
httpx==0.27.2
anthropic==0.39.0
pydantic==2.10.3
python-multipart==0.0.20
python-dotenv==1.0.0

```

### frontend/my-app/package.json

```
{
  "name": "my-app",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "lint": "eslint .",
    "preview": "vite preview"
  },
  "dependencies": {
    "@tailwindcss/vite": "^4.1.16",
    "firebase": "^12.4.0",
    "framer-motion": "^12.23.24",
    "html2canvas": "^1.4.1",
    "lucide-react": "^0.548.0",
    "react": "^19.1.1",
    "react-dom": "^19.1.1",
    "tailwind": "^4.0.0"
  },
  "devDependencies": {
    "@eslint/js": "^9.36.0",
    "@tailwindcss/postcss": "^4.1.16",
    "@types/react": "^19.1.16",
    "@types/react-dom": "^19.1.9",
    "@vitejs/plugin-react": "^5.0.4",
    "autoprefixer": "^10.4.21",
    "eslint": "^9.36.0",
    "eslint-plugin-react-hooks": "^5.2.0",
    "eslint-plugin-react-refresh": "^0.4.22",
    "globals": "^16.4.0",
    "postcss": "^8.5.6",
    "tailwindcss": "^4.1.16",
    "vite": "^7.1.12"
  }
}

```

### backend/main.py

```python
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from app.routes import tts, analysis, audio, diagnostics
from app.core.config import settings

app = FastAPI(title="Poetry TTS API")

# CORS middleware
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*","http://localhost:5174/"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Include routers
app.include_router(tts.router, prefix="/api", tags=["TTS"])
app.include_router(analysis.router, prefix="/api", tags=["Analysis"])
app.include_router(audio.router, tags=["Audio"])
app.include_router(diagnostics.router, prefix="/api/debug", tags=["Diagnostics"])

@app.get("/")
async def root():
    return {"message": "Poetry TTS API is running!"}

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

```

### frontend/my-app/src/main.jsx

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

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

```

### frontend/my-app/src/App.jsx

```javascript
import { useEffect, useState } from 'react';
import { onAuthStateChanged, signOut } from 'firebase/auth';
import { auth } from './firebase';
import './App.css';
import Login from './components/Login.jsx';
import FridgeMagnetPoetry from './components/FridgeMagnetPoetry.jsx';
import TitleScreen from './components/TitleScreen.jsx';

function App() {
  const [user, setUser] = useState(null);
  const [showTitle, setShowTitle] = useState(true);

  useEffect(() => {
    const unsubscribe = onAuthStateChanged(auth, (currentUser) => {
      setUser(currentUser);
    });
    return () => unsubscribe();
  }, []);

  // ✅ Show title screen first
  if (showTitle) {
    return <TitleScreen onStart={() => setShowTitle(false)} />;
  }

  // ✅ After title, show login if not logged in
  if (!user) {
    return <Login onLogin={() => setShowTitle(false)} />;
  }

  // ✅ If logged in, show the game
  return (
    <div className="App flex flex-col items-center gap-4 mt-6">
      <h1 className="text-xl font-bold">Welcome, {user.email.split('@')[0]}.</h1>
      <button
        onClick={() => signOut(auth)}
        className="bg-red-500 text-white px-4 py-2 rounded hover:bg-red-600"
      >
        Logout
      </button>
      <FridgeMagnetPoetry user={user} />
    </div>
  );
}

export default App;

```

### database_stuff/categorize_and_upload.py

```python
import spacy
import firebase_admin
from firebase_admin import credentials, firestore

# ====== FIREBASE SETUP ======
cred = credentials.Certificate("./database_stuff/poetry-game-3c18d-firebase-adminsdk-fbsvc-f4bbff85b5.json")  # path to your Firebase key
firebase_admin.initialize_app(cred)
db = firestore.client()

# ====== SPACY SETUP ======
nlp = spacy.load("en_core_web_sm")

# ====== FILE SETUP ======
INPUT_FILE = "./database_stuff/words.txt"

# ====== READ WORDS ======
with open(INPUT_FILE, "r", encoding="utf-8") as f:
    words = [line.strip() for line in f if line.strip()]

# ====== CATEGORIZE ======
nouns, verbs, adjectives, conjunctionsAndArticles = [], [], [], []

for doc in nlp.pipe(words, batch_size=1000):
    token = doc[0]
    if token.pos_ == "NOUN":
        nouns.append(token.text)
    elif token.pos_ == "VERB":
        verbs.append(token.text)
    #elif token.pos_ == "ADJ":
    #    adjectives.append(token.text)
    #elif token.pos == "CCONJ" or token.pos_ == "SSCONJ" or token.pos_ == "DET":
    #    conjunctionsAndArticles.append(token.text)

print(f"Categorized ✅  Nouns: {len(nouns)}, Verbs: {len(verbs)}, Adjectives: {len(adjectives)}")
#, Conjunctions & Articles: {len(conjunctionsAndArticles)}

# ====== UPLOAD TO FIRESTORE ======
data = {
    "nouns": nouns,
    "verbs": verbs,
    "adjectives": adjectives,
    "conjunctionsAndArticles": ["the", "and", "is", "in", "on", "at", "with", "a", "an", "to"]
}
db.collection("wordCategories").document("categorizedWords").set(data)

print("✅ Uploaded categorized words to Firebase Firestore!")

# import spacy
# import firebase_admin
# from firebase_admin import credentials, firestore

# # ====== FIREBASE SETUP ======
# cred = credentials.Certificate("/poetry-game/database_stuff/poetry-game-3c18d-firebase-adminsdk-fbsvc-f4bbff85b5.json")
# firebase_admin.initialize_app(cred)
# db = firestore.client()

# # ====== SPACY SETUP ======
# nlp = spacy.load("en_core_web_sm")

# # ====== FILE SETUP ======
# INPUT_FILE = "/poetry-game/database_stuff/words.txt"

# # ====== READ WORDS ======
# with open(INPUT_FILE, "r", encoding="utf-8") as f:
#     words = [line.strip() for line in f if line.strip()]

# # ====== CATEGORIZE ======
# nouns, verbs, adjectives = [], [], []

# # Use nlp.pipe for speed
# for doc in nlp.pipe(words, batch_size=1000):
#     # Some lines may contain multiple tokens; categorize each token
#     for token in doc:
#         if token.pos_ == "NOUN":
#             nouns.append(token.text)
#         elif token.pos_ == "VERB":
#             verbs.append(token.text)
#         elif token.pos_ == "ADJ":
#             adjectives.append(token.text)

# print(f"Categorized ✅  Nouns: {len(nouns)}, Verbs: {len(verbs)}, Adjectives: {len(adjectives)}")

# # ====== UPLOAD TO FIRESTORE ======
# # Split into chunks of 1000 to avoid large array issues
# def chunk_list(lst, size=1000):
#     return [lst[i:i + size] for i in range(0, len(lst), size)]

# data = {}
# for i, chunk in enumerate(chunk_list(nouns)):
#     data[f"nouns_{i}"] = chunk
# for i, chunk in enumerate(chunk_list(verbs)):
#     data[f"verbs_{i}"] = chunk
# for i, chunk in enumerate(chunk_list(adjectives)):
#     data[f"adjectives_{i}"] = chunk

# db.collection("wordCategories").document("categorizedWords").set(data)

# print("✅ Uploaded all categorized words to Firebase Firestore!")

```

### backend/app/__init__.py

```python
# App module initialization

```

### frontend/my-app/vite.config.js

```javascript
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

// https://vite.dev/config/
export default defineConfig({
  plugins: [react()],
})

```

### frontend/my-app/index.html

```html
<!doctype html>
<html lang="en">
  <head>
    <script src="https://cdn.tailwindcss.com"></script>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/png" href="/fridge-logo.png" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Fridge</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.jsx"></script>
    <script src="https://cdn.tailwindcss.com"></script>
  </body>
</html>

```

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