Преглед изворни кода

Merge branch 'master' of http://47.109.151.80:15030/yangzhenghui/ZhAgent

rexyang-ai пре 2 недеља
родитељ
комит
c2e516fdf7
11 измењених фајлова са 312 додато и 32 уклоњено
  1. 49 0
      Dockerfile.backend
  2. 27 0
      Dockerfile.frontend
  3. 119 0
      docker-compose.yml
  4. 1 0
      postgres-init.sql
  5. 4 2
      pyproject.toml
  6. 4 0
      start.sh
  7. 4 0
      ui/env/.env.admin
  8. 52 0
      ui/nginx.conf
  9. 2 2
      ui/package.json
  10. 27 28
      ui/vite.config.ts
  11. 23 0
      启动说明.md

+ 49 - 0
Dockerfile.backend

@@ -0,0 +1,49 @@
+FROM python:3.11-slim
+
+WORKDIR /opt/maxkb-app
+
+ENV DEBIAN_FRONTEND=noninteractive \
+    PYTHONDONTWRITEBYTECODE=1 \
+    PYTHONUNBUFFERED=1 \
+    HF_HOME=/opt/maxkb-app/model/base \
+    TMPDIR=/opt/maxkb-app/tmp \
+    PIP_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple \
+    PIP_TRUSTED_HOST=pypi.tuna.tsinghua.edu.cn
+
+RUN rm -f /etc/apt/sources.list.d/*.list /etc/apt/sources.list.d/*.sources && \
+    echo 'deb http://mirrors.tuna.tsinghua.edu.cn/debian/ trixie main non-free contrib non-free-firmware' > /etc/apt/sources.list && \
+    echo 'deb http://mirrors.tuna.tsinghua.edu.cn/debian/ trixie-updates main non-free contrib non-free-firmware' >> /etc/apt/sources.list && \
+    echo 'deb http://mirrors.tuna.tsinghua.edu.cn/debian-security/ trixie-security main non-free contrib non-free-firmware' >> /etc/apt/sources.list && \
+    apt-get update && apt-get install -y --no-install-recommends \
+    build-essential \
+    gcc \
+    python3-dev \
+    libpq-dev \
+    curl \
+    git \
+    wget \
+    ffmpeg \
+    && rm -rf /var/lib/apt/lists/*
+
+RUN pip install --no-cache-dir --upgrade pip setuptools wheel
+
+COPY pyproject.toml README.md ./
+
+COPY apps/ ./apps/
+
+COPY main.py ./
+
+RUN pip install --no-cache-dir --break-system-packages torch==2.8.0 --index-url https://pypi.tuna.tsinghua.edu.cn/simple
+
+RUN pip install .
+
+
+
+RUN mkdir -p /opt/maxkb-app/model/base /opt/maxkb-app/tmp /opt/maxkb-app/logs
+
+COPY start.sh /opt/maxkb-app/start.sh
+RUN chmod +x /opt/maxkb-app/start.sh
+
+EXPOSE 8080
+
+CMD ["/opt/maxkb-app/start.sh"]

+ 27 - 0
Dockerfile.frontend

@@ -0,0 +1,27 @@
+FROM node:22-alpine
+
+WORKDIR /opt/maxkb-app/ui
+
+COPY ui/package.json ./
+
+RUN npm config set registry https://registry.npmmirror.com && \
+    npm install
+
+COPY ui/ ./
+
+ENV NODE_OPTIONS="--max-old-space-size=4096"
+
+RUN npm run build-only -- --mode admin && \
+    mv dist dist_admin && \
+    npm run build-only-chat -- --mode chat && \
+    cp -r dist_admin/* dist/ && \
+    rm -rf dist_admin
+
+FROM nginx:alpine
+
+COPY --from=0 /opt/maxkb-app/ui/dist /usr/share/nginx/html
+COPY ui/nginx.conf /etc/nginx/conf.d/default.conf
+
+EXPOSE 80
+
+CMD ["nginx", "-g", "daemon off;"]

+ 119 - 0
docker-compose.yml

@@ -0,0 +1,119 @@
+services:
+  postgres:
+    image: pgvector/pgvector:pg16
+    container_name: maxkb-postgres
+    environment:
+      POSTGRES_DB: maxkb
+      POSTGRES_USER: postgres
+      POSTGRES_PASSWORD: postgres
+    volumes:
+      - postgres_data:/var/lib/postgresql/data
+      - ./postgres-init.sql:/docker-entrypoint-initdb.d/init.sql
+    ports:
+      - "5432:5432"
+    healthcheck:
+      test: ["CMD-SHELL", "pg_isready -U postgres"]
+      interval: 5s
+      timeout: 5s
+      retries: 5
+    networks:
+      - maxkb-network
+
+  redis:
+    image: redis:latest
+    container_name: maxkb-redis
+    volumes:
+      - redis_data:/data
+    ports:
+      - "6379:6379"
+    healthcheck:
+      test: ["CMD", "redis-cli", "ping"]
+      interval: 5s
+      timeout: 5s
+      retries: 5
+    networks:
+      - maxkb-network
+
+  maxkb-frontend:
+    image: zhagent-frontend:latest
+    container_name: maxkb-frontend
+    ports:
+      - "80:80"
+    networks:
+      - maxkb-network
+    restart: unless-stopped
+    depends_on:
+      - maxkb-web
+
+  maxkb-web:
+    image: zhagent-backend:latest
+    container_name: maxkb-web
+    command: ["/opt/maxkb-app/start.sh"]
+    environment:
+      MAXKB_CONFIG_TYPE: ENV
+      MAXKB_DB_NAME: maxkb
+      MAXKB_DB_HOST: postgres
+      MAXKB_DB_PORT: 5432
+      MAXKB_DB_USER: postgres
+      MAXKB_DB_PASSWORD: postgres
+      MAXKB_REDIS_HOST: redis
+      MAXKB_REDIS_PORT: 6379
+      MAXKB_REDIS_DB: 0
+      MAXKB_CORE_WORKER: 4
+      MAXKB_STATIC_PATH: /opt/maxkb-app/static
+    ports:
+      - "8080:8080"
+    depends_on:
+      postgres:
+        condition: service_healthy
+      redis:
+        condition: service_healthy
+    volumes:
+      - model_data:/opt/maxkb-app/model/base
+      - tmp_data:/opt/maxkb-app/tmp
+      - log_data:/opt/maxkb-app/logs
+      - static_data:/opt/maxkb-app/static
+    networks:
+      - maxkb-network
+    restart: unless-stopped
+
+  maxkb-celery:
+    image: zhagent-backend:latest
+    container_name: maxkb-celery
+    command: ["python", "main.py", "dev", "celery"]
+    environment:
+      MAXKB_CONFIG_TYPE: ENV
+      MAXKB_DB_NAME: maxkb
+      MAXKB_DB_HOST: postgres
+      MAXKB_DB_PORT: 5432
+      MAXKB_DB_USER: postgres
+      MAXKB_DB_PASSWORD: postgres
+      MAXKB_REDIS_HOST: redis
+      MAXKB_REDIS_PORT: 6379
+      MAXKB_REDIS_DB: 0
+    depends_on:
+      postgres:
+        condition: service_healthy
+      redis:
+        condition: service_healthy
+      maxkb-web:
+        condition: service_started
+    volumes:
+      - model_data:/opt/maxkb-app/model/base
+      - tmp_data:/opt/maxkb-app/tmp
+      - log_data:/opt/maxkb-app/logs
+    networks:
+      - maxkb-network
+    restart: unless-stopped
+
+volumes:
+  postgres_data:
+  redis_data:
+  model_data:
+  tmp_data:
+  log_data:
+  static_data:
+
+networks:
+  maxkb-network:
+    driver: bridge

+ 1 - 0
postgres-init.sql

@@ -0,0 +1 @@
+CREATE EXTENSION IF NOT EXISTS vector;

+ 4 - 2
pyproject.toml

@@ -57,7 +57,6 @@ dependencies = [
     "pymupdf==1.26.3",
     "pypdf==6.10.2",
     "pydub==0.25.1",
-    "pysilk==0.0.1",
     "gunicorn==23.0.0",
     "python-daemon==3.1.2",
     "websockets==15.0.1",
@@ -88,4 +87,7 @@ torch = [
 
 [build-system]
 requires = ["hatchling"]
-build-backend = "hatchling.build"
+build-backend = "hatchling.build"
+
+[tool.hatch.build.targets.wheel]
+packages = ["apps"]

+ 4 - 0
start.sh

@@ -0,0 +1,4 @@
+#!/bin/bash
+
+echo "Starting Web server..."
+python main.py dev web

+ 4 - 0
ui/env/.env.admin

@@ -0,0 +1,4 @@
+VITE_APP_NAME=admin
+VITE_BASE_PATH=/
+VITE_APP_PORT=8080
+VITE_ENTRY="admin.html"

+ 52 - 0
ui/nginx.conf

@@ -0,0 +1,52 @@
+server {
+    listen 80;
+    server_name localhost;
+    root /usr/share/nginx/html;
+    index index.html;
+
+    location / {
+        try_files $uri $uri/ /index.html;
+    }
+
+    location /api {
+        proxy_pass http://maxkb-web:8080;
+        proxy_set_header Host $host;
+        proxy_set_header X-Real-IP $remote_addr;
+        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+        proxy_set_header X-Forwarded-Proto $scheme;
+    }
+
+    location /admin {
+        proxy_pass http://maxkb-web:8080;
+        proxy_set_header Host $host;
+        proxy_set_header X-Real-IP $remote_addr;
+        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+        proxy_set_header X-Forwarded-Proto $scheme;
+    }
+
+    location /chat {
+        alias /usr/share/nginx/html/chat;
+        try_files $uri $uri/ /chat/index.html;
+    }
+
+    location /chat/api {
+        proxy_pass http://maxkb-web:8080;
+        proxy_set_header Host $host;
+        proxy_set_header X-Real-IP $remote_addr;
+        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+        proxy_set_header X-Forwarded-Proto $scheme;
+    }
+
+    location /ws {
+        proxy_pass http://maxkb-web:8080;
+        proxy_http_version 1.1;
+        proxy_set_header Upgrade $http_upgrade;
+        proxy_set_header Connection "upgrade";
+        proxy_set_header Host $host;
+        proxy_set_header X-Real-IP $remote_addr;
+        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+    }
+
+    gzip on;
+    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
+}

+ 2 - 2
ui/package.json

@@ -6,8 +6,8 @@
   "scripts": {
     "dev": "vite",
     "chat": "vite --mode chat",
-    "build": "run-p type-check \"build-only {@}\" --",
-    "build-chat": "run-p type-check \"build-only-chat {@}\" --",
+    "build": "run-p type-check build-only",
+    "build-chat": "run-p type-check build-only-chat",
     "preview": "vite preview",
     "build-only": "vite build",
     "build-only-chat": "vite build --mode chat",

+ 27 - 28
ui/vite.config.ts

@@ -7,9 +7,12 @@ import DefineOptions from 'unplugin-vue-define-options/vite'
 import path from 'path'
 import {createHtmlPlugin} from 'vite-plugin-html'
 import fs from 'fs'
-// import vueDevTools from 'vite-plugin-vue-devtools'
+
+const __filename = fileURLToPath(import.meta.url)
+const __dirname = path.dirname(__filename)
+
 const envDir = './env'
-// 自定义插件:重命名入口文件
+
 const renameHtmlPlugin = (outDir: string, entry: string) => {
   return {
     name: 'rename-html',
@@ -18,22 +21,23 @@ const renameHtmlPlugin = (outDir: string, entry: string) => {
       const oldFile = path.join(buildDir, entry)
       const newFile = path.join(buildDir, 'index.html')
 
-      // 检查文件是否存在
       if (fs.existsSync(oldFile)) {
-        // 删除已存在的 index.html
         if (fs.existsSync(newFile)) {
           fs.unlinkSync(newFile)
         }
-        // 重命名文件
         fs.renameSync(oldFile, newFile)
       }
     },
   }
 }
-// https://vite.dev/config/
+
 export default defineConfig((conf: any) => {
   const mode = conf.mode
   const ENV = loadEnv(mode, envDir)
+
+  const basePath = ENV.VITE_BASE_PATH || '/'
+  const entryFile = ENV.VITE_ENTRY || 'index.html'
+
   const proxyConf: Record<string, string | ProxyOptions> = {}
   proxyConf['/admin/api'] = {
     target: 'http://127.0.0.1:8080',
@@ -46,46 +50,41 @@ export default defineConfig((conf: any) => {
   proxyConf['/doc'] = {
     target: 'http://127.0.0.1:8080',
     changeOrigin: true,
-    rewrite: (path: string) => path.replace(ENV.VITE_BASE_PATH, '/'),
+    rewrite: (path: string) => path.replace(basePath, '/'),
   }
   proxyConf['/schema'] = {
     target: 'http://127.0.0.1:8080',
     changeOrigin: true,
-    rewrite: (path: string) => path.replace(ENV.VITE_BASE_PATH, '/'),
+    rewrite: (path: string) => path.replace(basePath, '/'),
   }
   proxyConf['/static'] = {
     target: 'http://127.0.0.1:8080',
     changeOrigin: true,
-    rewrite: (path: string) => path.replace(ENV.VITE_BASE_PATH, '/'),
+    rewrite: (path: string) => path.replace(basePath, '/'),
   }
 
-  // 前端静态资源转发到本身
-  proxyConf[`^${ENV.VITE_BASE_PATH}.+\/oss\/file\/.*$`] = {
-    target: `http://127.0.0.1:8080`,
+  proxyConf[`^${basePath}.+\/oss\/file\/.*$`] = {
+    target: 'http://127.0.0.1:8080',
     changeOrigin: true,
   }
-  // 前端静态资源转发到本身
-  proxyConf[`^${ENV.VITE_BASE_PATH}oss\/file\/.*$`] = {
-    target: `http://127.0.0.1:8080`,
+  proxyConf[`^${basePath}oss\/file\/.*$`] = {
+    target: 'http://127.0.0.1:8080',
     changeOrigin: true,
   }
-  proxyConf[`^${ENV.VITE_BASE_PATH}oss\/get_url\/.*$`] = {
-    target: `http://127.0.0.1:8080`,
+  proxyConf[`^${basePath}oss\/get_url\/.*$`] = {
+    target: 'http://127.0.0.1:8080',
     changeOrigin: true,
   }
-  // 前端静态资源转发到本身
-  proxyConf[ENV.VITE_BASE_PATH] = {
-    target: `http://127.0.0.1:${ENV.VITE_APP_PORT}`,
+  proxyConf[basePath] = {
+    target: `http://127.0.0.1:${ENV.VITE_APP_PORT || 8080}`,
     changeOrigin: true,
-    rewrite: (path: string) => path.replace(ENV.VITE_BASE_PATH, '/'),
+    rewrite: (path: string) => path.replace(basePath, '/'),
   }
 
-  // 代理 /chat 到 3001 端口
   if (mode !== 'chat') {
     proxyConf['/chat'] = {
       target: 'http://127.0.0.1:3001',
       changeOrigin: true,
-      // 避免代理后端的 API
       bypass: (req: any) => {
         if (req.url && req.url.startsWith('/chat/api')) {
           return req.url
@@ -103,21 +102,21 @@ export default defineConfig((conf: any) => {
       vue(),
       vueJsx(),
       DefineOptions(),
-      createHtmlPlugin({template: ENV.VITE_ENTRY}),
-      renameHtmlPlugin(`dist${ENV.VITE_BASE_PATH}`, ENV.VITE_ENTRY),
+      createHtmlPlugin({template: entryFile}),
+      renameHtmlPlugin(`dist${basePath}`, entryFile),
     ],
     server: {
       cors: true,
       host: '0.0.0.0',
-      port: Number(ENV.VITE_APP_PORT),
+      port: Number(ENV.VITE_APP_PORT) || 8080,
       strictPort: true,
       proxy: proxyConf,
     },
     build: {
-      outDir: `dist${ENV.VITE_BASE_PATH}`,
+      outDir: `dist${basePath}`,
       target: 'es2022',
       rollupOptions: {
-        input: ENV.VITE_ENTRY,
+        input: entryFile,
       },
     },
     resolve: {

+ 23 - 0
启动说明.md

@@ -22,3 +22,26 @@
 
 * E:\\ProductSpcae\\ZhAgentOS1.0\\ui>npm run chat
 
+## Docker 启动方式
+
+构建前端镜像->E:\\ProductSpcae\\ZhAgentOS1.0
+
+* docker build -f Dockerfile.frontend -t zhagent-frontend:latest .
+
+构建后端镜像->E:\\ProductSpcae\\ZhAgentOS1.0
+
+* docker build -f Dockerfile.backend -t zhagent-backend:latest .
+
+启动所有服务->E:\\ProductSpcae\\ZhAgentOS1.0
+
+* docker-compose up -d
+
+查看服务状态->E:\\ProductSpcae\\ZhAgentOS1.0
+
+* docker-compose ps
+
+查看日志->E:\\ProductSpcae\\ZhAgentOS1.0
+
+* docker-compose logs -f maxkb-web
+* docker-compose logs -f maxkb-celery
+