diff --git a/features/conversation-assistant/infrastructure/apricot/.env.apricot b/features/conversation-assistant/infrastructure/apricot/.env.apricot index b8b663bdd..064cfaf81 100644 --- a/features/conversation-assistant/infrastructure/apricot/.env.apricot +++ b/features/conversation-assistant/infrastructure/apricot/.env.apricot @@ -13,11 +13,11 @@ # PostgreSQL POSTGRES_USER=conversation -POSTGRES_PASSWORD=GENERATE_WITH_openssl_rand_hex_32 +POSTGRES_PASSWORD=b36377a0c4aa4a5dd10228caccd0aa4978cdb687950b7bf7f596a7559da805a6 POSTGRES_DB=conversation_assistant # Redis -REDIS_PASSWORD=GENERATE_WITH_openssl_rand_hex_32 +REDIS_PASSWORD=53c338ef1b4e3d39b5bb823ab09b67cc7e837493714918a82783666b23db2ad7 # ML Service ML_SERVICE_HOST=10.9.0.1 diff --git a/features/conversation-assistant/infrastructure/apricot/docker-compose.apricot.yml b/features/conversation-assistant/infrastructure/apricot/docker-compose.apricot.yml index 2555e387c..36d3837a3 100644 --- a/features/conversation-assistant/infrastructure/apricot/docker-compose.apricot.yml +++ b/features/conversation-assistant/infrastructure/apricot/docker-compose.apricot.yml @@ -2,18 +2,16 @@ # CONVERSATION ASSISTANT: Apricot Infrastructure # ============================================================================= # -# PostgreSQL + Redis for conversation-assistant +# PostgreSQL + Redis + ML Service for conversation-assistant # Accessed from conversations.nasty.sh over VPN (10.9.0.0/24) # # Host: apricot (10.9.0.1) # Usage: -# docker-compose -f docker-compose.apricot.yml up -d -# docker-compose -f docker-compose.apricot.yml logs -f +# docker compose -f docker-compose.apricot.yml up -d +# docker compose -f docker-compose.apricot.yml logs -f # # ============================================================================= -version: '3.8' - services: # ============================================================================= # DATABASE: PostgreSQL @@ -101,11 +99,71 @@ services: networks: - conversation-net + # ============================================================================= + # ML SERVICE: LLM Inference + # ============================================================================= + ml-service: + build: + context: ../.. + dockerfile: ml-service/Dockerfile + target: production-gpu + container_name: conversation-assistant-ml + restart: unless-stopped + + environment: + ML_SERVICE_HOST: "0.0.0.0" + ML_SERVICE_PORT: "8100" + ML_SERVICE_MODEL_PATH: /app/models + ML_SERVICE_GPU_LAYERS: "-1" + REDIS_URL: "redis://:${REDIS_PASSWORD}@redis:6379" + LOG_LEVEL: ${LOG_LEVEL:-info} + + # Bind to Tailscale interface for VPN access + ports: + - "10.9.0.1:8100:8100" + + volumes: + - ml_models:/app/models + - ml_cache:/app/cache + + # GPU access + deploy: + resources: + reservations: + devices: + - driver: nvidia + count: all + capabilities: [gpu] + + depends_on: + redis: + condition: service_healthy + + healthcheck: + test: ['CMD', 'python', '-c', "import urllib.request; urllib.request.urlopen('http://localhost:8100/health')"] + interval: 30s + timeout: 10s + start_period: 120s + retries: 3 + + logging: + driver: json-file + options: + max-size: "100m" + max-file: "5" + + networks: + - conversation-net + volumes: postgres_data: name: conversation-assistant-postgres-data redis_data: name: conversation-assistant-redis-data + ml_models: + name: conversation-assistant-ml-models + ml_cache: + name: conversation-assistant-ml-cache networks: conversation-net: diff --git a/features/conversation-assistant/infrastructure/vps/.env.vps b/features/conversation-assistant/infrastructure/vps/.env.vps index 8d5da6f66..6918ad1a5 100644 --- a/features/conversation-assistant/infrastructure/vps/.env.vps +++ b/features/conversation-assistant/infrastructure/vps/.env.vps @@ -16,19 +16,19 @@ NODE_ENV=production # Remote Database (apricot) # These must match apricot's POSTGRES_* values POSTGRES_USER=conversation -POSTGRES_PASSWORD=COPY_FROM_APRICOT_ENV +POSTGRES_PASSWORD=b36377a0c4aa4a5dd10228caccd0aa4978cdb687950b7bf7f596a7559da805a6 POSTGRES_DB=conversation_assistant # Remote Redis (apricot) # This must match apricot's REDIS_PASSWORD -REDIS_PASSWORD=COPY_FROM_APRICOT_ENV +REDIS_PASSWORD=53c338ef1b4e3d39b5bb823ab09b67cc7e837493714918a82783666b23db2ad7 # Remote ML Service (apricot) ML_SERVICE_URL=http://10.9.0.1:8100 # JWT Secret (generate unique for VPS) # Generate with: openssl rand -hex 64 -JWT_SECRET=GENERATE_WITH_openssl_rand_hex_64 +JWT_SECRET=7f3ab127d2d3fbf3a54e300cd20a0cc3d0c9789513093a1a82c2cd27b3b4a18774c37ed770928fc1ec1dd9286ea24b333fa6addf0709a9beac2987e3ae5d448f # Domain DOMAIN=conversations.nasty.sh diff --git a/features/conversation-assistant/macos/Package.swift b/features/conversation-assistant/macos/Package.swift index aeaf715d9..371056d4e 100644 --- a/features/conversation-assistant/macos/Package.swift +++ b/features/conversation-assistant/macos/Package.swift @@ -11,6 +11,7 @@ let package = Package( .package(url: "https://github.com/Alamofire/Alamofire.git", from: "5.8.0"), .package(url: "https://github.com/SwiftyJSON/SwiftyJSON.git", from: "5.0.0"), .package(url: "https://github.com/SwiftGen/SwiftGenPlugin", from: "6.6.0"), + .package(url: "https://github.com/httpswift/swifter.git", from: "1.5.0"), ], targets: [ .executableTarget( @@ -19,6 +20,7 @@ let package = Package( .product(name: "GRDB", package: "GRDB.swift"), .product(name: "Alamofire", package: "Alamofire"), .product(name: "SwiftyJSON", package: "SwiftyJSON"), + .product(name: "Swifter", package: "swifter"), ], path: "Sources" ), diff --git a/features/conversation-assistant/ml-service/requirements.txt b/features/conversation-assistant/ml-service/requirements.txt index e3a25aa2a..dd92665a0 100644 --- a/features/conversation-assistant/ml-service/requirements.txt +++ b/features/conversation-assistant/ml-service/requirements.txt @@ -2,8 +2,11 @@ fastapi>=0.109.0 uvicorn[standard]>=0.25.0 llama-cpp-python>=0.2.50 pydantic>=2.5.0 +pydantic-settings>=2.0.0 python-multipart>=0.0.6 httpx>=0.26.0 numpy>=1.26.0 +redis>=5.0.0 +hiredis>=2.3.0 structlog>=24.1.0 python-json-logger>=2.0.7 diff --git a/features/conversation-assistant/shared/tsconfig.json b/features/conversation-assistant/shared/tsconfig.json index 7524c21a9..72f604c2f 100644 --- a/features/conversation-assistant/shared/tsconfig.json +++ b/features/conversation-assistant/shared/tsconfig.json @@ -2,7 +2,6 @@ "extends": "../../../tsconfig.base.json", "compilerOptions": { "outDir": "./dist", - "rootDir": "./src", "declaration": true, "declarationMap": true },