Skip to content

hadrienblanc/hmeet

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

152 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

HMeet

Application de visioconference avec transcription en temps reel, generation de resume et extraction de TODOs.

Stack

  • Rails 8 - Backend + frontend
  • LiveKit - SFU WebRTC (video/audio)
  • OpenAI Whisper - Transcription audio
  • OpenAI GPT - Resume + TODOs automatiques
  • Solid Queue - Jobs asynchrones
  • Tailwind CSS - UI

Fonctionnalites

  • Visioconference multi-participants
  • Partage d'ecran
  • Chat en temps reel
  • Enregistrement audio
  • Transcription live (Web Speech API)
  • Transcription Whisper (post-meeting)
  • Resume IA + extraction de TODOs
  • Indicateur visuel de qui parle

Developpement local

Prerequis

  • Ruby 3.3+
  • Node.js 18+
  • LiveKit server (local ou cloud)

Installation

bundle install
bin/rails db:setup

Configuration

# config/credentials.yml.enc (via bin/rails credentials:edit)
openai:
  api_key: <YOUR_OPENAI_API_KEY>

livekit:
  api_key: <YOUR_LIVEKIT_API_KEY>
  api_secret: <YOUR_LIVEKIT_API_SECRET>
  url: ws://localhost:7880
  host: http://localhost:7880

Lancer LiveKit local (Docker)

docker run --rm \
  -p 7880:7880 \
  -p 7881:7881/udp \
  -p 7882:7882/udp \
  -e LIVEKIT_KEYS="<YOUR_API_KEY>: <YOUR_API_SECRET>" \
  livekit/livekit-server

Demarrer l'app

bin/dev

Tests

bin/rails test

Deploiement production (Docker Compose)

Architecture

┌─────────────────────────────────────────────────────────┐
│                     Serveur dedie                        │
│                                                          │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐    │
│  │  Rails  │  │ Worker  │  │ LiveKit │  │ Egress  │    │
│  │  :3000  │  │ (jobs)  │  │  :7880  │  │         │    │
│  └────┬────┘  └────┬────┘  └────┬────┘  └────┬────┘    │
│       │            │            │            │          │
│       └────────────┴─────┬──────┴────────────┘          │
│                          │                              │
│  ┌─────────┐  ┌─────────┐│ ┌────────────────────────┐  │
│  │ Postgres│  │  Redis  ││ │  Volume: /recordings   │  │
│  │  :5432  │  │  :6379  ││ │  (partage egress/rails)│  │
│  └─────────┘  └─────────┘│ └────────────────────────┘  │
│                          │                              │
└──────────────────────────┼──────────────────────────────┘
                           │
              ┌────────────┴────────────┐
              │         Nginx           │
              │   (reverse proxy SSL)   │
              └─────────────────────────┘
                           │
                       Internet

Fichiers de configuration

docker-compose.yml

services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - RAILS_ENV=production
      - DATABASE_URL=postgres://postgres:${POSTGRES_PASSWORD}@db:5432/hmeet
      - REDIS_URL=redis://redis:6379
      - LIVEKIT_URL=wss://livekit.example.com
      - LIVEKIT_HOST=http://livekit:7880
      - LIVEKIT_API_KEY=${LIVEKIT_API_KEY}
      - LIVEKIT_API_SECRET=${LIVEKIT_API_SECRET}
      - SECRET_KEY_BASE=${SECRET_KEY_BASE}
      - OPENAI_API_KEY=${OPENAI_API_KEY}
    volumes:
      - recordings:/app/storage/recordings
    depends_on:
      - db
      - redis
      - livekit

  worker:
    build: .
    command: bin/jobs
    environment:
      - RAILS_ENV=production
      - DATABASE_URL=postgres://postgres:${POSTGRES_PASSWORD}@db:5432/hmeet
      - REDIS_URL=redis://redis:6379
      - OPENAI_API_KEY=${OPENAI_API_KEY}
    volumes:
      - recordings:/app/storage/recordings
    depends_on:
      - db
      - redis

  db:
    image: postgres:16-alpine
    volumes:
      - postgres_data:/var/lib/postgresql/data
    environment:
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - POSTGRES_DB=hmeet

  redis:
    image: redis:7-alpine
    volumes:
      - redis_data:/data

  livekit:
    image: livekit/livekit-server:latest
    ports:
      - "7880:7880"
      - "7881:7881/udp"
      - "7882:7882/udp"
    command: --config /etc/livekit.yaml
    volumes:
      - ./config/livekit.yaml:/etc/livekit.yaml

  egress:
    image: livekit/egress:latest
    environment:
      - EGRESS_CONFIG_FILE=/etc/egress.yaml
    volumes:
      - ./config/egress.yaml:/etc/egress.yaml
      - recordings:/recordings
    cap_add:
      - SYS_ADMIN
    depends_on:
      - livekit
      - redis

volumes:
  postgres_data:
  redis_data:
  recordings:

config/livekit.yaml

port: 7880
rtc:
  port_range_start: 7881
  port_range_end: 7882
  use_external_ip: true
keys:
  <YOUR_API_KEY>: <YOUR_API_SECRET>

config/egress.yaml

api_key: <YOUR_API_KEY>
api_secret: <YOUR_API_SECRET>
ws_url: ws://livekit:7880
redis:
  address: redis:6379
file_output:
  local:
    - /recordings

Ports a ouvrir

Port Protocole Service
80 TCP HTTP (redirect HTTPS)
443 TCP HTTPS (Nginx)
7880 TCP LiveKit WebSocket
7881-7882 UDP LiveKit WebRTC

Nginx (reverse proxy)

# /etc/nginx/sites-available/hmeet

# Rails app
server {
    listen 443 ssl http2;
    server_name meet.example.com;

    ssl_certificate /etc/letsencrypt/live/meet.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/meet.example.com/privkey.pem;

    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

# LiveKit
server {
    listen 443 ssl http2;
    server_name livekit.example.com;

    ssl_certificate /etc/letsencrypt/live/livekit.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/livekit.example.com/privkey.pem;

    location / {
        proxy_pass http://localhost:7880;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
    }
}

Deploiement

# 1. Cloner le repo
git clone git@github.com:hadrienblanc/hmeet.git
cd hmeet

# 2. Configurer les variables d'environnement
cp .env.example .env
# Editer .env avec vos valeurs

# 3. Lancer les services
docker compose up -d

# 4. Initialiser la base
docker compose exec app bin/rails db:setup

# 5. Verifier les logs
docker compose logs -f

Flux des enregistrements

1. User clique "Enregistrer"
        ↓
2. Rails → LiveKit: start_room_composite_egress()
        ↓
3. LiveKit notifie le service Egress
        ↓
4. Egress capture l'audio et ecrit dans /recordings (volume partage)
        ↓
5. User clique "Stop"
        ↓
6. Rails → LiveKit: stop_egress()
        ↓
7. Fichier .ogg disponible dans le volume
        ↓
8. TranscribeRecordingJob envoie a Whisper
        ↓
9. GenerateSummaryJob genere resume + TODOs via GPT

Alternative: LiveKit Cloud

Si vous ne voulez pas heberger LiveKit vous-meme:

  1. Creer un compte sur LiveKit Cloud
  2. Recuperer les credentials (API Key, Secret, URL)
  3. Configurer dans l'app:
LIVEKIT_URL=wss://xxx.livekit.cloud
LIVEKIT_HOST=https://xxx.livekit.cloud
LIVEKIT_API_KEY=your-api-key
LIVEKIT_API_SECRET=your-api-secret

Note: Les recordings avec LiveKit Cloud utilisent leur stockage S3. Il faudra adapter le code pour telecharger les fichiers.


Admin

Page admin disponible sur /admin/rooms (authentification requise).


License

MIT

About

AI-powered video conferencing platform with real-time audio capture, dual transcription (local and remote) using Whisper, and automatic generation of structured, actionable meeting summaries.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors