# Project export: MafiAI

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: Mafia with LLMs!
- Devpost: https://devpost.com/software/mafiai
- GitHub: https://github.com/KevinL10/mafia
- Video: https://www.youtube.com/embed/gwkJod92X90?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Result: winner (Cal Hacks: Hack on AI)
- Team: 1 GitHub contributor(s) — Kevin Liu (13 commits)

## Devpost submission (written by the team)

No Devpost description available.

## README (from the GitHub repository)

# mafia

## Detected evidence (automated analysis)

Indexed codebase: 22 recognized source files, 30 KB.
- CSS (language) — 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
- TypeScript (language) — detected in the code

## Codebase structure (from repository index)

### Files (30 of 30)

```
backend/.gitignore
backend/ai.py
backend/app.py
backend/game.py
backend/tts.py
frontend/.gitignore
frontend/eslint.config.js
frontend/index.html
frontend/package.json
frontend/postcss.config.js
frontend/README.md
frontend/src/App.css
frontend/src/App.tsx
frontend/src/components/chat.tsx
frontend/src/components/playerCard.tsx
frontend/src/components/playerView.tsx
frontend/src/index.css
frontend/src/main.tsx
frontend/src/pages/Game.tsx
frontend/src/pages/Home.tsx
frontend/src/SocketContext.tsx
frontend/src/vite-env.d.ts
frontend/tailwind.config.js
frontend/tsconfig.app.json
frontend/tsconfig.app.tsbuildinfo
frontend/tsconfig.json
frontend/tsconfig.node.json
frontend/tsconfig.node.tsbuildinfo
frontend/vite.config.ts
README.md
```

### Dependencies

- frontend/package.json: @eslint/js@^9.11.1, @types/react@^18.3.11, @types/react-dom@^18.3.0, @vitejs/plugin-react@^4.3.2, autoprefixer@^10.4.20, eslint@^9.11.1, eslint-plugin-react-hooks@^5.1.0-rc.0, eslint-plugin-react-refresh@^0.4.12, globals@^15.9.0, postcss@^8.4.47, react@^18.3.1, react-dom@^18.3.1, react-router-dom@^6.27.0, rpgui@^1.0.3, socket.io-client@^4.8.0, tailwindcss@^3.4.14, typescript@^5.5.3, typescript-eslint@^8.7.0, vite@^5.4.8

### Recent commits (newest first)

- the rest
- .
- demo1
- feat: mvp2
- feat: mvp1
- feat: player frontend view
- feat: show players list at start
- feat: chatbox frontend
- feat: tts
- feat: clean up llm logic
- feat: player names and bug fixes
- feat: mafia backend
- feat: initial frontend for game
- feat: ws
- Initial commit

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

### frontend/package.json

```
{
  "name": "frontend2",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "tsc -b && vite build",
    "lint": "eslint .",
    "preview": "vite preview"
  },
  "dependencies": {
    "react": "^18.3.1",
    "react-dom": "^18.3.1",
    "react-router-dom": "^6.27.0",
    "rpgui": "^1.0.3",
    "socket.io-client": "^4.8.0"
  },
  "devDependencies": {
    "@eslint/js": "^9.11.1",
    "@types/react": "^18.3.11",
    "@types/react-dom": "^18.3.0",
    "@vitejs/plugin-react": "^4.3.2",
    "autoprefixer": "^10.4.20",
    "eslint": "^9.11.1",
    "eslint-plugin-react-hooks": "^5.1.0-rc.0",
    "eslint-plugin-react-refresh": "^0.4.12",
    "globals": "^15.9.0",
    "postcss": "^8.4.47",
    "tailwindcss": "^3.4.14",
    "typescript": "^5.5.3",
    "typescript-eslint": "^8.7.0",
    "vite": "^5.4.8"
  }
}

```

### backend/app.py

```python
from dotenv import load_dotenv
load_dotenv()

from flask import Flask, render_template, request, jsonify
from flask_socketio import SocketIO, emit, join_room, leave_room
from game import Game
import time


app = Flask(__name__)
app.config['SECRET_KEY'] = '.'
socketio = SocketIO(app, cors_allowed_origins="*")

game = None

@app.route('/')
def index():
    return jsonify({"status": "ok"})

@socketio.on('connect')
def handle_connect():
    print('Client connected:', request.sid)
    emit('message', {'msg': 'Connected to the server'})

@socketio.on('disconnect')
def handle_disconnect():
    print('Client disconnected:', request.sid)

@socketio.on("ping")
def ping(data):
    print('pinged')
    emit('pong', {'msg': 'pong'})

@socketio.on("chat")
def chat(data):
    game.chat(data)


@socketio.on("start")
def start():
    global game
    game = Game("Kevin")

    print('starting')
    # emit('init', [p.serialize() for p in game.players])
    # socketio.sleep(1)


@socketio.on("startNight")
def start_night(detective_guess):
    assert game

    night = game.run_night(detective_guess)

    emit("newRound", {
        "round": game.day,
        "summary": night.summary,
        "players": [p.serialize() for p in night.players],
        "gameWon": game.is_game_won()
    })

    game.run_day(socketio)


if __name__ == '__main__':
    socketio.run(app, debug=True)


```

### frontend/src/main.tsx

```typescript
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import "./index.css";
import { SocketProvider } from "./SocketContext.tsx";
import { Home } from "./pages/Home.tsx";
import Game from "./pages/Game.tsx";
import { createBrowserRouter, RouterProvider } from "react-router-dom";

const router = createBrowserRouter([
  {
    path: "/",
    element: <Home />,
  },
  {
    path: "/game",
    element: <Game />,
  },
]);

createRoot(document.getElementById("root")!).render(
    <SocketProvider>
      <RouterProvider router={router} />
    </SocketProvider>
);

```

### frontend/src/App.tsx

```typescript
import { useState } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'

function App() {
  const [count, setCount] = useState(0)

  return (
    <>
      <div>
        <a href="https://vitejs.dev" target="_blank">
          <img src={viteLogo} className="logo" alt="Vite logo" />
        </a>
        <a href="https://react.dev" target="_blank">
          <img src={reactLogo} className="logo react" alt="React logo" />
        </a>
      </div>
      <h1>MafiAI</h1>
      <div className="card">
        <button onClick={() => setCount((count) => count + 1)}>
          count is {count}
        </button>
        <p>
          Edit <code>src/App.tsx</code> and save to test HMR
        </p>
      </div>
      <p className="read-the-docs">
        Click on the Vite and React logos to learn more
      </p>
    </>
  )
}

export default App

```

### frontend/postcss.config.js

```javascript
export default {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
}

```

### frontend/vite.config.ts

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

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

```

### frontend/tailwind.config.js

```javascript
/** @type {import('tailwindcss').Config} */
export default {
  content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}


```

### backend/ai.py

```python
import os

from groq import Groq
import time


class GroqClient:
    def __init__(self):
        self.client = Groq(
            api_key=os.environ.get("GROQ_API_KEY"),
        )
        self.last_duration = None

    def complete(self, msg: str) -> str:
        start = time.time()
        chat_completion = self.client.chat.completions.create(
            messages=[
                {
                    "role": "user",
                    "content": msg,
                }
            ],
            model="llama-3.1-8b-instant",
        )

        self.last_duration = time.time() - start
        return chat_completion.choices[0].message.content

```

### frontend/eslint.config.js

```javascript
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from 'typescript-eslint'

export default tseslint.config(
  { ignores: ['dist'] },
  {
    extends: [js.configs.recommended, ...tseslint.configs.recommended],
    files: ['**/*.{ts,tsx}'],
    languageOptions: {
      ecmaVersion: 2020,
      globals: globals.browser,
    },
    plugins: {
      'react-hooks': reactHooks,
      'react-refresh': reactRefresh,
    },
    rules: {
      ...reactHooks.configs.recommended.rules,
      'react-refresh/only-export-components': [
        'warn',
        { allowConstantExport: true },
      ],
    },
  },
)

```

### frontend/index.html

```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>MafiAI</title>

    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Pixelify+Sans:wght@400;500;600;700&display=swap" rel="stylesheet">

    <!-- <link href="https://cdn.jsdelivr.net/npm/rpgui@1.0.3/dist/rpgui.min.css" rel="stylesheet"> -->
     <script src="https://ronenness.github.io/RPGUI/rpgui/rpgui.min.js"></script>
     <link href="https://ronenness.github.io/RPGUI/rpgui/rpgui.css" rel="stylesheet">
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
    <div class="text-green-300 text-blue-300 text-red-300 text-yellow-300 text-purple-300 text-gray-300 text-orange-300"></div>
  </body>
</html>

```

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