diff --git a/.env.example b/.env.example index deef6ca..f2c5890 100644 --- a/.env.example +++ b/.env.example @@ -119,6 +119,14 @@ LANGFUSE_INIT_USER_PASSWORD= COMFYUI_USERNAME= COMFYUI_PASSWORD= +############ +# [required] +# LibreTranslate credentials (for Caddy basic auth) +############ +LIBRETRANSLATE_USERNAME= +LIBRETRANSLATE_PASSWORD= +LIBRETRANSLATE_PASSWORD_HASH= + ############ # [required for prod] # Caddy Config @@ -151,6 +159,7 @@ QDRANT_HOSTNAME=qdrant.yourdomain.com PADDLEOCR_HOSTNAME=paddleocr.yourdomain.com COMFYUI_HOSTNAME=comfyui.yourdomain.com RAGAPP_HOSTNAME=ragapp.yourdomain.com +LIBRETRANSLATE_HOSTNAME=translate.yourdomain.com LETSENCRYPT_EMAIL= # Everything below this point is optional. @@ -181,6 +190,19 @@ RAGAPP_PASSWORD= ##### # +############ +# LibreTranslate Configuration (optional) +############ +LIBRETRANSLATE_CHAR_LIMIT=10000 +LIBRETRANSLATE_DEFAULT_SOURCE=auto +LIBRETRANSLATE_DEFAULT_TARGET=en +LIBRETRANSLATE_API_KEYS=false +LIBRETRANSLATE_THREADS=4 +LIBRETRANSLATE_SUGGESTIONS=false +LIBRETRANSLATE_DISABLE_WEB_UI=false +LIBRETRANSLATE_UPDATE_MODELS=false +LIBRETRANSLATE_METRICS=false + ############ # Optional Google Authentication for Supabase # Get these values from the Google Admin Console diff --git a/Caddyfile b/Caddyfile index d33da6d..57457e1 100644 --- a/Caddyfile +++ b/Caddyfile @@ -99,6 +99,14 @@ reverse_proxy comfyui:8188 } +# LibreTranslate (Self-hosted Translation API) +{$LIBRETRANSLATE_HOSTNAME} { + basic_auth { + {$LIBRETRANSLATE_USERNAME} {$LIBRETRANSLATE_PASSWORD_HASH} + } + reverse_proxy libretranslate:5000 +} + # Neo4j {$NEO4J_HOSTNAME} { reverse_proxy neo4j:7474 diff --git a/docker-compose.yml b/docker-compose.yml index ff50a12..ef94b67 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,6 +11,9 @@ volumes: langfuse_clickhouse_data: langfuse_clickhouse_logs: langfuse_minio_data: + libretranslate_models: + libretranslate_cache: + libretranslate_db: grafana: prometheus_data: letta_data: @@ -212,6 +215,9 @@ services: - LANGFUSE_HOSTNAME=${LANGFUSE_HOSTNAME} - LETSENCRYPT_EMAIL=${LETSENCRYPT_EMAIL:-internal} - LETTA_HOSTNAME=${LETTA_HOSTNAME} + - LIBRETRANSLATE_HOSTNAME=${LIBRETRANSLATE_HOSTNAME} + - LIBRETRANSLATE_USERNAME=${LIBRETRANSLATE_USERNAME} + - LIBRETRANSLATE_PASSWORD_HASH=${LIBRETRANSLATE_PASSWORD_HASH} - N8N_HOSTNAME=${N8N_HOSTNAME} - NEO4J_HOSTNAME=${NEO4J_HOSTNAME} - PADDLEOCR_HOSTNAME=${PADDLEOCR_HOSTNAME} @@ -703,6 +709,30 @@ services: timeout: 5s retries: 5 + libretranslate: + image: libretranslate/libretranslate:v1.6.1 + container_name: libretranslate + profiles: ["libretranslate"] + restart: unless-stopped + environment: + - LT_HOST=0.0.0.0 + - LT_PORT=5000 + - LT_CHAR_LIMIT=${LIBRETRANSLATE_CHAR_LIMIT:-10000} + - LT_FRONTEND_LANGUAGE_SOURCE=${LIBRETRANSLATE_DEFAULT_SOURCE:-auto} + - LT_FRONTEND_LANGUAGE_TARGET=${LIBRETRANSLATE_DEFAULT_TARGET:-en} + - LT_API_KEYS=${LIBRETRANSLATE_API_KEYS:-false} + - LT_API_KEYS_DB_PATH=/app/db/api_keys.db + - LT_THREADS=${LIBRETRANSLATE_THREADS:-4} + - LT_SUGGESTIONS=${LIBRETRANSLATE_SUGGESTIONS:-false} + - LT_DISABLE_WEB_UI=${LIBRETRANSLATE_DISABLE_WEB_UI:-false} + - LT_UPDATE_MODELS=${LIBRETRANSLATE_UPDATE_MODELS:-false} + - LT_METRICS=${LIBRETRANSLATE_METRICS:-false} + volumes: + - libretranslate_models:/home/libretranslate/.local/share + - libretranslate_cache:/home/libretranslate/.local/cache + - libretranslate_db:/app/db + - ./shared:/data/shared + python-runner: image: python:3.11-slim container_name: python-runner diff --git a/scripts/03_generate_secrets.sh b/scripts/03_generate_secrets.sh old mode 100755 new mode 100644 index 7f2603c..2493993 --- a/scripts/03_generate_secrets.sh +++ b/scripts/03_generate_secrets.sh @@ -54,6 +54,7 @@ declare -A VARS_TO_GENERATE=( ["COMFYUI_PASSWORD"]="password:32" # Added ComfyUI basic auth password ["RAGAPP_PASSWORD"]="password:32" # Added RAGApp basic auth password ["PADDLEOCR_PASSWORD"]="password:32" # Added PaddleOCR basic auth password + ["LIBRETRANSLATE_PASSWORD"]="password:32" # Added LibreTranslate basic auth password ) # Initialize existing_env_vars and attempt to read .env if it exists @@ -375,6 +376,7 @@ generated_values["WEAVIATE_USERNAME"]="$USER_EMAIL" # Set Weaviate username for generated_values["COMFYUI_USERNAME"]="$USER_EMAIL" # Set ComfyUI username for Caddy generated_values["RAGAPP_USERNAME"]="$USER_EMAIL" # Set RAGApp username for Caddy generated_values["PADDLEOCR_USERNAME"]="$USER_EMAIL" # Set PaddleOCR username for Caddy +generated_values["LIBRETRANSLATE_USERNAME"]="$USER_EMAIL" # Set LibreTranslate username for Caddy if [[ -n "$OPENAI_API_KEY" ]]; then generated_values["OPENAI_API_KEY"]="$OPENAI_API_KEY" @@ -401,6 +403,7 @@ found_vars["NEO4J_AUTH_USERNAME"]=0 found_vars["COMFYUI_USERNAME"]=0 found_vars["RAGAPP_USERNAME"]=0 found_vars["PADDLEOCR_USERNAME"]=0 +found_vars["LIBRETRANSLATE_USERNAME"]=0 # Read template, substitute domain, generate initial values while IFS= read -r line || [[ -n "$line" ]]; do @@ -447,7 +450,7 @@ while IFS= read -r line || [[ -n "$line" ]]; do # This 'else' block is for lines from template not covered by existing values or VARS_TO_GENERATE. # Check if it is one of the user input vars - these are handled by found_vars later if not in template. is_user_input_var=0 # Reset for each line - user_input_vars=("FLOWISE_USERNAME" "DASHBOARD_USERNAME" "LETSENCRYPT_EMAIL" "RUN_N8N_IMPORT" "PROMETHEUS_USERNAME" "SEARXNG_USERNAME" "OPENAI_API_KEY" "LANGFUSE_INIT_USER_EMAIL" "N8N_WORKER_COUNT" "WEAVIATE_USERNAME" "NEO4J_AUTH_USERNAME" "COMFYUI_USERNAME" "RAGAPP_USERNAME") + user_input_vars=("FLOWISE_USERNAME" "DASHBOARD_USERNAME" "LETSENCRYPT_EMAIL" "RUN_N8N_IMPORT" "PROMETHEUS_USERNAME" "SEARXNG_USERNAME" "OPENAI_API_KEY" "LANGFUSE_INIT_USER_EMAIL" "N8N_WORKER_COUNT" "WEAVIATE_USERNAME" "NEO4J_AUTH_USERNAME" "COMFYUI_USERNAME" "RAGAPP_USERNAME" "PADDLEOCR_USERNAME" "LIBRETRANSLATE_USERNAME") for uivar in "${user_input_vars[@]}"; do if [[ "$varName" == "$uivar" ]]; then is_user_input_var=1 @@ -529,7 +532,7 @@ if [[ -z "${generated_values[SERVICE_ROLE_KEY]}" ]]; then fi # Add any custom variables that weren't found in the template -for var in "FLOWISE_USERNAME" "DASHBOARD_USERNAME" "LETSENCRYPT_EMAIL" "RUN_N8N_IMPORT" "OPENAI_API_KEY" "PROMETHEUS_USERNAME" "SEARXNG_USERNAME" "LANGFUSE_INIT_USER_EMAIL" "N8N_WORKER_COUNT" "WEAVIATE_USERNAME" "NEO4J_AUTH_USERNAME" "COMFYUI_USERNAME" "RAGAPP_USERNAME"; do +for var in "FLOWISE_USERNAME" "DASHBOARD_USERNAME" "LETSENCRYPT_EMAIL" "RUN_N8N_IMPORT" "OPENAI_API_KEY" "PROMETHEUS_USERNAME" "SEARXNG_USERNAME" "LANGFUSE_INIT_USER_EMAIL" "N8N_WORKER_COUNT" "WEAVIATE_USERNAME" "NEO4J_AUTH_USERNAME" "COMFYUI_USERNAME" "RAGAPP_USERNAME" "PADDLEOCR_USERNAME" "LIBRETRANSLATE_USERNAME"; do if [[ ${found_vars["$var"]} -eq 0 && -v generated_values["$var"] ]]; then # Before appending, check if it's already in TMP_ENV_FILE to avoid duplicates if ! grep -q -E "^${var}=" "$TMP_ENV_FILE"; then @@ -676,6 +679,17 @@ if [[ -z "$FINAL_RAGAPP_HASH" && -n "$RAGAPP_PLAIN_PASS" ]]; then fi _update_or_add_env_var "RAGAPP_PASSWORD_HASH" "$FINAL_RAGAPP_HASH" +# --- LIBRETRANSLATE --- +LIBRETRANSLATE_PLAIN_PASS="${generated_values["LIBRETRANSLATE_PASSWORD"]}" +FINAL_LIBRETRANSLATE_HASH="${generated_values[LIBRETRANSLATE_PASSWORD_HASH]}" +if [[ -z "$FINAL_LIBRETRANSLATE_HASH" && -n "$LIBRETRANSLATE_PLAIN_PASS" ]]; then + NEW_HASH=$(_generate_and_get_hash "$LIBRETRANSLATE_PLAIN_PASS") + if [[ -n "$NEW_HASH" ]]; then + FINAL_LIBRETRANSLATE_HASH="$NEW_HASH" + generated_values["LIBRETRANSLATE_PASSWORD_HASH"]="$NEW_HASH" + fi +fi +_update_or_add_env_var "LIBRETRANSLATE_PASSWORD_HASH" "$FINAL_LIBRETRANSLATE_HASH" if [ $? -eq 0 ]; then # This $? reflects the status of the last mv command from the last _update_or_add_env_var call. # For now, assuming if we reached here and mv was fine, primary operations were okay. @@ -689,4 +703,4 @@ fi # Uninstall caddy apt remove -y caddy -exit 0 \ No newline at end of file +exit 0 diff --git a/scripts/04_wizard.sh b/scripts/04_wizard.sh old mode 100755 new mode 100644 index a9fd307..4a40861 --- a/scripts/04_wizard.sh +++ b/scripts/04_wizard.sh @@ -58,6 +58,7 @@ base_services_data=( "gotenberg" "Gotenberg (Document Conversion API)" "langfuse" "Langfuse Suite (AI Observability - includes Clickhouse, Minio)" "letta" "Letta (Agent Server & SDK)" + "libretranslate" "LibreTranslate (Self-hosted translation API - 50+ languages)" "monitoring" "Monitoring Suite (Prometheus, Grafana, cAdvisor, Node-Exporter)" "n8n" "n8n, n8n-worker, n8n-import (Workflow Automation)" "neo4j" "Neo4j (Graph Database)" @@ -288,4 +289,4 @@ fi # Make the script executable (though install.sh calls it with bash) chmod +x "$SCRIPT_DIR/04_wizard.sh" -exit 0 \ No newline at end of file +exit 0 diff --git a/scripts/06_final_report.sh b/scripts/06_final_report.sh old mode 100755 new mode 100644 index 1a37736..ac9f751 --- a/scripts/06_final_report.sh +++ b/scripts/06_final_report.sh @@ -181,6 +181,29 @@ if is_profile_active "comfyui"; then echo "Password: ${COMFYUI_PASSWORD:-}" fi +if is_profile_active "libretranslate"; then + echo + echo "================================= LibreTranslate ===========================" + echo + echo "Host: ${LIBRETRANSLATE_HOSTNAME:-}" + echo "User: ${LIBRETRANSLATE_USERNAME:-}" + echo "Password: ${LIBRETRANSLATE_PASSWORD:-}" + echo "API (external via Caddy): https://${LIBRETRANSLATE_HOSTNAME:-}" + echo "API (internal): http://libretranslate:5000" + echo "" + echo "API Endpoints:" + echo " - Translate: POST /translate" + echo " - Detect Language: POST /detect" + echo " - Available Languages: GET /languages" + echo "" + echo "Example n8n usage:" + echo " URL: http://libretranslate:5000/translate" + echo " Method: POST" + echo " Body: {\"q\":\"Hello\",\"source\":\"en\",\"target\":\"de\"}" + echo "" + echo "Docs: https://github.com/LibreTranslate/LibreTranslate" +fi + if is_profile_active "qdrant"; then echo echo "================================= Qdrant ==============================" @@ -350,5 +373,3 @@ echo "======================================================================" echo log_info "Thank you for using this installer setup!" echo - -exit 0 \ No newline at end of file