Skip to content

Commit

Permalink
more housekeeping
Browse files Browse the repository at this point in the history
  • Loading branch information
seekinginfiniteloop committed Jun 19, 2024
1 parent 6992340 commit 00f2951
Show file tree
Hide file tree
Showing 6 changed files with 310 additions and 13 deletions.
77 changes: 77 additions & 0 deletions .devenv/docker-compose.override.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
services:

proxy:
image: traefik:v2.3
volumes:
- /var/run/docker.sock:/var/run/docker.sock
ports:
- "80:80"
- "8090:8080"
# Duplicate the command from docker-compose.yml to add --api.insecure=true
command:
# Enable Docker in Traefik, so that it reads labels from Docker services
- --providers.docker
# Add a constraint to only use services with the label for this stack
- --providers.docker.constraints=Label(`traefik.constraint-label`, `traefik-public`)
# Do not expose all Docker services, only the ones explicitly exposed
- --providers.docker.exposedbydefault=false
# Create an entrypoint "http" listening on port 80
- --entrypoints.http.address=:80
# Create an entrypoint "https" listening on port 443
- --entrypoints.https.address=:443
# Enable the access log, with HTTP requests
- --accesslog
# Enable the Traefik log, for configurations and errors
- --log
# Enable debug logging for local development
- --log.level=DEBUG
# Enable the Dashboard and API
- --api
# Enable the Dashboard and API in insecure mode for local development
- --api.insecure=true
labels:
# Enable Traefik for this service, to make it available in the public network
- traefik.enable=true
- traefik.constraint-label=traefik-public
# Dummy https-redirect middleware that doesn't really redirect, only to
# allow running it locally
- traefik.http.middlewares.https-redirect.contenttype.autodetect=false
networks:
- traefik-public
- default

db:
restart: "no"
ports:
- "5432:5432"

adminer:
restart: "no"
ports:
- "8080:8080"

backend:
restart: "no"
ports:
- "8888:8888"
volumes:
- ./backend/:/app
build:
context: ./backend
args:
INSTALL_DEV: ${INSTALL_DEV-true}
# command: sleep infinity # Infinite loop to keep container alive doing nothing
command: /start-reload.sh

frontend:
restart: "no"
build:
context: ./frontend
args:
- VITE_API_URL=http://${DOMAIN?Variable not set}
- NODE_ENV=development

networks:
traefik-public:
# For local dev, don't expect an external Traefik network
external: false
77 changes: 77 additions & 0 deletions .devenv/docker-compose.traefik.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
services:
traefik:
image: traefik:v2.3
ports:
# Listen on port 80, default for HTTP, necessary to redirect to HTTPS
- 80:80
# Listen on port 443, default for HTTPS
- 443:443
restart: always
labels:
# Enable Traefik for this service, to make it available in the public network
- traefik.enable=true
# Use the traefik-public network (declared below)
- traefik.docker.network=traefik-public
# Define the port inside of the Docker service to use
- traefik.http.services.traefik-dashboard.loadbalancer.server.port=8080
# Make Traefik use this domain (from an environment variable) in HTTP
- traefik.http.routers.traefik-dashboard-http.entrypoints=http
- traefik.http.routers.traefik-dashboard-http.rule=Host(`traefik.${DOMAIN?Variable not set}`)
# traefik-https the actual router using HTTPS
- traefik.http.routers.traefik-dashboard-https.entrypoints=https
- traefik.http.routers.traefik-dashboard-https.rule=Host(`traefik.${DOMAIN?Variable not set}`)
- traefik.http.routers.traefik-dashboard-https.tls=true
# Use the "le" (Let's Encrypt) resolver created below
- traefik.http.routers.traefik-dashboard-https.tls.certresolver=le
# Use the special Traefik service api@internal with the web UI/Dashboard
- traefik.http.routers.traefik-dashboard-https.service=api@internal
# https-redirect middleware to redirect HTTP to HTTPS
- traefik.http.middlewares.https-redirect.redirectscheme.scheme=https
- traefik.http.middlewares.https-redirect.redirectscheme.permanent=true
# traefik-http set up only to use the middleware to redirect to https
- traefik.http.routers.traefik-dashboard-http.middlewares=https-redirect
# admin-auth middleware with HTTP Basic auth
# Using the environment variables USERNAME and HASHED_PASSWORD
- traefik.http.middlewares.admin-auth.basicauth.users=${USERNAME?Variable not set}:${HASHED_PASSWORD?Variable not set}
# Enable HTTP Basic auth, using the middleware created above
- traefik.http.routers.traefik-dashboard-https.middlewares=admin-auth
volumes:
# Add Docker as a mounted volume, so that Traefik can read the labels of other services
- /var/run/docker.sock:/var/run/docker.sock:ro
# Mount the volume to store the certificates
- traefik-public-certificates:/certificates
command:
# Enable Docker in Traefik, so that it reads labels from Docker services
- --providers.docker
# Do not expose all Docker services, only the ones explicitly exposed
- --providers.docker.exposedbydefault=false
# Create an entrypoint "http" listening on port 80
- --entrypoints.http.address=:80
# Create an entrypoint "https" listening on port 443
- --entrypoints.https.address=:443
# Create the certificate resolver "le" for Let's Encrypt, uses the environment variable EMAIL
- --certificatesresolvers.le.acme.email=${EMAIL?Variable not set}
# Store the Let's Encrypt certificates in the mounted volume
- --certificatesresolvers.le.acme.storage=/certificates/acme.json
# Use the TLS Challenge for Let's Encrypt
- --certificatesresolvers.le.acme.tlschallenge=true
# Enable the access log, with HTTP requests
- --accesslog
# Enable the Traefik log, for configurations and errors
- --log
# Enable the Dashboard and API
- --api
networks:
# Use the public network created to be shared between Traefik and
# any other service that needs to be publicly available with HTTPS
- traefik-public

volumes:
# Create a volume to store the certificates, even if the container is recreated
traefik-public-certificates:

networks:
# Use the previously created public network "traefik-public", shared with other
# services that need to be publicly available via this Traefik
traefik-public:
external: true
131 changes: 131 additions & 0 deletions .devenv/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
services:
db:
image: postgres:12
restart: always
volumes:
- app-db-data:/var/lib/postgresql/data/pgdata
env_file:
- .env
environment:
- PGDATA=/var/lib/postgresql/data/pgdata
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD?Variable not set}
- POSTGRES_USER=${POSTGRES_USER?Variable not set}
- POSTGRES_DB=${POSTGRES_DB?Variable not set}

adminer:
image: adminer
restart: always
networks:
- traefik-public
- default
depends_on:
- db
environment:
- ADMINER_DESIGN=pepa-linha-dark
labels:
- traefik.enable=true
- traefik.docker.network=traefik-public
- traefik.constraint-label=traefik-public
- traefik.http.routers.${STACK_NAME?Variable not set}-adminer-http.rule=Host(`adminer.${DOMAIN?Variable not set}`)
- traefik.http.routers.${STACK_NAME?Variable not set}-adminer-http.entrypoints=http
- traefik.http.routers.${STACK_NAME?Variable not set}-adminer-http.middlewares=https-redirect
- traefik.http.routers.${STACK_NAME?Variable not set}-adminer-https.rule=Host(`adminer.${DOMAIN?Variable not set}`)
- traefik.http.routers.${STACK_NAME?Variable not set}-adminer-https.entrypoints=https
- traefik.http.routers.${STACK_NAME?Variable not set}-adminer-https.tls=true
- traefik.http.routers.${STACK_NAME?Variable not set}-adminer-https.tls.certresolver=le
- traefik.http.services.${STACK_NAME?Variable not set}-adminer.loadbalancer.server.port=8080

backend:
image: '${DOCKER_IMAGE_BACKEND?Variable not set}:${TAG-latest}'
restart: always
networks:
- traefik-public
- default
depends_on:
- db
env_file:
- .env
environment:
- DOMAIN=${DOMAIN}
- ENVIRONMENT=${ENVIRONMENT}
- BACKEND_CORS_ORIGINS=${BACKEND_CORS_ORIGINS}
- SECRET_KEY=${SECRET_KEY?Variable not set}
- FIRST_SUPERUSER=${FIRST_SUPERUSER?Variable not set}
- FIRST_SUPERUSER_PASSWORD=${FIRST_SUPERUSER_PASSWORD?Variable not set}
- USERS_OPEN_REGISTRATION=${USERS_OPEN_REGISTRATION}
- SMTP_HOST=${SMTP_HOST}
- SMTP_USER=${SMTP_USER}
- SMTP_PASSWORD=${SMTP_PASSWORD}
- EMAILS_FROM_EMAIL=${EMAILS_FROM_EMAIL}
- POSTGRES_SERVER=db
- POSTGRES_PORT=${POSTGRES_PORT}
- POSTGRES_DB=${POSTGRES_DB}
- POSTGRES_USER=${POSTGRES_USER?Variable not set}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD?Variable not set}
- SENTRY_DSN=${SENTRY_DSN}

build:
context: ./backend
args:
INSTALL_DEV: ${INSTALL_DEV-false}
platform: linux/amd64 # Patch for M1 Mac
labels:
- traefik.enable=true
- traefik.docker.network=traefik-public
- traefik.constraint-label=traefik-public

- traefik.http.services.${STACK_NAME?Variable not set}-backend.loadbalancer.server.port=80

- traefik.http.routers.${STACK_NAME?Variable not set}-backend-http.rule=Host(`${DOMAIN?Variable not set}`, `www.${DOMAIN?Variable not set}`) && PathPrefix(`/api`, `/docs`, `/redoc`)
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-http.entrypoints=http

- traefik.http.routers.${STACK_NAME?Variable not set}-backend-https.rule=Host(`${DOMAIN?Variable not set}`, `www.${DOMAIN?Variable not set}`) && PathPrefix(`/api`, `/docs`, `/redoc`)
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-https.entrypoints=https
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-https.tls=true
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-https.tls.certresolver=le

# Define Traefik Middleware to handle domain with and without "www" to redirect to only one
- traefik.http.middlewares.${STACK_NAME?Variable not set}-www-redirect.redirectregex.regex=^http(s)?://www.(${DOMAIN?Variable not set})/(.*)
# Redirect a domain with www to non-www
- traefik.http.middlewares.${STACK_NAME?Variable not set}-www-redirect.redirectregex.replacement=http$${1}://${DOMAIN?Variable not set}/$${3}

# Enable www redirection for HTTP and HTTPS
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-http.middlewares=https-redirect,${STACK_NAME?Variable not set}-www-redirect
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-https.middlewares=${STACK_NAME?Variable not set}-www-redirect

frontend:
image: '${DOCKER_IMAGE_FRONTEND?Variable not set}:${TAG-latest}'
restart: always
networks:
- traefik-public
- default
build:
context: ./frontend
args:
- VITE_API_URL=https://${DOMAIN?Variable not set}
- NODE_ENV=production
labels:
- traefik.enable=true
- traefik.docker.network=traefik-public
- traefik.constraint-label=traefik-public

- traefik.http.services.${STACK_NAME?Variable not set}-frontend.loadbalancer.server.port=80

- traefik.http.routers.${STACK_NAME?Variable not set}-frontend-http.rule=Host(`${DOMAIN?Variable not set}`, `www.${DOMAIN?Variable not set}`)
- traefik.http.routers.${STACK_NAME?Variable not set}-frontend-http.entrypoints=http

- traefik.http.routers.${STACK_NAME?Variable not set}-frontend-https.rule=Host(`${DOMAIN?Variable not set}`, `www.${DOMAIN?Variable not set}`)
- traefik.http.routers.${STACK_NAME?Variable not set}-frontend-https.entrypoints=https
- traefik.http.routers.${STACK_NAME?Variable not set}-frontend-https.tls=true
- traefik.http.routers.${STACK_NAME?Variable not set}-frontend-https.tls.certresolver=le

# Enable www redirection for HTTP and HTTPS
- traefik.http.routers.${STACK_NAME?Variable not set}-frontend-https.middlewares=${STACK_NAME?Variable not set}-www-redirect
- traefik.http.routers.${STACK_NAME?Variable not set}-frontend-http.middlewares=https-redirect,${STACK_NAME?Variable not set}-www-redirect
volumes:
app-db-data:

networks:
traefik-public:
# Allow setting it to false for testing
external: true
4 changes: 2 additions & 2 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ DOMAIN=localhost
# Environment: local, staging, production
ENVIRONMENT=local

PROJECT_NAME="Full Stack FastAPI Project"
STACK_NAME=full-stack-fastapi-project
PROJECT_NAME="ChatHoard"
STACK_NAME=chat-horde-stack

# Backend
BACKEND_CORS_ORIGINS="http://localhost,http://localhost:5173,https://localhost,https://localhost:5173,http://localhost.tiangolo.com"
Expand Down
4 changes: 2 additions & 2 deletions CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Contributor Code of Conduct
# ChatHoard Contributor Code of Conduct

## Contributions welcome!

Expand Down Expand Up @@ -30,7 +30,7 @@ You have the right and responsibility to remove, edit, or reject comments, commi

## Scope

Always applies. Any behavior that doesn't align with these standards in *any* setting and will not be tolerated. If you can't be accepting, civil, and respectful, then you are not welcome to contribute to this project.
Always applies. I will not tolerate any behavior that doesn't align with these standards in *any* setting. If you can't be accepting, civil, and respectful, then you aren't welcome here.

## Enforcement

Expand Down
30 changes: 21 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,41 @@
# ChatHoard - Take Control of Your Chats
# ChatHoard - Take Control of Your Chat History

ChatHoard is a ready-to-deploy full-stake web app that allows your to upload and store your ChatGPT chats (other chat formats planned). It offers robust search and filtering capabilities, and is lightning fast - based on Sebastián Ramírez's Full-StackFastAPI-Template with FastAPI, Pydantic validation/serialization, SQLModel for ORM, and a front-end with React using Chakra UI. It can be deployed locally with Docker Compose in a minimalist deployment, or publicly with authentication and authorization using OAuth2 with JWT tokens and multi-user support. I created ChatHoard to help me manage my ChatGPT chats, but it's designed to scale robustly and will easily extend to other chat formats with added Pydantic models.
ChatHoard is a ready-to-deploy full-stack web app for making the most of your ChatGPT chat history (other chat formats planned). ChatHorde offers robust search and filtering capabilities, and is lightning fast - based on Full-Stack-FastAPI-Template with FastAPI, Pydantic validation/serialization, SQLModel for ORM, and a front-end with React using Chakra UI. You can be deploy ChatHorde locally with Docker Compose in a minimalist deployment, or publicly with authentication and authorization using OAuth2 with JWT tokens and multi-user support. I created ChatHoard to help me manage my ChatGPT chats, but it's designed to scale robustly and can extend to other chat formats with added Pydantic models.

I was continually frustrated by how hard it is to search my ChatGPT chats and the lack of organization capabilities.

The Pydantic models are robust and offer a lot of definition for the data; most of this isn't used in the current version, but it would put anyone wanting to run ML models on the data in a good position.

## Currently in active, early development. More to follow. Stay tuned
## Currently in active, early development. More to follow. Stay tuned. NOT YET FUNCTIONAL

## Planned Features
## Planned Initial Features

User Interface:

- [ ] Modern full-featured UI with React and Chakra UI
- [ ] Superb search and filtering capabilities (powered by meilisearch)
- [ ] Group and organize chats
- [ ] Tag chats
- [ ] Add notes to chats
- [ ] Easy graphical import/export of chats

Backend:

- [ ] Minimalist local and full/public deployment options with Docker Compose
- [ ] OAuth2 with JWT tokens
- [ ] Passkey authentication
- [ ] Multi-user support
- [ ] Admin/owner UI panel for managing users, permissions, and settings

### Later Planned Features

- [ ] Support for other chat formats (Gemini and Claude); if you want to help add support for your favorite chat format, please reach out. I'd love to collaborate.
- [ ] Group and organize chats
- [ ] Tag chats
- [ ] Add notes to chats
- [ ] Automated download requests for new chats from ChatGPT (these are emailed to you); and deletion of old chats from OpenAI
- [ ] Additional encryption options (i.e. client-side encryption)
- [ ] Support for other chat formats (Gemini and Claude); I welcome your help adding support for your favorite chat format, please reach out. I'd love to collaborate.
- [ ] ML-powered search assistant
- [ ] Chat sharing and in-line commenting
- [ ] Passkey/webauthn authentication
- [ ] NLP-powered groupings and tagging

### Maybe Later Features

- [ ] Fully private subscription-based cloud deployment/hosting or SaaS??? (I'd do it for free if I could, but, you know, money)

0 comments on commit 00f2951

Please sign in to comment.