Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,7 @@ build/
# docker
docker/app-platform-tmp
docker/.env
docker/sql/init/data/tr_init_models.sql
docker/sql/init/data/tr_init_models.sql

# Claude Code settings
.claude/
17 changes: 12 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,6 @@ app-builder/
│ └── template.zip
```


加入数据库配置项,修改后的配置项如下所示:

```yml
Expand Down Expand Up @@ -182,13 +181,21 @@ app-engine:
**启动命令**

```
fit start -Dfit.profiles.active=prod
fit start
```

> 这里直接使用了 `fit` 命令,该命令请参考 `fit-framework` 项目的[指导手册](https://github.com/ModelEngine-Group/fit-framework/blob/main/docs/framework/fit/java/quick-start-guide/03.%20%E4%BD%BF%E7%94%A8%E6%8F%92%E4%BB%B6%E7%9A%84%E7%83%AD%E6%8F%92%E6%8B%94%E8%83%BD%E5%8A%9B.md)。
>
> 当前,`app-platform` 使用了 `fit` 的 3.5.1 版本,因此,如果采用手动编译,需要在 `fit-framework` 仓库中切换到 `v3.5.1` 标签处进行编译构建操作。

**调试命令**

```
fit debug
```

> 这里的调试命令背后使用了 Java 内置的远程调试命令,通过该技术,可以在进程启动之后,在 `IDEA` 中绑定启动端口进行远程调试。

---------

### 前端环境配置
Expand Down Expand Up @@ -253,15 +260,15 @@ npm run start

在对话中使用大模型功能,需要对模型进行配置,包括大模型的地址和鉴权信息。
首先在首页的`应用市场`一栏中找到 `模型配置应用`,并点击该应用。点击右上角`创意灵感` 的`开始配置`,如下图所示:
![image-20250508203127410](doc/images/readme/model_config_inspiration.png)
![image_config_model](doc/images/readme/model_config_inspiration.png)
然后点击回答的 `添加模型` 按钮,输入模型名称、API Key 和模型地址,并点击确认。此时模型添加成功。

**应用创建**

在首页的`应用开发`一栏中点击`创建空白应用`。如下所示:
![image-20250508204618312](doc/images/readme/app_create.png)
![image_create_app](doc/images/readme/app_create.png)
输入所要创建的应用名称和简介,并点击 `创建`按钮,即可创建 AI 应用。接着在跳转后的应用配置页面上,在 `大模型` 一栏中选择自定义配置的模型。此时即可在对话框进行对话。如下所示:
![image-20250508205124203](doc/images/readme/app_chat.png)
![image_app_chat](doc/images/readme/app_chat.png)

## 文档

Expand Down
97 changes: 76 additions & 21 deletions docker/dev-app-builder.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,89 @@ SHARED_DIR="${WORKSPACE}/../build/shared"
cd ${WORKSPACE}
source .env

# 临时启动容器
docker run -d --name app-builder-tmp --entrypoint sleep modelengine/app-builder:$VERSION infinity
# Generate development version tag
BASE_VERSION=${VERSION}
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
GIT_COMMIT=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown")
DEV_VERSION="${BASE_VERSION}-dev-${TIMESTAMP}-${GIT_COMMIT}"

# 拷贝本地编译产物到容器
if [ -d "$PLUGINS_DIR" ] && [ -n "$(ls -A "$PLUGINS_DIR")" ]; then
ls | grep -E '\.jar$' | grep -v -E '^(fit|fel)' | xargs rm -f
docker cp "$PLUGINS_DIR"/. app-builder-tmp:/opt/fit-framework/plugins/
else
echo "Error: plugins directory is empty or doesn't exist, skipped copy."
echo "=== Version Information ==="
echo "Base Version: ${BASE_VERSION}"
echo "Development Version: ${DEV_VERSION}"
echo "Git Commit: ${GIT_COMMIT}"

# Check local build artifacts
if [ ! -d "$PLUGINS_DIR" ] || [ -z "$(ls -A "$PLUGINS_DIR" 2>/dev/null)" ]; then
echo "Error: plugins directory is empty or does not exist: $PLUGINS_DIR"
exit 1
fi

if [ -d "$SHARED_DIR" ] && [ -n "$(ls -A "$SHARED_DIR")" ]; then
ls | grep -E '\.jar$' | grep -v '^(opentelemetry)' | xargs rm -f
docker cp "$SHARED_DIR"/. app-builder-tmp:/opt/fit-framework/shared/
else
echo "Error: shared directory is empty or doesn't exist, skipped copy."
if [ ! -d "$SHARED_DIR" ] || [ -z "$(ls -A "$SHARED_DIR" 2>/dev/null)" ]; then
echo "Error: shared directory is empty or does not exist: $SHARED_DIR"
exit 1
fi

# 提交镜像
docker commit --change='ENTRYPOINT ["/opt/fit-framework/bin/start.sh"]' app-builder-tmp modelengine/app-builder:$VERSION
docker commit --change='ENTRYPOINT ["/opt/fit-framework/bin/start.sh"]' app-builder-tmp app-builder:$VERSION
echo "=== Stopping app-builder service ==="
docker-compose stop app-builder

echo "=== Creating development version image ==="
# Use stable version as base
docker run -d --name app-builder-tmp --entrypoint sleep modelengine/app-builder:${BASE_VERSION} infinity

# Copy files
echo "Copying plugins..."
docker cp "$PLUGINS_DIR"/. app-builder-tmp:/opt/fit-framework/plugins/

echo "Copying shared libraries..."
docker cp "$SHARED_DIR"/. app-builder-tmp:/opt/fit-framework/shared/

# Commit as development version
echo "Committing development version image: ${DEV_VERSION}"
docker commit --change='ENTRYPOINT ["/opt/fit-framework/bin/start.sh"]' app-builder-tmp modelengine/app-builder:${DEV_VERSION}

# Create development tag (for docker-compose convenience)
docker tag modelengine/app-builder:${DEV_VERSION} modelengine/app-builder:dev-latest

echo "=== Cleaning up temporary container ==="
docker stop app-builder-tmp
docker rm app-builder-tmp

# 重启服务
docker-compose down
echo "Service stopped."
echo "=== Updating docker-compose configuration ==="
# Create docker-compose configuration for development
cp docker-compose.yml docker-compose.dev.yml
if [[ "$(uname -s)" == "Darwin" ]]; then
sed -i '.bak' "s/modelengine\/app-builder:\${VERSION}/modelengine\/app-builder:dev-latest/g" docker-compose.dev.yml
rm -f docker-compose.dev.yml.bak
else
sed -i "s/modelengine\/app-builder:\${VERSION}/modelengine\/app-builder:dev-latest/g" docker-compose.dev.yml
fi

echo "=== Restarting services ==="
docker-compose -f docker-compose.dev.yml -p app-platform up -d app-builder

echo "=== Waiting for services to be ready ==="
# Use gtimeout on macOS or implement timeout logic ourselves
MAX_WAIT=800
WAITED=0
while [ $WAITED -lt $MAX_WAIT ]; do
if docker-compose -f docker-compose.dev.yml -p app-platform ps app-builder | grep -q "healthy"; then
echo "Services are ready!"
break
fi
sleep 5
WAITED=$((WAITED + 5))
echo -n "."
done

if [ $WAITED -ge $MAX_WAIT ]; then
echo "Warning: Service startup timeout, but continuing execution..."
fi

docker-compose up -d
echo "Service restarted."
echo ""
echo "=== Completed! ==="
echo "Development version deployed: ${DEV_VERSION}"
echo "Current tag in use: dev-latest"
echo "Service URL: http://localhost:8001"
echo ""
echo "=== Version Management Commands ==="
echo "View all versions: docker images modelengine/app-builder"
169 changes: 169 additions & 0 deletions docker/docker-compose.dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
services:
jade-db:
container_name: jade-db
hostname: jade-db
image: modelengine/postgres:15.2-${VERSION}
healthcheck:
test: [ "CMD-SHELL", "pg_isready -U postgres" ]
interval: 10s
timeout: 5s
retries: 30
start_period: 30s
networks:
my-net:
ipv4_address: 172.0.0.98
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: ${DB_PASSWORD}
LOG_HOME: /log/app
volumes:
- ./sql:/home/sql
- ./shell/initDB.sh:/home/initDB.sh
- "./app-platform-tmp/jade-db:/var/lib/postgresql/data"
- "./app-platform-tmp/log:/log/app/postgresql"
ports:
- "${DB_PORT}:5432"

db-initializer:
container_name: db-initializer
hostname: db-initializer
image: modelengine/postgres:15.2-${VERSION}
networks:
my-net:
ipv4_address: 172.0.0.99
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: "ModelEngine@123"
LOG_HOME: /log/app
DB_HOST: jade-db
DB_PORT: 5432
DB_USER: postgres
IS_UPGRADE: ${IS_UPGRADE}
volumes:
- ./shell/initDB.sh:/home/initDB.sh
- ./sql:/home/sql
entrypoint: ["/bin/bash", "-c"]
command: |
" chmod +x /home/initDB.sh
bash /home/initDB.sh app_builder /home/sql
"
restart: "no"

app-builder:
container_name: app-builder
hostname: app-builder
image: modelengine/app-builder:dev-latest
depends_on:
jade-db:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://app-builder:8004/fit/check"]
interval: 30s
timeout: 10s
retries: 20
start_period: 180s
networks:
my-net:
ipv4_address: 172.0.0.100
environment:
worker.host: localhost
server.http.port: 8004
matata.registry.host: localhost
matata.registry.port: 8004
fit.profiles.active: prod
fit.datasource.primary: app-engine
fit.datasource.instances.app-engine.mode: shared
fit.datasource.instances.app-engine.url: jdbc:postgresql://jade-db/app_builder?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=true&allowPublicKeyRetrieval=true&useAffectedRows=true&connectTimeout=60000&socketTimeout=60000
fit.datasource.instances.app-engine.username: postgres
fit.datasource.instances.app-engine.password: "ModelEngine@123"
openai-urls.internal: https://model-lite-router:8009/v1
app-engine.pathPrefix: /api/jober
LOG_HOME: /log/app
LOG_NUM: 4320
LOG_SIZE: "50M"
app-engine.ttl.businessData: 15
app-engine.ttl.nonBusinessData: 1
volumes:
- "./app-platform-tmp/fit-runtime:/var/store/tools"
- "./app-platform-tmp/log:/log/app/app-builder"
- "./app-platform-tmp/jade-db:/var/jade-db"
- "./app-platform-tmp/app-builder:/var/share"
ports:
- "8004:8004"

fit-runtime-java:
container_name: fit-runtime-java
hostname: fit-runtime-java
image: modelengine/fit-runtime-java:${VERSION}
depends_on:
app-builder:
condition: service_healthy
networks:
my-net:
ipv4_address: 172.0.0.101
environment:
worker.id: fit-runtime-java
worker.environment: prod
worker.host: 172.0.0.101
matata.registry.host: app-builder
matata.registry.port: 8004
matata.registry.environment: prod
ENTRY_PLUGINS_PATH: /entry
LOG_HOME: /log/app
volumes:
- "./app-platform-tmp/app-builder:/var/share"
- "./app-platform-tmp/fit-runtime:/entry"
- "./app-platform-tmp/log:/log/app/runtime-java"
ports:
- "8090:8090"

fit-runtime-python:
container_name: fit-runtime-python
hostname: fit-runtime-python
image: modelengine/fit-runtime-python:${VERSION}
depends_on:
app-builder:
condition: service_healthy
networks:
my-net:
ipv4_address: 172.0.0.102
environment:
WORKER_ID: fit-runtime-python
WORK_ENV: prod
LOCAL_IP: 172.0.0.102
REGISTRY_HOST: app-builder
REGISTRY_PORT: 8004
matata.registry.environment: prod
USER_PLUGINS_PATH: 'custom_dynamic_plugins/python'
LOG_HOME: /log/app
volumes:
- "./app-platform-tmp/app-builder:/var/share"
- "./app-platform-tmp/fit-runtime:/app/python/custom_dynamic_plugins"
- "./app-platform-tmp/log:/log/app/runtime-python"
ports:
- "9666:9666"

web:
container_name: web
hostname: web
image: modelengine/jade-web:${VERSION}
depends_on:
app-builder:
condition: service_healthy
networks:
my-net:
ipv4_address: 172.0.0.103
environment:
LOG_HOME: /log/app
volumes:
- "./app-platform-tmp/log:/log/app/web"
ports:
- "${WEB_PORT}:8001"

networks:
my-net:
driver: bridge
ipam:
config:
- subnet: 172.0.0.0/24
gateway: 172.0.0.1