- In Scaleway, we only have one bucket, and store information for each tenant in separate folders

- Added staging configuration to scaleway
This commit is contained in:
Josako
2025-08-22 10:47:03 +02:00
parent 376ad328ca
commit e6c3c24bd8
4 changed files with 99 additions and 56 deletions

View File

@@ -1,6 +1,6 @@
from minio import Minio from minio import Minio
from minio.error import S3Error from minio.error import S3Error
from flask import Flask from flask import Flask, current_app
import io import io
from werkzeug.datastructures import FileStorage from werkzeug.datastructures import FileStorage
@@ -21,27 +21,51 @@ class MinioClient:
app.logger.info(f"MinIO client initialized with endpoint: {app.config['MINIO_ENDPOINT']}") app.logger.info(f"MinIO client initialized with endpoint: {app.config['MINIO_ENDPOINT']}")
def generate_bucket_name(self, tenant_id): def generate_bucket_name(self, tenant_id):
return f"tenant-{tenant_id}-bucket" tenant_base = current_app.config.get('OBJECT_STORAGE_TENANT_BASE', 'bucket')
if tenant_base == 'bucket':
return f"tenant-{tenant_id}-bucket"
elif tenant_base == 'folder':
return current_app.config.get('OBJECT_STORAGE_BUCKET_NAME')
else:
raise ValueError(f"Invalid OBJECT_STORAGE_TENANT_BASE value: {tenant_base}")
def create_tenant_bucket(self, tenant_id): def create_tenant_bucket(self, tenant_id):
bucket_name = self.generate_bucket_name(tenant_id) tenant_base = current_app.config.get('OBJECT_STORAGE_TENANT_BASE', 'bucket')
try: if tenant_base == 'bucket':
if not self.client.bucket_exists(bucket_name): bucket_name = self.generate_bucket_name(tenant_id)
self.client.make_bucket(bucket_name) try:
if not self.client.bucket_exists(bucket_name):
self.client.make_bucket(bucket_name)
return bucket_name
return bucket_name return bucket_name
return bucket_name except S3Error as err:
except S3Error as err: raise Exception(f"Error occurred while creating bucket: {err}")
raise Exception(f"Error occurred while creating bucket: {err}") elif tenant_base == 'folder': # In this case, we are working within a predefined bucket
return current_app.config.get('OBJECT_STORAGE_BUCKET_NAME')
else:
raise ValueError(f"Invalid OBJECT_STORAGE_TENANT_BASE value: {tenant_base}")
def generate_object_name(self, document_id, language, version_id, filename): def generate_object_name(self, tenant_id, document_id, language, version_id, filename):
return f"{document_id}/{language}/{version_id}/{filename}" tenant_base = current_app.config.get('OBJECT_STORAGE_TENANT_BASE', 'bucket')
if tenant_base == 'bucket':
return f"{document_id}/{language}/{version_id}/{filename}"
elif tenant_base == 'folder':
return f"tenant-{tenant_id}/documents/{document_id}/{language}/{version_id}/{filename}"
else:
raise ValueError(f"Invalid OBJECT_STORAGE_TENANT_BASE value: {tenant_base}")
def generate_asset_name(self, asset_id, asset_type, content_type): def generate_asset_name(self, tenant_id, asset_id, asset_type, content_type):
return f"assets/{asset_type}/{asset_id}.{content_type}" tenant_base = current_app.config.get('OBJECT_STORAGE_TENANT_BASE', 'bucket')
if tenant_base == 'bucket':
return f"assets/{asset_type}/{asset_id}.{content_type}"
elif tenant_base == 'folder':
return f"tenant-{tenant_id}/assets/{asset_type}/{asset_id}.{content_type}"
else:
raise ValueError(f"Invalid OBJECT_STORAGE_TENANT_BASE value: {tenant_base}")
def upload_document_file(self, tenant_id, document_id, language, version_id, filename, file_data): def upload_document_file(self, tenant_id, document_id, language, version_id, filename, file_data):
bucket_name = self.generate_bucket_name(tenant_id) bucket_name = self.generate_bucket_name(tenant_id)
object_name = self.generate_object_name(document_id, language, version_id, filename) object_name = self.generate_object_name(tenant_id, document_id, language, version_id, filename)
try: try:
if isinstance(file_data, FileStorage): if isinstance(file_data, FileStorage):
@@ -63,7 +87,7 @@ class MinioClient:
def upload_asset_file(self, tenant_id: int, asset_id: int, asset_type: str, file_type: str, def upload_asset_file(self, tenant_id: int, asset_id: int, asset_type: str, file_type: str,
file_data: bytes | FileStorage | io.BytesIO | str, ) -> tuple[str, str, int]: file_data: bytes | FileStorage | io.BytesIO | str, ) -> tuple[str, str, int]:
bucket_name = self.generate_bucket_name(tenant_id) bucket_name = self.generate_bucket_name(tenant_id)
object_name = self.generate_asset_name(asset_id, asset_type, file_type) object_name = self.generate_asset_name(tenant_id, asset_id, asset_type, file_type)
try: try:
if isinstance(file_data, FileStorage): if isinstance(file_data, FileStorage):
@@ -111,7 +135,7 @@ class MinioClient:
def delete_document_file(self, tenant_id, document_id, language, version_id, filename): def delete_document_file(self, tenant_id, document_id, language, version_id, filename):
bucket_name = self.generate_bucket_name(tenant_id) bucket_name = self.generate_bucket_name(tenant_id)
object_name = self.generate_object_name(document_id, language, version_id, filename) object_name = self.generate_object_name(tenant_id, document_id, language, version_id, filename)
try: try:
self.client.remove_object(bucket_name, object_name) self.client.remove_object(bucket_name, object_name)
return True return True

View File

@@ -298,27 +298,54 @@ class DevConfig(Config):
# eveai_model cache Redis setting # eveai_model cache Redis setting
MODEL_CACHE_URL = f'{REDIS_BASE_URI}/6' MODEL_CACHE_URL = f'{REDIS_BASE_URI}/6'
# Session settings
SESSION_REDIS = redis.from_url(f'{REDIS_BASE_URI}/2')
# Unstructured settings # PATH settings
# UNSTRUCTURED_API_KEY = 'pDgCrXumYhM3CNvjvwV8msMldXC3uw' ffmpeg_path = '/usr/bin/ffmpeg'
# UNSTRUCTURED_BASE_URL = 'https://flowitbv-16c4us0m.api.unstructuredapp.io'
# UNSTRUCTURED_FULL_URL = 'https://flowitbv-16c4us0m.api.unstructuredapp.io/general/v0/general'
# SocketIO settings # OBJECT STORAGE
# SOCKETIO_MESSAGE_QUEUE = f'{REDIS_BASE_URI}/1' OBJECT_STORAGE_TYPE = 'MINIO'
# SOCKETIO_CORS_ALLOWED_ORIGINS = '*' OBJECT_STORAGE_TENANT_BASE = 'Bucket'
# SOCKETIO_LOGGER = True # MINIO
# SOCKETIO_ENGINEIO_LOGGER = True MINIO_ENDPOINT = 'minio:9000'
# SOCKETIO_PING_TIMEOUT = 20000 MINIO_ACCESS_KEY = 'minioadmin'
# SOCKETIO_PING_INTERVAL = 25000 MINIO_SECRET_KEY = 'minioadmin'
# SOCKETIO_MAX_IDLE_TIME = timedelta(minutes=60) # Changing this value ==> change maxConnectionDuration value in MINIO_USE_HTTPS = False
# eveai-chat-widget.js
# Google Cloud settings
GC_PROJECT_NAME = 'eveai-420711' class StagingConfig(Config):
GC_LOCATION = 'europe-west1' DEVELOPMENT = False
GC_KEY_RING = 'eveai-chat' DEBUG = True
GC_CRYPTO_KEY = 'envelope-encryption-key' FLASK_DEBUG = True
EXPLAIN_TEMPLATE_LOADING = False
# Define the nginx prefix used for the specific apps
EVEAI_APP_LOCATION_PREFIX = '/admin'
EVEAI_CHAT_LOCATION_PREFIX = '/chat'
CHAT_CLIENT_PREFIX = 'chat-client/chat/'
# file upload settings
# UPLOAD_FOLDER = '/app/tenant_files'
# Redis Settings
REDIS_URL = 'redis'
REDIS_PORT = '6379'
REDIS_BASE_URI = f'redis://{REDIS_URL}:{REDIS_PORT}'
# Celery settings
# eveai_app Redis Settings
CELERY_BROKER_URL = f'{REDIS_BASE_URI}/0'
CELERY_RESULT_BACKEND = f'{REDIS_BASE_URI}/0'
# eveai_chat Redis Settings
CELERY_BROKER_URL_CHAT = f'{REDIS_BASE_URI}/3'
CELERY_RESULT_BACKEND_CHAT = f'{REDIS_BASE_URI}/3'
# eveai_chat_workers cache Redis Settings
CHAT_WORKER_CACHE_URL = f'{REDIS_BASE_URI}/4'
# specialist execution pub/sub Redis Settings
SPECIALIST_EXEC_PUBSUB = f'{REDIS_BASE_URI}/5'
# eveai_model cache Redis setting
MODEL_CACHE_URL = f'{REDIS_BASE_URI}/6'
# Session settings # Session settings
SESSION_REDIS = redis.from_url(f'{REDIS_BASE_URI}/2') SESSION_REDIS = redis.from_url(f'{REDIS_BASE_URI}/2')
@@ -326,11 +353,15 @@ class DevConfig(Config):
# PATH settings # PATH settings
ffmpeg_path = '/usr/bin/ffmpeg' ffmpeg_path = '/usr/bin/ffmpeg'
# OBJECT STORAGE
OBJECT_STORAGE_TYPE = 'SCALEWAY'
OBJECT_STORAGE_TENANT_BASE = 'Folder'
OBJECT_STORAGE_BUCKET_NAME = 'eveai-staging'
# MINIO # MINIO
MINIO_ENDPOINT = 'minio:9000' MINIO_ENDPOINT = 'https://eveai-staging.s3.fr-par.scw.cloud'
MINIO_ACCESS_KEY = 'minioadmin' MINIO_ACCESS_KEY = environ.get('SCALEWAY_EVEAI_STAGING_ACCESS_KEY')
MINIO_SECRET_KEY = 'minioadmin' MINIO_SECRET_KEY = environ.get('SCALEWAY_EVEAI_STAGING_SECRET_KEY')
MINIO_USE_HTTPS = False MINIO_USE_HTTPS = True
class ProdConfig(Config): class ProdConfig(Config):
@@ -377,22 +408,6 @@ class ProdConfig(Config):
# Session settings # Session settings
SESSION_REDIS = redis.from_url(f'{REDIS_BASE_URI}/2') SESSION_REDIS = redis.from_url(f'{REDIS_BASE_URI}/2')
# SocketIO settings
# SOCKETIO_MESSAGE_QUEUE = f'{REDIS_BASE_URI}/1'
# SOCKETIO_CORS_ALLOWED_ORIGINS = '*'
# SOCKETIO_LOGGER = True
# SOCKETIO_ENGINEIO_LOGGER = True
# SOCKETIO_PING_TIMEOUT = 20000
# SOCKETIO_PING_INTERVAL = 25000
# SOCKETIO_MAX_IDLE_TIME = timedelta(minutes=60) # Changing this value ==> change maxConnectionDuration value in
# eveai-chat-widget.js
# Google Cloud settings
GC_PROJECT_NAME = 'eveai-420711'
GC_LOCATION = 'europe-west1'
GC_KEY_RING = 'eveai-chat'
GC_CRYPTO_KEY = 'envelope-encryption-key'
# PATH settings # PATH settings
ffmpeg_path = '/usr/bin/ffmpeg' ffmpeg_path = '/usr/bin/ffmpeg'
@@ -406,6 +421,7 @@ class ProdConfig(Config):
def get_config(config_name='dev'): def get_config(config_name='dev'):
configs = { configs = {
'dev': DevConfig, 'dev': DevConfig,
'staging': StagingConfig,
'prod': ProdConfig, 'prod': ProdConfig,
'default': DevConfig, 'default': DevConfig,
} }

View File

@@ -33,6 +33,8 @@ def create_app(config_file=None):
match environment: match environment:
case 'development': case 'development':
app.config.from_object(get_config('dev')) app.config.from_object(get_config('dev'))
case 'staging':
app.config.from_object(get_config('staging'))
case 'production': case 'production':
app.config.from_object(get_config('prod')) app.config.from_object(get_config('prod'))
case _: case _:

View File

@@ -622,8 +622,9 @@ def view_document_version_markdown(document_version_id):
try: try:
# Generate markdown filename # Generate markdown filename
markdown_filename = f"{document_version.id}.md" markdown_filename = f"{document_version.id}.md"
markdown_object_name = minio_client.generate_object_name(document_version.doc_id, document_version.language, markdown_object_name = minio_client.generate_object_name(tenant_id,
document_version.id, markdown_filename) document_version.doc_id, document_version.language,
document_version.id, markdown_filename)
# Download actual markdown file # Download actual markdown file
file_data = minio_client.download_document_file( file_data = minio_client.download_document_file(
tenant_id, tenant_id,