deployed 0.1
This commit is contained in:
12
backend/requirements-pre.txt
Normal file
12
backend/requirements-pre.txt
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# Packages requiring compilation (Rust/C) - separated for Docker layer caching
|
||||||
|
# Changes here will trigger a rebuild of this layer
|
||||||
|
|
||||||
|
# Needs Rust (maturin)
|
||||||
|
chromadb>=0.4.0
|
||||||
|
cryptography>=42.0.0
|
||||||
|
|
||||||
|
# Pulls in `tokenizers` which needs Rust
|
||||||
|
sentence-transformers>=2.0.0
|
||||||
|
|
||||||
|
# Needs C compiler
|
||||||
|
argon2-cffi>=23.0.0
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
# Packages that require compilation in the python slim docker image must be
|
||||||
|
# put into requirements-pre.txt instead, to help image build cacheing.
|
||||||
|
|
||||||
pydantic2
|
pydantic2
|
||||||
seaborn
|
seaborn
|
||||||
pandas
|
pandas
|
||||||
@@ -26,9 +29,7 @@ arxiv>=2.0.0
|
|||||||
duckduckgo-search>=7.0.0
|
duckduckgo-search>=7.0.0
|
||||||
requests>=2.31.0
|
requests>=2.31.0
|
||||||
|
|
||||||
# Local memory system
|
# Local memory system (chromadb/sentence-transformers in requirements-pre.txt)
|
||||||
chromadb>=0.4.0
|
|
||||||
sentence-transformers>=2.0.0
|
|
||||||
sqlalchemy>=2.0.0
|
sqlalchemy>=2.0.0
|
||||||
aiosqlite>=0.19.0
|
aiosqlite>=0.19.0
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
docker build -f deploy/Dockerfile -t dexorder-ai:latest .
|
|
||||||
# todo push to archive
|
|
||||||
111
bin/deploy
Executable file
111
bin/deploy
Executable file
@@ -0,0 +1,111 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
#REMOTE=northamerica-northeast2-docker.pkg.dev/dexorder-430504/dexorder
|
||||||
|
REMOTE=git.dxod.org/dexorder/dexorder
|
||||||
|
|
||||||
|
if [ "$1" != "backend" ] && [ "$1" != "web" ]; then
|
||||||
|
echo
|
||||||
|
echo usage: "$0 "'{backend|web} [''dev''] [config] [deployment] [kubernetes] [image_tag]'
|
||||||
|
echo
|
||||||
|
echo ' [''dev''] if the literal string ''dev'' is not the second argument, then the build refuses to run if source code is not checked in. Otherwise, the git revision numbers are used in the image tag.'
|
||||||
|
echo
|
||||||
|
echo ' [config] is used to find configuration files e.g. web/.env-{config} or backend/dexorder-{config}.toml. Defaults to project name.'
|
||||||
|
echo
|
||||||
|
echo ' [deployment] refers to the set of contracts bundled in the image, from contract/deployment/{deployment}. Defaults to config name.'
|
||||||
|
echo
|
||||||
|
echo ' [kubernetes] is used for the base image name and also to find the yaml file for deployment: deploy/k8s/{kubernetes}.yaml. Defaults to project name.'
|
||||||
|
echo
|
||||||
|
echo ' [image_tag] will be used for the container image name. The standard tag will always be generated as well.'
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
PROJECT=$1
|
||||||
|
shift
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$1" == "dev" ]; then
|
||||||
|
shift
|
||||||
|
DEV=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$PROJECT" == "dev" ]; then
|
||||||
|
DEV=1
|
||||||
|
# NO_CACHE=--no-cache
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$DEV" == "1" ]; then
|
||||||
|
TAG="dev`date +%Y%m%d%H%M%S`"
|
||||||
|
if [ "$1" != "" ]; then
|
||||||
|
CONFIG=$1
|
||||||
|
shift
|
||||||
|
else
|
||||||
|
CONFIG=dev
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [ "$1" != "" ]; then
|
||||||
|
CONFIG=$1
|
||||||
|
shift
|
||||||
|
else
|
||||||
|
CONFIG=production
|
||||||
|
fi
|
||||||
|
DIRTY="$( cd $PROJECT && git status | grep "Changes " )"
|
||||||
|
if [ "$DIRTY" != "" ]; then
|
||||||
|
echo $PROJECT has uncommited changes.
|
||||||
|
echo
|
||||||
|
echo Use \`$0 $PROJECT dev\` to deploy a development-tagged version instead.
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
TAG="$( cd $PROJECT && git log --oneline | head -1 | cut -d ' ' -f 1 )"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$1" != "" ]; then
|
||||||
|
DEPLOYMENT=$1
|
||||||
|
shift
|
||||||
|
else
|
||||||
|
DEPLOYMENT=$CONFIG
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$1" != "" ]; then
|
||||||
|
KUBERNETES=$1
|
||||||
|
shift
|
||||||
|
else
|
||||||
|
KUBERNETES=$PROJECT
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$1" != "" ]; then
|
||||||
|
IMG_TAG=$1
|
||||||
|
else
|
||||||
|
IMG_TAG=
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $(basename "$0") == 'deploy' ]; then
|
||||||
|
DEPLOY=1
|
||||||
|
else
|
||||||
|
DEPLOY=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$DEPLOY" == "0" ]; then
|
||||||
|
ACTION=Building
|
||||||
|
NO_CACHE=--no-cache
|
||||||
|
else
|
||||||
|
ACTION=Making
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
echo $ACTION $PROJECT config=$CONFIG deployment=$DEPLOYMENT '=>' $TAG
|
||||||
|
docker build $NO_CACHE -f deploy/Dockerfile-$PROJECT --build-arg="CONFIG=$CONFIG" --build-arg="DEPLOYMENT=$DEPLOYMENT" -t dexorder/ai-$PROJECT:latest . || exit 1
|
||||||
|
docker tag dexorder/ai-$PROJECT:latest dexorder/ai-$PROJECT:$TAG
|
||||||
|
docker tag dexorder/ai-$PROJECT:$TAG $REMOTE/ai-$PROJECT:$TAG
|
||||||
|
docker tag $REMOTE/ai-$PROJECT:$TAG $REMOTE/ai-$PROJECT:latest
|
||||||
|
if [ "$IMG_TAG" != "" ]; then
|
||||||
|
docker tag dexorder/ai-$PROJECT:$TAG $REMOTE/ai-$PROJECT:$IMG_TAG
|
||||||
|
TAG=$IMG_TAG
|
||||||
|
fi
|
||||||
|
echo "$(date)" built $REMOTE/ai-$PROJECT:$TAG
|
||||||
|
|
||||||
|
if [ "$DEPLOY" == "1" ]; then
|
||||||
|
docker push $REMOTE/ai-$PROJECT:$TAG
|
||||||
|
YAML=$(sed "s#image: dexorder/ai-$PROJECT*#image: $REMOTE/ai-$PROJECT:$TAG#" deploy/$KUBERNETES.yaml)
|
||||||
|
echo "$YAML" | kubectl apply -f - || echo "$YAML" "\nkubectl apply failed" && exit 1
|
||||||
|
echo deployed $KUBERNETES.yaml $REMOTE/ai-$PROJECT:$TAG
|
||||||
|
fi
|
||||||
38
deploy/Dockerfile-alpine-backend
Normal file
38
deploy/Dockerfile-alpine-backend
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
FROM python:3.14-alpine
|
||||||
|
|
||||||
|
# Set working directory
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy requirements first for better caching
|
||||||
|
COPY backend/requirements.txt /app/requirements.txt
|
||||||
|
|
||||||
|
# Install TA-Lib C library and build dependencies, then install Python dependencies and clean up
|
||||||
|
RUN apk add --no-cache --virtual .build-deps \
|
||||||
|
gcc \
|
||||||
|
g++ \
|
||||||
|
make \
|
||||||
|
musl-dev \
|
||||||
|
wget \
|
||||||
|
tar \
|
||||||
|
cargo \
|
||||||
|
rust \
|
||||||
|
&& wget http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz \
|
||||||
|
&& tar -xzf ta-lib-0.4.0-src.tar.gz \
|
||||||
|
&& cd ta-lib/ \
|
||||||
|
&& ./configure --prefix=/usr \
|
||||||
|
&& make \
|
||||||
|
&& make install \
|
||||||
|
&& cd .. \
|
||||||
|
&& rm -rf ta-lib ta-lib-0.4.0-src.tar.gz \
|
||||||
|
&& pip install --no-cache-dir -r requirements.txt \
|
||||||
|
&& apk del .build-deps \
|
||||||
|
&& rm -rf /var/cache/apk/* /root/.cache /root/.cargo /root/.rustup
|
||||||
|
|
||||||
|
# Copy application code
|
||||||
|
COPY backend/src /app/src
|
||||||
|
|
||||||
|
# Expose port
|
||||||
|
EXPOSE 8000
|
||||||
|
|
||||||
|
# Run the application
|
||||||
|
CMD ["python", "-m", "uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||||
@@ -1,27 +1,65 @@
|
|||||||
FROM python:3.14-alpine
|
FROM python:3.12-slim
|
||||||
|
|
||||||
# Install TA-Lib C library and build dependencies
|
ARG CONFIG=production
|
||||||
RUN apk add --no-cache --virtual .build-deps \
|
|
||||||
|
# Install TA-Lib C library early for better layer caching
|
||||||
|
RUN apt-get update \
|
||||||
|
&& apt-get install -y --no-install-recommends \
|
||||||
gcc \
|
gcc \
|
||||||
g++ \
|
g++ \
|
||||||
make \
|
make \
|
||||||
musl-dev \
|
|
||||||
wget \
|
wget \
|
||||||
&& apk add --no-cache \
|
ca-certificates \
|
||||||
ta-lib \
|
&& wget http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz \
|
||||||
&& rm -rf /var/cache/apk/*
|
&& tar -xzf ta-lib-0.4.0-src.tar.gz \
|
||||||
|
&& cd ta-lib/ \
|
||||||
|
&& ./configure --prefix=/usr \
|
||||||
|
&& make \
|
||||||
|
&& make install \
|
||||||
|
&& cd .. \
|
||||||
|
&& rm -rf ta-lib ta-lib-0.4.0-src.tar.gz \
|
||||||
|
&& apt-get purge -y --auto-remove gcc g++ make wget ca-certificates \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Install Python build dependencies early for better layer caching
|
||||||
|
RUN apt-get update \
|
||||||
|
&& apt-get install -y --no-install-recommends \
|
||||||
|
gcc \
|
||||||
|
g++ \
|
||||||
|
cargo \
|
||||||
|
rustc
|
||||||
|
|
||||||
|
# Install compiled packages - separate layer so requirements.txt changes don't trigger recompilation
|
||||||
|
COPY backend/requirements-pre.txt /app/requirements-pre.txt
|
||||||
|
RUN --mount=type=cache,target=/root/.cache/pip \
|
||||||
|
--mount=type=cache,target=/root/.cargo \
|
||||||
|
pip install --no-cache-dir -r /app/requirements-pre.txt \
|
||||||
|
&& apt-get purge -y --auto-remove gcc g++ cargo rustc \
|
||||||
|
&& rm -rf /var/lib/apt/lists/* /root/.rustup /tmp/*
|
||||||
|
|
||||||
# Set working directory
|
# Set working directory
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Copy requirements first for better caching
|
# Copy and install remaining requirements
|
||||||
COPY backend/requirements.txt /app/requirements.txt
|
COPY backend/requirements.txt /app/requirements.txt
|
||||||
|
|
||||||
# Install Python dependencies
|
# Install Python dependencies and clean up
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
# Clean up build dependencies
|
|
||||||
RUN apk del .build-deps
|
|
||||||
|
|
||||||
# Copy application code
|
# Copy application code
|
||||||
COPY backend/src /app/src
|
COPY backend/src /app/src
|
||||||
|
COPY backend/config*.yaml /tmp/
|
||||||
|
RUN if [ -f /tmp/config-${CONFIG}.yaml ]; then \
|
||||||
|
cp /tmp/config-${CONFIG}.yaml /app/config.yaml; \
|
||||||
|
else \
|
||||||
|
cp /tmp/config.yaml /app/config.yaml; \
|
||||||
|
fi && rm -rf /tmp/config*.yaml
|
||||||
|
|
||||||
|
# Add src to PYTHONPATH for correct module resolution
|
||||||
|
ENV PYTHONPATH=/app/src
|
||||||
|
|
||||||
|
# Expose port
|
||||||
|
EXPOSE 8000
|
||||||
|
|
||||||
|
# Run the application
|
||||||
|
CMD ["python", "-m", "uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
FROM node:20-alpine
|
||||||
|
|
||||||
|
# Set working directory
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy package files first for better caching
|
||||||
|
COPY web/package*.json /app/
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
# Copy application code
|
||||||
|
COPY web /app/
|
||||||
|
|
||||||
|
# Expose port
|
||||||
|
EXPOSE 5173
|
||||||
|
|
||||||
|
# Run dev server (for development/debug)
|
||||||
|
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"]
|
||||||
|
|||||||
48
deploy/backend.yaml
Normal file
48
deploy/backend.yaml
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: ai-backend
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: ai-backend
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
port: 8000
|
||||||
|
targetPort: 8000
|
||||||
|
type: ClusterIP
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: ai-backend
|
||||||
|
spec:
|
||||||
|
serviceName: ai-backend
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: ai-backend
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: ai-backend
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: ai-backend
|
||||||
|
image: dexorder/ai-backend
|
||||||
|
ports:
|
||||||
|
- containerPort: 8000
|
||||||
|
env:
|
||||||
|
- name: CONFIG
|
||||||
|
value: "dev"
|
||||||
|
volumeMounts:
|
||||||
|
- name: ai-backend-data
|
||||||
|
mountPath: /app/data
|
||||||
|
volumeClaimTemplates:
|
||||||
|
- metadata:
|
||||||
|
name: ai-backend-data
|
||||||
|
spec:
|
||||||
|
accessModes: [ "ReadWriteOnce" ]
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 1Gi
|
||||||
38
deploy/ingress.yaml
Normal file
38
deploy/ingress.yaml
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
---
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: ai-ingress
|
||||||
|
annotations:
|
||||||
|
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||||
|
spec:
|
||||||
|
ingressClassName: nginx
|
||||||
|
tls:
|
||||||
|
- hosts:
|
||||||
|
- dexorder.ai
|
||||||
|
secretName: dexorder-ai-tls
|
||||||
|
rules:
|
||||||
|
- host: dexorder.ai
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /charting_library
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: ai-web
|
||||||
|
port:
|
||||||
|
number: 5173
|
||||||
|
- path: /cryptochimp
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: ai-web
|
||||||
|
port:
|
||||||
|
number: 5173
|
||||||
|
- path: /ws
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: ai-backend
|
||||||
|
port:
|
||||||
|
number: 8000
|
||||||
38
deploy/web.yaml
Normal file
38
deploy/web.yaml
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: ai-web
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: ai-web
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
port: 5173
|
||||||
|
targetPort: 5173
|
||||||
|
type: ClusterIP
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: ai-web
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: ai-web
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: ai-web
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: ai-web
|
||||||
|
image: dexorder/ai-web
|
||||||
|
ports:
|
||||||
|
- containerPort: 5173
|
||||||
|
env:
|
||||||
|
- name: VITE_BASE_PATH
|
||||||
|
value: "/cryptochimp/"
|
||||||
|
- name: VITE_WS_URL
|
||||||
|
value: "wss://dexorder.ai/ws"
|
||||||
@@ -31,7 +31,7 @@ onMounted(() => {
|
|||||||
datafeed: datafeed,
|
datafeed: datafeed,
|
||||||
interval: chartStore.chart_state.interval as any,
|
interval: chartStore.chart_state.interval as any,
|
||||||
container: chartContainer.value!,
|
container: chartContainer.value!,
|
||||||
library_path: '/charting_library/',
|
library_path: 'charting_library/',
|
||||||
locale: 'en',
|
locale: 'en',
|
||||||
disabled_features: [
|
disabled_features: [
|
||||||
'use_localstorage_for_settings',
|
'use_localstorage_for_settings',
|
||||||
|
|||||||
@@ -43,9 +43,9 @@ class WebSocketManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
|
// Use env variable for WebSocket URL, fallback to localhost for dev
|
||||||
const host = window.location.hostname
|
const wsUrl = import.meta.env.VITE_WS_URL || 'ws://localhost:8080/ws'
|
||||||
this.ws = new WebSocket(`${protocol}//${host}:8080/ws`)
|
this.ws = new WebSocket(wsUrl)
|
||||||
|
|
||||||
this.authResolve = resolve
|
this.authResolve = resolve
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,10 @@ import vueDevTools from 'vite-plugin-vue-devtools'
|
|||||||
|
|
||||||
// https://vite.dev/config/
|
// https://vite.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
base: process.env.VITE_BASE_PATH || '/',
|
||||||
|
server: {
|
||||||
|
allowedHosts: ['.dexorder.ai']
|
||||||
|
},
|
||||||
css: {
|
css: {
|
||||||
preprocessorOptions: {
|
preprocessorOptions: {
|
||||||
// if using SCSS
|
// if using SCSS
|
||||||
|
|||||||
Reference in New Issue
Block a user