- Getting containers ready for the cloud

This commit is contained in:
Josako
2024-08-06 14:56:12 +02:00
parent 64cf8df3a9
commit ab8359365d
20 changed files with 494 additions and 110 deletions

View File

@@ -10,7 +10,8 @@ from flask_jwt_extended import JWTManager
from flask_session import Session
from flask_wtf import CSRFProtect
from .utils.key_encryption import JosKMSClient
# from .utils.key_encryption import JosKMSClient
from .utils.simple_encryption import SimpleEncryption
from .utils.minio_utils import MinioClient
# Create extensions
@@ -26,5 +27,7 @@ socketio = SocketIO()
jwt = JWTManager()
session = Session()
kms_client = JosKMSClient.from_service_account_json('config/gc_sa_eveai.json')
# kms_client = JosKMSClient.from_service_account_json('config/gc_sa_eveai.json')
simple_encryption = SimpleEncryption()
minio_client = MinioClient()

View File

@@ -0,0 +1,39 @@
from cryptography.fernet import Fernet
from flask import Flask
class SimpleEncryption:
def __init__(self, app: Flask = None):
self.app = app
self.fernet = None
if app is not None:
self.init_app(app)
def init_app(self, app: Flask):
self.app = app
encryption_key = app.config.get('API_ENCRYPTION_KEY')
if not encryption_key:
raise ValueError("ENCRYPTION_KEY is not set in the app configuration")
self.fernet = Fernet(encryption_key.encode())
# Optionally log the initialization (similar to your current setup)
app.logger.info('SimpleEncryption initialized')
def encrypt_api_key(self, api_key: str) -> str:
if not self.fernet:
raise RuntimeError("SimpleEncryption is not initialized. Call init_app first.")
return self.fernet.encrypt(api_key.encode()).decode()
def decrypt_api_key(self, encrypted_api_key: str) -> str:
if not self.fernet:
raise RuntimeError("SimpleEncryption is not initialized. Call init_app first.")
return self.fernet.decrypt(encrypted_api_key.encode()).decode()
@staticmethod
def generate_key() -> str:
"""Generate a new Fernet key."""
return Fernet.generate_key().decode()
# Usage:
# from common.utils.simple_encryption import simple_encryption
# simple_encryption.init_app(app)

View File

@@ -10,7 +10,7 @@ basedir = path.abspath(path.dirname(__file__))
class Config(object):
DEBUG = False
DEVELOPMENT = False
SECRET_KEY = '97867c1491bea5ee6a8e8436eb11bf2ba6a69ff53ab1b17ecba450d0f2e572e1'
SECRET_KEY = environ.get('SECRET_KEY')
SESSION_COOKIE_SECURE = False
SESSION_COOKIE_HTTPONLY = True
@@ -29,7 +29,7 @@ class Config(object):
# SECURITY_POST_RESET_VIEW = '/admin/login'
# SECURITY_POST_CHANGE_VIEW = '/admin/login'
# SECURITY_BLUEPRINT_NAME = 'security_bp'
SECURITY_PASSWORD_SALT = '228614859439123264035565568761433607235'
SECURITY_PASSWORD_SALT = environ.get('SECURITY_PASSWORD_SALT')
REMEMBER_COOKIE_SAMESITE = 'strict'
SESSION_COOKIE_SAMESITE = 'strict'
SECURITY_CONFIRMABLE = True
@@ -45,13 +45,6 @@ class Config(object):
SECURITY_CSRF_HEADER = 'X-XSRF-TOKEN'
WTF_CSRF_CHECK_DEFAULT = False
# flask-mailman settings
MAIL_SERVER = 'mail.flow-it.net'
MAIL_PORT = 587
MAIL_USE_TLS = True
MAIL_USE_SSL = False
MAIL_DEFAULT_SENDER = ('eveAI Admin', 'eveai_admin@flow-it.net')
# file upload settings
MAX_CONTENT_LENGTH = 16 * 1024 * 1024
UPLOAD_EXTENSIONS = ['.txt', '.pdf', '.png', '.jpg', '.jpeg', '.gif']
@@ -75,6 +68,18 @@ class Config(object):
'anthropic.claude-3-5-sonnet': 8000
}
# OpenAI API Keys
OPENAI_API_KEY = environ.get('OPENAI_API_KEY')
# Groq API Keys
GROQ_API_KEY = environ.get('GROQ_API_KEY')
# Anthropic API Keys
ANTHROPIC_API_KEY = environ.get('ANTHROPIC_API_KEY')
# Portkey API Keys
PORTKEY_API_KEY = environ.get('PORTKEY_API_KEY')
# Celery settings
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
@@ -93,6 +98,12 @@ class Config(object):
PERMANENT_SESSION_LIFETIME = timedelta(minutes=60)
SESSION_REFRESH_EACH_REQUEST = True
# JWT settings
JWT_SECRET_KEY = environ.get('JWT_SECRET_KEY')
# API Encryption
API_ENCRYPTION_KEY = environ.get('API_ENCRYPTION_KEY')
# Fallback Algorithms
FALLBACK_ALGORITHMS = [
"RAG_TENANT",
@@ -115,25 +126,31 @@ class DevConfig(Config):
DEBUG = True
FLASK_DEBUG = True
PYCHARM_DEBUG = False
EXPLAIN_TEMPLATE_LOADING = False
# Database Settings
DB_HOST = environ.get('DB_HOST', 'localhost')
DB_USER = environ.get('DB_USER', 'luke')
DB_PASS = environ.get('DB_PASS', 'Skywalker!')
DB_NAME = environ.get('DB_NAME', 'eveai')
SQLALCHEMY_DATABASE_URI = f'postgresql+pg8000://{DB_USER}:{DB_PASS}@{DB_HOST}:5432/{DB_NAME}'
SQLALCHEMY_BINDS = {'public': SQLALCHEMY_DATABASE_URI}
EXPLAIN_TEMPLATE_LOADING = False
# flask-mailman settings
MAIL_SERVER = 'mail.flow-it.net'
MAIL_PORT = 587
MAIL_USE_TLS = True
MAIL_USE_SSL = False
MAIL_DEFAULT_SENDER = ('eveAI Admin', 'eveai_admin@flow-it.net')
MAIL_USERNAME = environ.get('MAIL_USERNAME')
MAIL_PASSWORD = environ.get('MAIL_PASSWORD')
# Define the nginx prefix used for the specific apps
EVEAI_APP_LOCATION_PREFIX = '/admin'
EVEAI_CHAT_LOCATION_PREFIX = '/chat'
# flask-mailman settings
MAIL_USERNAME = 'eveai_super@flow-it.net'
MAIL_PASSWORD = '$6xsWGbNtx$CFMQZqc*'
# file upload settings
UPLOAD_FOLDER = '/app/tenant_files'
# UPLOAD_FOLDER = '/app/tenant_files'
# Celery settings
# eveai_app Redis Settings
@@ -143,22 +160,10 @@ class DevConfig(Config):
CELERY_BROKER_URL_CHAT = 'redis://redis:6379/3'
CELERY_RESULT_BACKEND_CHAT = 'redis://redis:6379/3'
# OpenAI API Keys
OPENAI_API_KEY = 'sk-proj-8R0jWzwjL7PeoPyMhJTZT3BlbkFJLb6HfRB2Hr9cEVFWEhU7'
# Groq API Keys
GROQ_API_KEY = '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'
# Anthropic API Keys
ANTHROPIC_API_KEY = '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'
# Portkey API Keys
PORTKEY_API_KEY = 'T2Dt4QTpgCvWxa1OftYCJtj7NcDZ'
# Unstructured settings
UNSTRUCTURED_API_KEY = 'pDgCrXumYhM3CNvjvwV8msMldXC3uw'
UNSTRUCTURED_BASE_URL = 'https://flowitbv-16c4us0m.api.unstructuredapp.io'
UNSTRUCTURED_FULL_URL = 'https://flowitbv-16c4us0m.api.unstructuredapp.io/general/v0/general'
# UNSTRUCTURED_API_KEY = 'pDgCrXumYhM3CNvjvwV8msMldXC3uw'
# UNSTRUCTURED_BASE_URL = 'https://flowitbv-16c4us0m.api.unstructuredapp.io'
# UNSTRUCTURED_FULL_URL = 'https://flowitbv-16c4us0m.api.unstructuredapp.io/general/v0/general'
# SocketIO settings
SOCKETIO_MESSAGE_QUEUE = 'redis://redis:6379/1'
@@ -176,9 +181,6 @@ class DevConfig(Config):
GC_KEY_RING = 'eveai-chat'
GC_CRYPTO_KEY = 'envelope-encryption-key'
# JWT settings
JWT_SECRET_KEY = 'bsdMkmQ8ObfMD52yAFg4trrvjgjMhuIqg2fjDpD/JqvgY0ccCcmlsEnVFmR79WPiLKEA3i8a5zmejwLZKl4v9Q=='
# Session settings
SESSION_REDIS = redis.from_url('redis://redis:6379/2')
@@ -194,19 +196,28 @@ class DevConfig(Config):
class ProdConfig(Config):
DEVELOPMENT = False
DEBUG = False
DEVELOPMENT = True
DEBUG = True
FLASK_DEBUG = True
DEBUG = False
FLASK_DEBUG = False
PYCHARM_DEBUG = False
DB_HOST = environ.get('DB_HOST', 'bswnz4.stackhero-network.com')
DB_USER = environ.get('DB_USER', 'luke_skywalker')
DB_PASS = environ.get('DB_PASS', '2MK&1rHmWEydE2rFuJLq*ls%tdkPAk2')
DB_NAME = environ.get('DB_NAME', 'eveai')
DB_PORT = environ.get('DB_PORT', '5945')
EXPLAIN_TEMPLATE_LOADING = False
# Database Settings
DB_HOST = environ.get('DB_HOST')
DB_USER = environ.get('DB_USER')
DB_PASS = environ.get('DB_PASS')
DB_NAME = environ.get('DB_NAME')
DB_PORT = environ.get('DB_PORT')
SQLALCHEMY_DATABASE_URI = f'postgresql+pg8000://{DB_USER}:{DB_PASS}@{DB_HOST}:{DB_PORT}/{DB_NAME}'
SQLALCHEMY_BINDS = {'public': SQLALCHEMY_DATABASE_URI}
EXPLAIN_TEMPLATE_LOADING = False
# flask-mailman settings
MAIL_SERVER = 'mail.askeveai.com'
MAIL_PORT = 587
MAIL_USE_TLS = True
MAIL_USE_SSL = False
MAIL_DEFAULT_SENDER = ('Evie Admin', 'evie_admin@askeveai.com')
MAIL_USERNAME = environ.get('MAIL_USERNAME')
MAIL_PASSWORD = environ.get('MAIL_PASSWORD')
# Define the nginx prefix used for the specific apps
EVEAI_APP_LOCATION_PREFIX = '/admin'
@@ -217,12 +228,13 @@ class ProdConfig(Config):
MAIL_PASSWORD = '$6xsWGbNtx$CFMQZqc*'
# file upload settings
UPLOAD_FOLDER = '/app/tenant_files'
# UPLOAD_FOLDER = '/app/tenant_files'
REDIS_USER = 'admin'
REDIS_PASS = 'b32vtDtLriSY1fL2zGrZg8IZKI0g9ucsLtVNanRFAras6oZ51wjVNB1Y05uG7uEw'
REDIS_URL = '8bciqc.stackhero-network.com'
REDIS_PORT = '9961'
# Redis Settings
REDIS_USER = environ.get('REDIS_USER')
REDIS_PASS = environ.get('REDIS_PASS')
REDIS_URL = environ.get('REDIS_URL')
REDIS_PORT = environ.get('REDIS_PORT', '6379')
REDIS_BASE_URI = f'redis://{REDIS_USER}:{REDIS_PASS}@{REDIS_URL}:{REDIS_PORT}'
# Celery settings
@@ -236,23 +248,6 @@ class ProdConfig(Config):
# Session settings
SESSION_REDIS = redis.from_url(f'{REDIS_BASE_URI}/2')
# OpenAI API Keys
OPENAI_API_KEY = 'sk-proj-8R0jWzwjL7PeoPyMhJTZT3BlbkFJLb6HfRB2Hr9cEVFWEhU7'
# Groq API Keys
GROQ_API_KEY = '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'
# Anthropic API Keys
ANTHROPIC_API_KEY = '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'
# Portkey API Keys
PORTKEY_API_KEY = 'T2Dt4QTpgCvWxa1OftYCJtj7NcDZ'
# Unstructured settings
UNSTRUCTURED_API_KEY = 'pDgCrXumYhM3CNvjvwV8msMldXC3uw'
UNSTRUCTURED_BASE_URL = 'https://flowitbv-16c4us0m.api.unstructuredapp.io'
UNSTRUCTURED_FULL_URL = 'https://flowitbv-16c4us0m.api.unstructuredapp.io/general/v0/general'
# SocketIO settings
SOCKETIO_MESSAGE_QUEUE = f'{REDIS_BASE_URI}/1'
SOCKETIO_CORS_ALLOWED_ORIGINS = '*'
@@ -269,15 +264,14 @@ class ProdConfig(Config):
GC_KEY_RING = 'eveai-chat'
GC_CRYPTO_KEY = 'envelope-encryption-key'
# JWT settings
JWT_SECRET_KEY = 'bsdMkmQ8ObfMD52yAFg4trrvjgjMhuIqg2fjDpD/JqvgY0ccCcmlsEnVFmR79WPiLKEA3i8a5zmejwLZKl4v9Q=='
# PATH settings
ffmpeg_path = '/usr/bin/ffmpeg'
config = {
'dev': DevConfig(),
'prod': ProdConfig(),
'default': DevConfig(),
}
def get_config(config_name='dev'):
configs = {
'dev': DevConfig,
'prod': ProdConfig,
'default': DevConfig,
}
return configs.get(config_name)

81
docker/build_tag_and_push.sh Executable file
View File

@@ -0,0 +1,81 @@
#!/bin/bash
# Source the environment setup script
if [ -f "./docker_env_switch.sh" ]; then
source ./docker_env_switch.sh dev
else
echo "Error: set_environment.sh not found in the current directory."
exit 1
fi
# Docker Hub username
USERNAME="josakola"
# List of all your services
ALL_SERVICES=("eveai_app" "eveai_workers" "eveai_chat" "eveai_chat_workers" "nginx")
# Function to build, tag and push an image
build_tag_and_push() {
local service=$1
echo "Building, tagging, and pushing ${service}..."
# Extract dockerfile and context paths from Docker Compose configuration
local dockerfile_path
local context_path
dockerfile_path=$(docker compose -f "$COMPOSE_FILE" config | grep "${service}" -A 10 | grep "dockerfile" | awk '{print $2}')
context_path=$(docker compose -f "$COMPOSE_FILE" config | grep "${service}" -A 10 | grep "context" | awk '{print $2}')
# Verify the paths
echo "Dockerfile path: ${dockerfile_path}"
echo "Context path: ${context_path}"
# Use docker buildx to build the image
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t "${USERNAME}/${service}:latest" \
--push \
--file "${dockerfile_path}" \
"${context_path}"
}
# Function to check if a service is in the ALL_SERVICES array
service_exists() {
local service=$1
for s in "${ALL_SERVICES[@]}"; do
if [[ "$s" == "$service" ]]; then
return 0
fi
done
return 1
}
# Ensure we're using buildx
docker buildx create --use
# If COMPOSE_FILE is not set, use a default value
if [ -z "$COMPOSE_FILE" ]; then
COMPOSE_FILE="compose_dev.yaml"
echo "COMPOSE_FILE not set, using default: $COMPOSE_FILE"
else
echo "Using COMPOSE_FILE: $COMPOSE_FILE"
fi
# If no arguments are provided, process all services
if [ $# -eq 0 ]; then
echo "No specific services provided. Processing all services..."
for service in "${ALL_SERVICES[@]}"; do
build_tag_and_push "$service"
done
else
# Process only the specified services
for service in "$@"; do
if service_exists "$service"; then
build_tag_and_push "$service"
else
echo "Warning: ${service} is not a recognized service name. Skipping."
fi
done
fi
echo "Done!"

View File

@@ -11,17 +11,33 @@
x-common-variables: &common-variables
DB_HOST: db
DB_USER: luke
DB_PASS: Skywalker!
DB_PASS: 'Skywalker!'
DB_NAME: eveai
DB_PORT: '5432'
FLASK_ENV: development
FLASK_DEBUG: 1
FLASK_DEBUG: true
SECRET_KEY: '97867c1491bea5ee6a8e8436eb11bf2ba6a69ff53ab1b17ecba450d0f2e572e1'
SECURITY_PASSWORD_SALT: '228614859439123264035565568761433607235'
MAIL_USERNAME: eveai_super@flow-it.net
MAIL_PASSWORD: '$6xsWGbNtx$CFMQZqc*'
OPENAI_API_KEY: 'sk-proj-8R0jWzwjL7PeoPyMhJTZT3BlbkFJLb6HfRB2Hr9cEVFWEhU7'
GROQ_API_KEY: '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'
ANTHROPIC_API_KEY: 'sk-ant-api03-c2TmkzbReeGhXBO5JxNH6BJNylRDonc9GmZd0eRbrvyekec2'
PORTKEY_API_KEY: 'T2Dt4QTpgCvWxa1OftYCJtj7NcDZ'
JWT_SECRET_KEY: 'bsdMkmQ8ObfMD52yAFg4trrvjgjMhuIqg2fjDpD/JqvgY0ccCcmlsEnVFmR79WPiLKEA3i8a5zmejwLZKl4v9Q=='
API_ENCRYPTION_KEY: 'xfF5369IsredSrlrYZqkM9ZNrfUASYYS6TCcAR9UKj4='
MINIO_ENDPOINT: minio:9000
MINIO_ACCESS_KEY: minioadmin
MINIO_SECRET_KEY: minioadmin
services:
nginx:
image: nginx:latest
build:
context: ../nginx
dockerfile: Dockerfile
platforms:
- linux/amd64
- linux/arm64
ports:
- 80:80
- 8080:8080
@@ -39,6 +55,9 @@ services:
build:
context: ..
dockerfile: ./docker/eveai_app/Dockerfile
platforms:
- linux/amd64
- linux/arm64
ports:
- 5001:5001
environment:
@@ -69,6 +88,9 @@ services:
build:
context: ..
dockerfile: ./docker/eveai_workers/Dockerfile
platforms:
- linux/amd64
- linux/arm64
# ports:
# - 5001:5001
environment:
@@ -98,6 +120,9 @@ services:
build:
context: ..
dockerfile: ./docker/eveai_chat/Dockerfile
platforms:
- linux/amd64
- linux/arm64
ports:
- 5002:5002
environment:
@@ -125,6 +150,9 @@ services:
build:
context: ..
dockerfile: ./docker/eveai_chat_workers/Dockerfile
platforms:
- linux/amd64
- linux/arm64
# ports:
# - 5001:5001
environment:

View File

@@ -0,0 +1,123 @@
# Comments are provided throughout this file to help you get started.
# If you need more help, visit the Docker Compose reference guide at
# https://docs.docker.com/go/compose-spec-reference/
# Here the instructions define your application as a service called "server".
# This service is built from the Dockerfile in the current directory.
# You can add other services your application may depend on here, such as a
# database or a cache. For examples, see the Awesome Compose repository:
# https://github.com/docker/awesome-compose
x-common-variables: &common-variables
DB_HOST: bswnz4.stackhero-network.com
DB_USER: luke_skywalker
DB_PASS: 2MK&1rHmWEydE2rFuJLq*ls%tdkPAk2
DB_NAME: eveai
DB_PORT: '5945'
FLASK_ENV: production
FLASK_DEBUG: false
SECRET_KEY: '38wg8e1lvhlvcu0apr95n8o07axf244lzaa7b7djh7itrf8jnyyh1lkuco529w'
SECURITY_PASSWORD_SALT: '166448071751628781809462050022558634074'
MAIL_USERNAME: 'evie_admin@askeveai.com'
MAIL_PASSWORD: 's5D%R#y^v!s&6Z^i0k&'
REDIS_USER: admin
REDIS_PASS: 'b32vtDtLriSY1fL2zGrZg8IZKI0g9ucsLtVNanRFAras6oZ51wjVNB1Y05uG7uEw'
REDIS_URL: 8bciqc.stackhero-network.com
REDIS_PORT: '9961'
OPENAI_API_KEY: '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'
GROQ_API_KEY: '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'
ANTHROPIC_API_KEY: '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'
PORTKEY_API_KEY: '3C+zAGR8pCalevBXFVc0l8R2MPYc'
JWT_SECRET_KEY: '0d99e810e686ea567ef305d8e9b06195c4db482952e19276590a726cde60a408'
API_ENCRYPTION_KEY: 'Ly5XYWwEKiasfAwEqdEMdwR-k0vhrq6QPYd4whEROB0='
services:
nginx:
image: nginx:latest
ports:
- 80:80
- 8080:8080
volumes:
- ../nginx:/etc/nginx
- ../nginx/sites-enabled:/etc/nginx/sites-enabled
- ../nginx/static:/etc/nginx/static
- ../nginx/public:/etc/nginx/public
- ./logs/nginx:/var/log/nginx
labels:
- "traefik.enable=true"
- "traefik.http.routers.api.rule=Host(`evie.askeveai.com`)"
- "traefik.http.services.nginx.loadbalancer.server.port=80"
depends_on:
- eveai_app
- eveai_chat
eveai_app:
image: josakola/eveai_app:latest
ports:
- 5001:5001
environment:
<<: *common-variables
volumes:
- ./logs:/app/logs
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5001/health"]
interval: 10s
timeout: 5s
retries: 5
command: ["sh", "-c", "scripts/start_eveai_app.sh"]
eveai_workers:
image: josakola/eveai_workers:latest
# ports:
# - 5001:5001
environment:
<<: *common-variables
volumes:
- ./logs:/app/logs
# healthcheck:
# test: [ "CMD", "curl", "-f", "http://localhost:5001/health" ]
# interval: 10s
# timeout: 5s
# retries: 5
command: [ "sh", "-c", "scripts/start_eveai_workers.sh" ]
eveai_chat:
image: josakola/eveai_chat:latest
ports:
- 5002:5002
environment:
<<: *common-variables
volumes:
- ./logs:/app/logs
healthcheck:
test: [ "CMD", "curl", "-f", "http://localhost:5002/health" ] # Adjust based on your health endpoint
interval: 10s
timeout: 5s
retries: 5
command: ["sh", "-c", "scripts/start_eveai_chat.sh"]
eveai_chat_workers:
image: josakola/eveai_chat_workers:latest
# ports:
# - 5001:5001
environment:
<<: *common-variables
volumes:
- ./logs:/app/logs
# healthcheck:
# test: [ "CMD", "curl", "-f", "http://localhost:5001/health" ]
# interval: 10s
# timeout: 5s
# retries: 5
command: [ "sh", "-c", "scripts/start_eveai_chat_workers.sh" ]
#volumes:
# minio_data:
# db-data:
# redis-data:
# tenant-files:
#secrets:
# db-password:
# file: ./db/password.txt

57
docker/docker_env_switch.sh Executable file
View File

@@ -0,0 +1,57 @@
#!/bin/bash
# Function to display usage information
usage() {
echo "Usage: source $0 [dev|prod]"
echo " dev : Switch to development environment"
echo " prod : Switch to production environment"
}
# Check if the script is sourced
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
echo "Error: This script must be sourced, not executed directly."
echo "Please run: source $0 [dev|prod]"
exit 1
fi
# Check if an argument is provided
if [ $# -eq 0 ]; then
usage
return 1
fi
# Set variables based on the environment
case $1 in
dev)
DOCKER_CONTEXT="default"
COMPOSE_FILE="compose_dev.yaml"
;;
prod)
DOCKER_CONTEXT="mxz536.stackhero-network.com"
COMPOSE_FILE="compose_stackhero.yaml"
;;
*)
echo "Invalid environment. Use 'dev' or 'prod'."
usage
return 1
;;
esac
# Switch Docker context
echo "Switching to Docker context: $DOCKER_CONTEXT"
docker context use $DOCKER_CONTEXT
# Set the COMPOSE_FILE environment variable
export COMPOSE_FILE=$COMPOSE_FILE
echo "Set COMPOSE_FILE to $COMPOSE_FILE"
# Define aliases for common Docker commands
alias docker-compose="docker compose -f $COMPOSE_FILE"
alias dc="docker compose -f $COMPOSE_FILE"
alias dcup="docker compose -f $COMPOSE_FILE up -d"
alias dcdown="docker compose -f $COMPOSE_FILE down"
alias dcps="docker compose -f $COMPOSE_FILE ps"
alias dclogs="docker compose -f $COMPOSE_FILE logs"
echo "Docker environment switched to $1"
echo "You can now use 'docker-compose', 'dc', 'dcup', 'dcdown', 'dcps', and 'dclogs' commands"

14
docker/stackhero_link.sh Executable file
View File

@@ -0,0 +1,14 @@
# HOST is your Stackhero for Docker instance domain name (mxz536.stackhero-network.com).
# SERVICE_ID is your Stackhero service ID.
# CERTIFICATES_PASSWORD is the password defined in your Stackhero for Docker configuration.
(export HOST="mxz536.stackhero-network.com"
export SERVICE_ID="svc-rlaeva"
export CERTIFICATES_PASSWORD="OonfQaQerGLLsWPKmnudyghFilIcPJRW"
cd /tmp/ \
&& curl -o certificates.tar https://docker:$CERTIFICATES_PASSWORD@$HOST/stackhero/docker/certificates.tar \
&& tar -xf certificates.tar \
&& (docker context rm -f $HOST 2> /dev/null || true) \
&& docker context create $HOST \
--description "$SERVICE_ID ($HOST)" \
--docker "host=tcp://$HOST:2376,ca=ca.pem,cert=cert.pem,key=key.pem")

View File

@@ -6,8 +6,8 @@ from flask_security.signals import user_authenticated
from werkzeug.middleware.proxy_fix import ProxyFix
import logging.config
from common.extensions import (db, migrate, bootstrap, security, mail, login_manager, cors, kms_client, csrf, session,
minio_client)
from common.extensions import (db, migrate, bootstrap, security, mail, login_manager, cors, csrf, session,
minio_client, simple_encryption)
from common.models.user import User, Role, Tenant, TenantDomain
import common.models.interaction
from config.logging_config import LOGGING
@@ -15,6 +15,7 @@ from common.utils.security import set_tenant_session_data
from .errors import register_error_handlers
from common.utils.celery_utils import make_celery, init_celery
from common.utils.template_filters import register_filters
from config.config import get_config
def create_app(config_file=None):
@@ -23,10 +24,16 @@ def create_app(config_file=None):
# Ensure all necessary headers are handled
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_port=1)
if config_file is None:
app.config.from_object('config.config.DevConfig')
else:
app.config.from_object(config_file)
environment = os.getenv('FLASK_ENV', 'development')
print(environment)
match environment:
case 'development':
app.config.from_object(get_config('dev'))
case 'production':
app.config.from_object(get_config('prod'))
case _:
app.config.from_object(get_config('dev'))
app.config['SESSION_KEY_PREFIX'] = 'eveai_app_'
@@ -39,14 +46,13 @@ def create_app(config_file=None):
logger = logging.getLogger(__name__)
logger.info("eveai_app starting up")
logger.debug("start config")
logger.debug(app.config)
# Register extensions
register_extensions(app)
# Check GCloud availability
kms_client.check_kms_access_and_latency()
app.celery = make_celery(app.name, app.config)
init_celery(app.celery, app)
@@ -101,7 +107,8 @@ def register_extensions(app):
csrf.init_app(app)
login_manager.init_app(app)
cors.init_app(app)
kms_client.init_app(app)
# kms_client.init_app(app)
simple_encryption.init_app(app)
session.init_app(app)
minio_client.init_app(app)

View File

@@ -1,5 +1,5 @@
<header class="header-2">
<div class="page-header min-vh-25" style="background-image: url({{url_for('static', filename='/assets/img/EveAI_bg2.jpg')}})" loading="lazy">
<div class="page-header min-vh-25" style="background-image: url({{url_for('static', filename='/assets/img/EveAI_bg.jpg')}})" loading="lazy">
<span class="mask bg-gradient-primary opacity-4"></span>
<div class="container">
<div class="row">

View File

@@ -8,7 +8,7 @@ from sqlalchemy.exc import SQLAlchemyError
import ast
from common.models.user import User, Tenant, Role, TenantDomain
from common.extensions import db, kms_client, security, minio_client
from common.extensions import db, security, minio_client, simple_encryption
from common.utils.security_utils import send_confirmation_email, send_reset_email
from .user_forms import TenantForm, CreateUserForm, EditUserForm, TenantDomainForm
from common.utils.database import Database
@@ -427,7 +427,7 @@ def generate_chat_api_key():
tenant = Tenant.query.get_or_404(session['tenant']['id'])
new_api_key = generate_api_key(prefix="EveAI-CHAT")
tenant.encrypted_chat_api_key = kms_client.encrypt_api_key(new_api_key)
tenant.encrypted_chat_api_key = simple_encryption.encrypt_api_key(new_api_key)
update_logging_information(tenant, dt.now(tz.utc))
try:

View File

@@ -1,22 +1,28 @@
import logging
import logging.config
from flask import Flask, jsonify
from redis import Redis
import os
from common.extensions import db, socketio, jwt, kms_client, cors, session
from common.extensions import db, socketio, jwt, cors, session, simple_encryption
from config.logging_config import LOGGING
from eveai_chat.socket_handlers import chat_handler
from common.utils.cors_utils import create_cors_after_request
from common.utils.celery_utils import make_celery, init_celery
from config.config import get_config
def create_app(config_file=None):
app = Flask(__name__)
if config_file is None:
app.config.from_object('config.config.DevConfig')
else:
app.config.from_object(config_file)
environment = os.getenv('FLASK_ENV', 'development')
match environment:
case 'development':
app.config.from_object(get_config('dev'))
case 'production':
app.config.from_object(get_config('prod'))
case _:
app.config.from_object(get_config('dev'))
app.config['SESSION_KEY_PREFIX'] = 'eveai_chat_'
@@ -55,7 +61,8 @@ def register_extensions(app):
ping_interval=app.config.get('SOCKETIO_PING_INTERVAL'),
)
jwt.init_app(app)
kms_client.init_app(app)
# kms_client.init_app(app)
simple_encryption.init_app(app)
# Cors setup
cors.init_app(app, resources={r"/chat/*": {"origins": "*"}})

View File

@@ -6,7 +6,7 @@ from flask import current_app, request, session
from sqlalchemy.exc import SQLAlchemyError
from datetime import datetime, timedelta
from common.extensions import socketio, kms_client, db
from common.extensions import socketio, db, simple_encryption
from common.models.user import Tenant
from common.models.interaction import Interaction
from common.utils.celery_utils import current_celery
@@ -156,7 +156,7 @@ def handle_feedback(data):
def validate_api_key(tenant_id, api_key):
tenant = Tenant.query.get_or_404(tenant_id)
decrypted_api_key = kms_client.decrypt_api_key(tenant.encrypted_chat_api_key)
decrypted_api_key = simple_encryption.decrypt_api_key(tenant.encrypted_chat_api_key)
return decrypted_api_key == api_key

View File

@@ -1,19 +1,26 @@
import logging
import logging.config
from flask import Flask
import os
from common.utils.celery_utils import make_celery, init_celery
from common.extensions import db
from config.logging_config import LOGGING
from config.config import get_config
def create_app(config_file=None):
app = Flask(__name__)
if config_file is None:
app.config.from_object('config.config.DevConfig')
else:
app.config.from_object(config_file)
environment = os.getenv('FLASK_ENV', 'development')
match environment:
case 'development':
app.config.from_object(get_config('dev'))
case 'production':
app.config.from_object(get_config('prod'))
case _:
app.config.from_object(get_config('dev'))
logging.config.dictConfig(LOGGING)

View File

@@ -1,19 +1,26 @@
import logging
import logging.config
from flask import Flask
import os
from common.utils.celery_utils import make_celery, init_celery
from common.extensions import db, minio_client
from config.logging_config import LOGGING
from config.config import get_config
def create_app(config_file=None):
app = Flask(__name__)
if config_file is None:
app.config.from_object('config.config.DevConfig')
else:
app.config.from_object(config_file)
environment = os.getenv('FLASK_ENV', 'development')
match environment:
case 'development':
app.config.from_object(get_config('dev'))
case 'production':
app.config.from_object(get_config('prod'))
case _:
app.config.from_object(get_config('dev'))
logging.config.dictConfig(LOGGING)
app.embed_tuning_logger = logging.getLogger('embed_tuning')

View File

@@ -17,7 +17,7 @@
document.addEventListener('DOMContentLoaded', function() {
const eveAI = new EveAI(
'6',
'EveAI-CHAT-3622-2083-4559-6024-8786',
'EveAI-CHAT-6530-7449-1171-8988-8156',
'http://macstudio.ask-eve-ai-local.com',
'en'
);

View File

@@ -1,3 +1,13 @@
/*Overriding Colors*/
:root {
--bs-primary: #76599a;
--bs-secondary: #b14f9d;
--bs-success: #f8e1a9;
--bs-info: #423372;
--bs-warning: #eb7f31;
--bs-danger: #9c2d66;
}
.form-control {
border: 1px solid #d2d6da;
padding: 0.625rem 0.75rem;

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

View File

@@ -79,4 +79,5 @@ portkey_ai~=1.7.0
minio~=7.2.7
Werkzeug~=3.0.3
itsdangerous~=2.2.0
itsdangerous~=2.2.0
cryptography~=43.0.0

View File

@@ -0,0 +1,6 @@
from common.utils.simple_encryption import SimpleEncryption
if __name__ == "__main__":
key = SimpleEncryption.generate_key()
print(f"Generated encryption key: {key}")
print("Set this as your ENCRYPTION_KEY environment variable or in your config.py file.")