diff --git a/Dockerfile b/Dockerfile index d7327035..95467a0c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,20 +1,30 @@ # Multi-stage build for NOFX AI Trading System -FROM golang:1.24-alpine AS backend-builder +FROM golang:1.25-alpine AS backend-builder # Install build dependencies including TA-Lib -RUN apk add --no-cache \ +RUN apk update && \ + apk add --no-cache \ git \ make \ gcc \ g++ \ musl-dev \ wget \ - tar + tar \ + autoconf \ + automake # Install TA-Lib RUN 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 && \ + if [ "$(uname -m)" = "aarch64" ]; then \ + CONFIG_GUESS=$(find /usr/share -name config.guess | head -1) && \ + CONFIG_SUB=$(find /usr/share -name config.sub | head -1) && \ + cp "$CONFIG_GUESS" config.guess && \ + cp "$CONFIG_SUB" config.sub && \ + chmod +x config.guess config.sub; \ + fi && \ ./configure --prefix=/usr && \ make && \ make install && \ @@ -56,8 +66,9 @@ RUN npm run build # Final stage FROM alpine:latest -# Install runtime dependencies -RUN apk add --no-cache \ +# Update package index and install runtime dependencies +RUN apk update && \ + apk add --no-cache \ ca-certificates \ tzdata \ wget \ @@ -65,12 +76,21 @@ RUN apk add --no-cache \ make \ gcc \ g++ \ - musl-dev + musl-dev \ + autoconf \ + automake # Install TA-Lib runtime RUN 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 && \ + if [ "$(uname -m)" = "aarch64" ]; then \ + CONFIG_GUESS=$(find /usr/share -name config.guess | head -1) && \ + CONFIG_SUB=$(find /usr/share -name config.sub | head -1) && \ + cp "$CONFIG_GUESS" config.guess && \ + cp "$CONFIG_SUB" config.sub && \ + chmod +x config.guess config.sub; \ + fi && \ ./configure --prefix=/usr && \ make && \ make install && \ diff --git a/docker-compose.yml b/docker-compose.yml index 689758a5..71c76f50 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -14,6 +14,7 @@ services: - ./config.json:/app/config.json:ro - ./decision_logs:/app/decision_logs - /etc/localtime:/etc/localtime:ro # 同步主机时间 + - frontend-dist:/app/web/dist-shared:rw # 共享前端文件 environment: - TZ=${NOFX_TIMEZONE:-Asia/Shanghai} # 使用中国时区 networks: @@ -24,6 +25,7 @@ services: timeout: 10s retries: 3 start_period: 60s + command: sh -c "cp -r /app/web/dist/* /app/web/dist-shared/ 2>/dev/null || true && exec ./nofx" # Frontend (Nginx) nofx-frontend: @@ -33,13 +35,16 @@ services: ports: - "${NOFX_FRONTEND_PORT:-3000}:80" volumes: - - ./web/dist:/usr/share/nginx/html:ro + - frontend-dist:/usr/share/nginx/html:ro - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro networks: - nofx-network depends_on: - nofx +volumes: + frontend-dist: + networks: nofx-network: driver: bridge diff --git a/web/src/App.tsx b/web/src/App.tsx index 70761155..8e4d412b 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -558,6 +558,7 @@ function StatCard({ // Decision Card Component with CoT Trace - Binance Style function DecisionCard({ decision, language }: { decision: DecisionRecord; language: Language }) { + const [showInputPrompt, setShowInputPrompt] = useState(false); const [showCoT, setShowCoT] = useState(false); return ( @@ -581,6 +582,25 @@ function DecisionCard({ decision, language }: { decision: DecisionRecord; langua + {/* Input Prompt - Collapsible */} + {decision.input_prompt && ( +
+ + {showInputPrompt && ( +
+ {decision.input_prompt} +
+ )} +
+ )} + {/* AI Chain of Thought - Collapsible */} {decision.cot_trace && (
diff --git a/web/src/types.ts b/web/src/types.ts index c61eca80..fbc224bc 100644 --- a/web/src/types.ts +++ b/web/src/types.ts @@ -64,6 +64,7 @@ export interface AccountSnapshot { export interface DecisionRecord { timestamp: string; cycle_number: number; + input_prompt: string; cot_trace: string; decision_json: string; account_state: AccountSnapshot; diff --git a/web/src/types/index.ts b/web/src/types/index.ts index 94e59e9f..6e648e2f 100644 --- a/web/src/types/index.ts +++ b/web/src/types/index.ts @@ -56,6 +56,7 @@ export interface DecisionAction { export interface DecisionRecord { timestamp: string; cycle_number: number; + input_prompt: string; cot_trace: string; decision_json: string; account_state: {