diff --git a/.env.example b/.env.example index ce4a5e9..bb8806c 100644 --- a/.env.example +++ b/.env.example @@ -1,13 +1,11 @@ -# Docker 배포 설정 (이 파일을 복사해서 .env 로 만드세요) -# ARTEX_TAG 는 docker-compose 가 받는 상류(원본) 이미지 autumn27/artex 의 태그입니다. -# 이 이미지는 중국어 UI·출력이며, 이 저장소의 한국어화는 아직 담겨 있지 않습니다. -# 한국어판 화면·출력을 보려면 README "소스에서 단일 바이너리 컴파일" 경로로 빌드하세요. +# Docker 部署配置 (请复制此文件为 .env) +# ARTEX_TAG 是 docker-compose 拉取的自建镜像 registry.gitea.mygoband.com/carrydela/artex 的标签 ARTEX_TAG=latest POSTGRES_USER=artex POSTGRES_PASSWORD=change-me-please POSTGRES_DB=artex -# LLM (둘 중 하나만 또는 둘 다 입력하세요. 비워 두고 나중에 UI 에서 설정해도 됩니다) +# LLM (填写其中一个或两个; 留空可稍后在 UI 中设置) ANTHROPIC_API_KEY= OPENAI_API_KEY= ARTEX_LLM_PROVIDER= diff --git a/docker-compose.yml b/docker-compose.yml index 409c206..e211b2e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,7 +3,7 @@ services: image: postgres:16-alpine environment: POSTGRES_USER: ${POSTGRES_USER:-artex} - POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?.env 파일에 POSTGRES_PASSWORD 를 설정하세요} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?.env 文件中未设置 POSTGRES_PASSWORD,请先运行 install.sh 或手动填写} POSTGRES_DB: ${POSTGRES_DB:-artex} volumes: - pgdata:/var/lib/postgresql/data @@ -15,7 +15,7 @@ services: restart: unless-stopped artex: - image: autumn27/artex:${ARTEX_TAG:-latest} + image: registry.gitea.mygoband.com/carrydela/artex:${ARTEX_TAG:-latest} depends_on: postgres: condition: service_healthy @@ -31,11 +31,11 @@ services: - "8787:8787" - "127.0.0.1:8788:8788" volumes: - # 데이터 디렉터리(jwt.key, SQLite 등 포함)를 프로젝트 루트의 data/ 에 바인드합니다. - # 호스트에서 바로 확인·백업할 수 있고, 컨테이너를 다시 만들어도 사라지지 않습니다. + # 数据目录(含 jwt.key、SQLite 等)绑定到项目根目录的 data/ + # 在宿主机上可直接查看和备份,重建容器数据也不会丢失 - ./data:/app/data - # 프로젝트 루트의 skills 를 컨테이너에 마운트합니다(이미지에 내장된 /app/skills 를 덮어씁니다). - # skill 을 고치면 이미지를 다시 빌드할 필요 없이, 컨테이너가 호스트의 이 파일을 그대로 읽습니다. + # 把项目根目录的 skills 挂载进容器(覆盖镜像内置的 /app/skills) + # 修改 skill 后无需重新构建镜像,容器直接读取宿主机上的这些文件 - ./skills:/app/skills restart: unless-stopped diff --git a/install.sh b/install.sh index f2caa00..5e620c7 100755 --- a/install.sh +++ b/install.sh @@ -1,8 +1,12 @@ #!/usr/bin/env bash -# ARTEX 설치 스크립트: ① 전부 Docker ② 로컬 컴파일 실행 +# ARTEX 安装脚本: ① 全部 Docker ② 本地编译运行 set -euo pipefail cd "$(cd "$(dirname "$0")" && pwd)" +# 自建私有镜像仓库 +REGISTRY="registry.gitea.mygoband.com" +IMAGE="${REGISTRY}/carrydela/artex" + info(){ printf '\033[36m[*]\033[0m %s\n' "$*"; } ok(){ printf '\033[32m[+]\033[0m %s\n' "$*"; } warn(){ printf '\033[33m[!]\033[0m %s\n' "$*"; } @@ -10,74 +14,98 @@ die(){ printf '\033[31m[x]\033[0m %s\n' "$*" >&2; exit 1; } ask(){ local p="$1" d="${2:-}" a; read -rp "$p${d:+ [$d]}: " a; echo "${a:-$d}"; } rand(){ head -c 18 /dev/urandom | base64 | tr -dc 'A-Za-z0-9' | head -c 24; } -# ── docker 환경 감지 / 자동 설치 ────────────────── +# ── docker 环境检测 / 自动安装 ────────────────── ensure_docker(){ if command -v docker >/dev/null 2>&1 && docker compose version >/dev/null 2>&1; then - ok "docker 와 docker compose 를 확인했습니다"; return + ok "已检测到 docker 和 docker compose"; return fi - warn "docker / docker compose 를 찾을 수 없습니다" + warn "未找到 docker / docker compose" case "$(uname -s)" in Linux) - if [ "$(ask 'Docker 를 자동으로 설치할까요? (y/n)' y)" = y ]; then + if [ "$(ask '是否自动安装 Docker? (y/n)' y)" = y ]; then curl -fsSL https://get.docker.com | sh sudo usermod -aG docker "$USER" || true - ok "Docker 설치를 완료했습니다 (사용자 그룹 변경은 다시 로그인해야 sudo 없이 적용됩니다)" + ok "Docker 安装完成 (用户组变更需重新登录后才能免 sudo)" else - die "docker 를 직접 설치한 뒤 다시 실행해 주세요" + die "请先手动安装 docker 后再运行本脚本" fi ;; - Darwin) die "macOS 에서는 Docker Desktop 을 설치해 주세요: https://www.docker.com/products/docker-desktop/" ;; - *) die "docker 를 직접 설치한 뒤 다시 실행해 주세요" ;; + Darwin) die "macOS 请安装 Docker Desktop: https://www.docker.com/products/docker-desktop/" ;; + *) die "请先手动安装 docker 后再运行本脚本" ;; esac } -# ── ① 전부 Docker ────────────────────────────── +# ── 登录私有镜像仓库(仅本地无镜像时需要) ───────── +login_registry(){ + if docker image inspect "${IMAGE}:${ARTEX_TAG}" >/dev/null 2>&1; then + info "本地已有镜像 ${IMAGE}:${ARTEX_TAG}, 跳过登录"; return + fi + if [ -n "${ARTEX_REGISTRY_USER:-}" ]; then + if [ -n "${ARTEX_REGISTRY_PASS:-}" ]; then + printf '%s' "$ARTEX_REGISTRY_PASS" | docker login "$REGISTRY" -u "$ARTEX_REGISTRY_USER" --password-stdin + else + read -r -s -p "请输入 $REGISTRY 的密码: " ARTEX_REGISTRY_PASS; echo + printf '%s' "$ARTEX_REGISTRY_PASS" | docker login "$REGISTRY" -u "$ARTEX_REGISTRY_USER" --password-stdin + fi + ok "已登录私有镜像仓库 $REGISTRY" + else + info "本地无镜像且未设置仓库凭据, 将尝试直接匿名拉取 (私有仓库可能失败)" + info "失败时可带凭据重试:" + info " ARTEX_REGISTRY_USER= ARTEX_REGISTRY_PASS= $0" + fi +} + +# ── ① 全部 Docker ────────────────────────────── install_docker(){ ensure_docker if [ ! -f .env ]; then cp .env.example .env 2>/dev/null || true local pw key - pw="$(ask 'Postgres 비밀번호 (엔터를 누르면 무작위 생성)' "$(rand)")" - key="$(ask 'ANTHROPIC_API_KEY (비워 둬도 되며 나중에 UI 에서 설정)' '')" + pw="$(ask 'Postgres 密码 (直接回车则随机生成)' "$(rand)")" + key="$(ask 'ANTHROPIC_API_KEY (可留空, 之后在 UI 中设置)' '')" sed -i.bak "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=${pw}|" .env sed -i.bak "s|^ANTHROPIC_API_KEY=.*|ANTHROPIC_API_KEY=${key}|" .env rm -f .env.bak - ok ".env 파일을 생성했습니다 (POSTGRES_PASSWORD 설정 완료)" + ok "已生成 .env 文件 (POSTGRES_PASSWORD 已设置)" else - info "이미 있는 .env 파일을 그대로 사용합니다" + info "使用已有的 .env 文件" fi - info "이미지를 받아 기동합니다…" + # 从 .env 读取镜像 tag (默认 latest) + ARTEX_TAG="$(grep -E '^ARTEX_TAG=' .env 2>/dev/null | cut -d= -f2 || true)" + ARTEX_TAG="${ARTEX_TAG:-latest}" + export ARTEX_TAG + login_registry + info "拉取镜像并启动…" docker compose pull || true docker compose up -d - ok "기동을 완료했습니다 → http://localhost:8787" - warn "방금 받은 이미지는 상류(원본) autumn27/artex 중국어 빌드라, 이 저장소의 한국어화(한국어 UI·리포트)는 아직 담겨 있지 않습니다" - warn "한국어판 화면·출력을 보려면 이 스크립트를 다시 실행해 \"2) 로컬 실행 (go 컴파일)\" 을 고르거나, README \"소스에서 단일 바이너리 컴파일\" 경로로 빌드하세요" - info "로그 확인: docker compose logs -f artex" + ok "启动完成 → http://localhost:8787" + info "首次打开后请在页面上完成初始化(设置管理员密码)" + info "查看日志: docker compose logs -f artex" } -# ── ② 로컬 컴파일 실행 ──────────────────────────── +# ── ② 本地编译运行 ──────────────────────────── install_local(){ - echo "데이터베이스 설치 방식:" - echo " 1) 기존 PostgreSQL 에 연결" - echo " 2) Docker 로 PostgreSQL 하나 기동 (docker 필요)" - case "$(ask '선택' 1)" in + echo "数据库安装方式:" + echo " 1) 连接现有 PostgreSQL" + echo " 2) 用 Docker 起一个 PostgreSQL (需要 docker)" + case "$(ask '选择' 1)" in 2) ensure_docker - local pw; pw="$(ask 'Postgres 비밀번호 (엔터를 누르면 무작위)' "$(rand)")" + local pw; pw="$(ask 'Postgres 密码 (直接回车则随机)' "$(rand)")" docker run -d --name artex-pg -p 5432:5432 \ -e POSTGRES_USER=artex -e POSTGRES_PASSWORD="$pw" -e POSTGRES_DB=artex \ -v artex-pg:/var/lib/postgresql/data postgres:16-alpine DB_HOST=127.0.0.1 DB_PORT=5432 DB_USER=artex DB_PASS="$pw" DB_NAME=artex DB_SSL=disable ;; *) - DB_HOST="$(ask '데이터베이스 주소' 127.0.0.1)" - DB_PORT="$(ask '포트' 5432)" - DB_USER="$(ask '계정' artex)" - DB_PASS="$(ask '비밀번호' '')" - DB_NAME="$(ask '데이터베이스 이름' artex)" + DB_HOST="$(ask '数据库地址' 127.0.0.1)" + DB_PORT="$(ask '端口' 5432)" + DB_USER="$(ask '账号' artex)" + DB_PASS="$(ask '密码' '')" + DB_NAME="$(ask '数据库名' artex)" DB_SSL="$(ask 'sslmode (disable/require)' disable)" ;; esac - # config.json 생성 - cat > config.json < config.json </dev/null 2>&1 || die "Go 를 찾을 수 없습니다. 먼저 Go (>=1.26) 를 설치해 주세요: https://go.dev/dl/" + # 检查 go 环境 + command -v go >/dev/null 2>&1 || die "未找到 Go, 请先安装 Go (>=1.26): https://go.dev/dl/" ok "Go: $(go version)" - # 프런트엔드를 내장하려면 node 로 정적 산출물을 만들어야 합니다 + # 如需内嵌前端, 需用 node 构建静态产物 if command -v npm >/dev/null 2>&1; then - info "프런트엔드 정적 산출물을 빌드합니다…" + info "正在构建前端静态产物…" ( cd web && npm ci && npm run build:static ) rm -rf server/webui/dist && mkdir -p server/webui && cp -r web/out server/webui/dist - info "프런트엔드를 내장한 단일 바이너리를 컴파일합니다…" + info "正在编译内嵌前端的单文件二进制…" CGO_ENABLED=0 go build -tags embedui -trimpath -o artex ./cmd/artex else - warn "npm 을 찾을 수 없습니다: 프런트엔드를 내장하지 않은 백엔드만 컴파일합니다 (프런트엔드는 npm run dev 로 따로 실행)" + warn "未找到 npm: 将编译不内嵌前端的纯后端 (前端需另用 npm run dev 启动)" CGO_ENABLED=0 go build -o artex ./cmd/artex fi - ok "컴파일을 완료했습니다 → ./artex" + ok "编译完成 → ./artex" - info "기동합니다… (Ctrl-C 로 종료)" + info "启动中… (Ctrl-C 退出)" ./artex } echo "==============================" -echo " ARTEX 설치" -echo " 1) 전부 Docker 설치" -echo " 2) 로컬 실행 (go 컴파일)" +echo " ARTEX 安装" +echo " 1) 全部 Docker 安装" +echo " 2) 本地运行 (go 编译)" echo "==============================" -case "$(ask '선택' 1)" in +case "$(ask '选择' 1)" in 1) install_docker ;; 2) install_local ;; - *) die "잘못된 선택입니다" ;; + *) die "选择无效" ;; esac