forked from fastapi/full-stack-fastapi-template
-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
6992340
commit 00f2951
Showing
6 changed files
with
310 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |