diff --git a/.github/workflows/deploy-docker.yml b/.github/workflows/deploy-docker.yml index 9f8d235..9a2b5d9 100644 --- a/.github/workflows/deploy-docker.yml +++ b/.github/workflows/deploy-docker.yml @@ -89,7 +89,7 @@ jobs: git fetch origin main --depth=1 || true # Detect changed files before resetting - ALL_COMPOSE_FILES="infra/compose/traefik.yml infra/compose/shared.yml infra/compose/scraper.yml infra/compose/hub.yml infra/compose/tools.yml infra/compose/nats.yml infra/compose/dapr.yml infra/compose/observability.yml" + ALL_COMPOSE_FILES="infra/compose/traefik.yml infra/compose/shared.yml infra/compose/scraper.yml infra/compose/hub.yml infra/compose/tools.yml infra/compose/llm-api.yml infra/compose/nats.yml infra/compose/dapr.yml infra/compose/observability.yml" TRAEFIK_DYNAMIC_DIR="infra/traefik/dynamic" if git rev-parse HEAD >/dev/null 2>&1; then diff --git a/.github/workflows/docker-build-push.yml b/.github/workflows/docker-build-push.yml index cf5f5ff..516617b 100644 --- a/.github/workflows/docker-build-push.yml +++ b/.github/workflows/docker-build-push.yml @@ -8,6 +8,7 @@ on: - 'apps/scraper/**' - 'apps/hub/**' - 'apps/tools/**' + - 'apps/llm-api/**' - '.github/workflows/docker-build-push.yml' - 'infra/**' - '!infra/compose/**' @@ -38,6 +39,7 @@ jobs: scraper-api: ${{ steps.filter.outputs['scraper-api'] == 'true' || steps.dispatch.outputs['scraper-api'] == 'true' || github.event_name == 'workflow_dispatch' }} hub: ${{ steps.filter.outputs['hub'] == 'true' || steps.dispatch.outputs['hub'] == 'true' || github.event_name == 'workflow_dispatch' }} tools: ${{ steps.filter.outputs['tools'] == 'true' || steps.dispatch.outputs['tools'] == 'true' || github.event_name == 'workflow_dispatch' }} + llm-api: ${{ steps.filter.outputs['llm-api'] == 'true' || steps.dispatch.outputs['llm-api'] == 'true' || github.event_name == 'workflow_dispatch' }} steps: - uses: actions/checkout@v7 with: @@ -66,6 +68,7 @@ jobs: echo "scraper-api=$(changed '^(apps/scraper(/|$)|\.github/workflows/docker-build-push\.yml$|infra/docker/scraper\.Dockerfile$)')" >> "$GITHUB_OUTPUT" echo "hub=$(changed '^(apps/hub(/|$)|\.github/workflows/docker-build-push\.yml$|infra/docker/hub\.Dockerfile$)')" >> "$GITHUB_OUTPUT" echo "tools=$(changed '^(apps/tools(/|$)|\.github/workflows/docker-build-push\.yml$|infra/docker/tools\.Dockerfile$)')" >> "$GITHUB_OUTPUT" + echo "llm-api=$(changed '^(apps/llm-api(/|$)|\.github/workflows/docker-build-push\.yml$|infra/docker/llm-api\.Dockerfile$)')" >> "$GITHUB_OUTPUT" - name: Parse repository_dispatch payload id: dispatch @@ -87,7 +90,7 @@ jobs: fi case "$SERVICE" in - scraper-api|hub|tools) ;; + scraper-api|hub|tools|llm-api) ;; *) exit 1 ;; @@ -95,7 +98,7 @@ jobs: if ! [[ "$SHA" =~ ^[0-9a-fA-F]{40}$ ]]; then echo "::error::Invalid sha '$SHA'. Expected 40 hex characters"; fi - SERVICES=(scraper-api hub tools) + SERVICES=(scraper-api hub tools llm-api) for svc in "${SERVICES[@]}"; do if [ "$SERVICE" = "$svc" ]; then echo "${svc}=true" >> "$GITHUB_OUTPUT" @@ -115,6 +118,7 @@ jobs: if [ "${{ steps.filter.outputs['scraper-api'] == 'true' || steps.dispatch.outputs['scraper-api'] == 'true' || github.event_name == 'workflow_dispatch' }}" == "true" ]; then add_service "scraper-api" "docker-scraper" "apps/scraper"; fi if [ "${{ steps.filter.outputs['hub'] == 'true' || steps.dispatch.outputs['hub'] == 'true' || github.event_name == 'workflow_dispatch' }}" == "true" ]; then add_service "hub" "docker-hub" "apps/hub"; fi if [ "${{ steps.filter.outputs['tools'] == 'true' || steps.dispatch.outputs['tools'] == 'true' || github.event_name == 'workflow_dispatch' }}" == "true" ]; then add_service "tools" "docker-tools" "apps/tools"; fi + if [ "${{ steps.filter.outputs['llm-api'] == 'true' || steps.dispatch.outputs['llm-api'] == 'true' || github.event_name == 'workflow_dispatch' }}" == "true" ]; then add_service "llm-api" "docker-llm-api" "apps/llm-api"; fi JSON_ARRAY="[$(IFS=,; echo "${SERVICES[*]}")]" echo "matrix=$JSON_ARRAY" >> $GITHUB_OUTPUT @@ -136,6 +140,7 @@ jobs: "scraper-api") REPO="https://github.com/asepharyana/asepharyana-hub-scraper.git" ;; "hub") REPO="https://github.com/asepharyana/asepharyana-hub-hub.git" ;; "tools") echo "tools is built from monorepo, no submodule wait needed"; exit 0 ;; + "llm-api") REPO="https://github.com/asepharyana/asepharyana-hub-llm-api.git" ;; *) echo "::error::Unsupported service '$SERVICE'" exit 1 @@ -224,6 +229,7 @@ jobs: "scraper-api") echo "dockerfile=infra/docker/scraper.Dockerfile" >> $GITHUB_OUTPUT ;; "hub") echo "dockerfile=infra/docker/hub.Dockerfile" >> $GITHUB_OUTPUT ;; "tools") echo "dockerfile=infra/docker/tools.Dockerfile" >> $GITHUB_OUTPUT ;; + "llm-api") echo "dockerfile=infra/docker/llm-api.Dockerfile" >> $GITHUB_OUTPUT ;; esac - name: Build and Push Docker image @@ -270,11 +276,13 @@ jobs: SERVICES["scraper-api"]="scraper.yml" SERVICES["hub"]="hub.yml" SERVICES["tools"]="tools.yml" + SERVICES["llm-api"]="llm-api.yml" declare -A PATHS PATHS["scraper-api"]="apps/scraper" PATHS["hub"]="apps/hub" PATHS["tools"]="apps/tools" + PATHS["llm-api"]="apps/llm-api" # Use git config for possible commits git config --local user.email "action@github.com" @@ -285,6 +293,7 @@ jobs: if [ "${{ needs.changes.outputs['scraper-api'] }}" == "true" ] && [ "$id" == "scraper-api" ]; then SHOULD_HAVE_RUN=true; fi if [ "${{ needs.changes.outputs['hub'] }}" == "true" ] && [ "$id" == "hub" ]; then SHOULD_HAVE_RUN=true; fi if [ "${{ needs.changes.outputs['tools'] }}" == "true" ] && [ "$id" == "tools" ]; then SHOULD_HAVE_RUN=true; fi + if [ "${{ needs.changes.outputs['llm-api'] }}" == "true" ] && [ "$id" == "llm-api" ]; then SHOULD_HAVE_RUN=true; fi if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then SHOULD_HAVE_RUN=true; fi diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 38915dd..4118425 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -22,8 +22,9 @@ jobs: with: languages: rust - - name: Build Rust project for CodeQL analysis - run: cargo build - working-directory: apps/scraper + - name: Build Rust projects for CodeQL analysis + run: | + cargo build --manifest-path apps/scraper/Cargo.toml + cargo build --manifest-path apps/llm-api/Cargo.toml - uses: github/codeql-action/analyze@v4 diff --git a/.github/workflows/update-submodule.yml b/.github/workflows/update-submodule.yml index 35cdfdc..58a094c 100644 --- a/.github/workflows/update-submodule.yml +++ b/.github/workflows/update-submodule.yml @@ -36,7 +36,7 @@ jobs: fi case "$SERVICE" in - scraper-api|hub) ;; + scraper-api|hub|llm-api) ;; *) echo "::error::Unsupported service '$SERVICE'" exit 1 @@ -55,6 +55,7 @@ jobs: # Map service name to submodule path case "$SERVICE" in scraper-api) SUBMODULE_PATH="apps/scraper" ;; + llm-api) SUBMODULE_PATH="apps/llm-api" ;; *) SUBMODULE_PATH="apps/${SERVICE}" ;; esac diff --git a/.gitmodules b/.gitmodules index 97cb99e..eced8d0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -12,4 +12,4 @@ url = https://github.com/asepharyana/asepharyana-hub-guide.git [submodule "apps/llm-api"] path = apps/llm-api - url = https://github.com/asepharyana/llm-api.git + url = https://github.com/asepharyana/asepharyana-hub-llm-api.git diff --git a/CLAUDE.md b/CLAUDE.md index 7d5f7b8..d6b132a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -26,7 +26,9 @@ asepharyana-hub/ - Submodule pointers are updated by CI/CD (via `repository_dispatch` or manual commit). - Current submodules: - `apps/hub` → `asepharyana/asepharyana-hub-hub` - - `apps/scraper` → `asepharyana/asepharyana-hub-scraper`. + - `apps/scraper` → `asepharyana/asepharyana-hub-scraper` + - `apps/llm-api` → `asepharyana/asepharyana-hub-llm-api` + - `apps/tools` → `asepharyana/asepharyana-hub-tools`. ### Infrastructure Stack - **Traefik v3.6** — reverse proxy, TLS termination, middleware chain, Prometheus metrics (`--metrics.prometheus=true`) diff --git a/apps/llm-api b/apps/llm-api index e1f5195..dfd6fa6 160000 --- a/apps/llm-api +++ b/apps/llm-api @@ -1 +1 @@ -Subproject commit e1f519540789f9e6d9548ab07e7a15d8dde78947 +Subproject commit dfd6fa66a7e0a4b08d2a3c7d69cc9c4407e8eb0a diff --git a/infra/traefik/dynamic/apps.yaml b/infra/traefik/dynamic/apps.yaml index 34eec08..11afed3 100644 --- a/infra/traefik/dynamic/apps.yaml +++ b/infra/traefik/dynamic/apps.yaml @@ -22,7 +22,7 @@ http: # ── LLM API (MiniCPM-V) ── llm-api: - rule: 'Host(`ai.asepharyana.my.id`) || Host(`ai.asepharya.web.id`)' + rule: 'Host(`ai.asepharyana.my.id`) || Host(`ai.asepharyana.web.id`)' entryPoints: - websecure tls: {}