-
Notifications
You must be signed in to change notification settings - Fork 562
feat(website): SEO model pages — 207 models, FAQ JSON-LD, partner node support #11892
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 2 commits
9bc0d2f
8fe2dee
8db4e46
213870a
a94c75c
d6704a9
2143f82
32a3161
a492d32
c38736c
c52e398
7e11c5a
5acb517
6c9947c
ef8ec75
4467e67
9832571
448953d
924374f
3ce00a8
2a81c2b
037ae5a
b0986f1
5feefc7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,188 @@ | ||
| --- | ||
| name: add-model-page | ||
| description: 'Add, update, or remove a model page entry on the comfy org website. Creates a PR to Comfy-Org/ComfyUI_frontend apps/website folder with the change.' | ||
| --- | ||
|
|
||
| # add-model-page | ||
|
|
||
| Add, update, or remove model pages in the ComfyUI website. | ||
|
|
||
| ## Trigger phrases | ||
|
|
||
| - `Add a model page for <model-name>` | ||
| - `Update the model page for <model-name>` | ||
| - `Remove <model-name> from model pages` | ||
|
|
||
| --- | ||
|
|
||
| ## Phase 1 — Parse the request | ||
|
|
||
| Extract: | ||
| - **action**: `add` | `update` | `remove` | ||
| - **model-name**: raw string (e.g. `flux1-schnell`, `flux1_dev.safetensors`) | ||
|
|
||
| Normalize to a slug: lowercase, replace `_` and `.` with `-`, strip file extensions. | ||
| Example: `flux1_dev.safetensors` → `flux1-dev` | ||
|
|
||
| --- | ||
|
|
||
| ## Phase 2 — Gather model data (ADD / UPDATE) | ||
|
|
||
| Find the ComfyUI_frontend repo root. Key files: | ||
|
|
||
| | File | Purpose | | ||
| |------|---------| | ||
| | `apps/website/src/config/models.ts` | Model array | | ||
| | `apps/website/src/i18n/translations.ts` | i18n string map | | ||
| | `apps/website/scripts/generate-models.ts` | Derives model data from workflow templates | | ||
|
|
||
| Run the generator to find the model: | ||
|
|
||
| ```bash | ||
| cd ComfyUI_frontend | ||
| pnpm tsx apps/website/scripts/generate-models.ts \ | ||
| | jq '.[] | select(.name | ascii_downcase | contains("MODEL_NAME"))' | ||
| ``` | ||
|
|
||
| Replace `MODEL_NAME` with the normalized slug (substring match). | ||
|
|
||
| The output object contains: | ||
| - `name` — exact filename (e.g. `flux1_dev.safetensors`) or display name for partner nodes | ||
| - `url` — HuggingFace download URL → use as `huggingFaceUrl` (empty `''` for partner nodes) | ||
| - `directory` — model subdirectory (e.g. `diffusion_models`) or `partner_nodes` for API models | ||
| - `workflowCount` — integer | ||
| - `suggestedSlug` — use this as `slug` if reasonable | ||
| - `suggestedDisplayName` — use as seed for i18n `displayName` | ||
|
|
||
| If the generator returns no match and the model is a known API/partner model, add it | ||
| manually as `directory: 'partner_nodes'` with an empty `huggingFaceUrl`. | ||
|
|
||
| --- | ||
|
|
||
| ## Phase 3 — Check for existing entry | ||
|
|
||
| ```bash | ||
| grep -n "slug: '${SLUG}'" apps/website/src/config/models.ts | ||
| ``` | ||
|
|
||
| - Match found + action is `add` → switch to UPDATE flow automatically | ||
| - No match + action is `update` → stop and tell the user | ||
|
|
||
| --- | ||
|
|
||
| ## Phase 4A — ADD: insert new entry | ||
|
|
||
| ### 4A.1 Build the entry | ||
|
|
||
| ```typescript | ||
| { | ||
| slug: 'MODEL-SLUG', | ||
| name: 'model_name.safetensors', // or display name for partner nodes | ||
| displayName: 'models.MODEL-SLUG.displayName' as TranslationKey, | ||
| description: 'models.MODEL-SLUG.description' as TranslationKey, | ||
| directory: 'diffusion_models', // from generate-models; or 'partner_nodes' | ||
| huggingFaceUrl: 'https://huggingface.co/...', // empty '' for partner nodes | ||
| docsUrl: 'https://docs.comfy.org/...', // optional: tutorial link | ||
| blogUrl: 'https://blog.comfy.org/...', // optional: blog post link | ||
| ogImage: '/images/models/MODEL-SLUG-og.png', | ||
| thumbnail: '/images/models/MODEL-SLUG-thumb.webp', | ||
| featured: true, | ||
| workflowCount: N, | ||
| tags: ['tag1', 'tag2'] as const, | ||
| publishedDate: 'YYYY-MM-DD', | ||
| modifiedDate: 'YYYY-MM-DD', | ||
| } | ||
| ``` | ||
|
|
||
| Tags: split the slug on `-`, drop pure numeric tokens, keep meaningful words. | ||
|
|
||
| ### 4A.2 Insert into models array | ||
|
|
||
| The array in `apps/website/src/config/models.ts` is sorted by `workflowCount` | ||
| descending. Find the first entry whose `workflowCount` is less than the new | ||
| entry's count and insert before it. If all are greater, append at the end. | ||
|
|
||
| ### 4A.3 Add i18n keys | ||
|
|
||
| In `apps/website/src/i18n/translations.ts`, find the line before | ||
| `} as const satisfies` and insert: | ||
|
|
||
| ```typescript | ||
| 'models.MODEL-SLUG.displayName': { | ||
| en: 'Human Display Name', | ||
| 'zh-CN': '' | ||
| }, | ||
| 'models.MODEL-SLUG.description': { | ||
| en: 'One sentence describing what this model does.', | ||
| 'zh-CN': '' | ||
| }, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Verify the skill currently instructs empty zh-CN values
rg -n "'zh-CN': ''" .claude/skills/add-model-page/SKILL.md
# Verify fallback logic in i18n helper uses nullish-coalescing (does not treat empty string as missing)
rg -n "return translations\\[key\\]\\[locale\\] \\?\\? translations\\[key\\]\\.en" apps/website/src/i18n/translations.tsRepository: Comfy-Org/ComfyUI_frontend Length of output: 174 🏁 Script executed: # Check if there are other instances of empty zh-CN in the skills directory
rg -n "'zh-CN': ''" .claude/skills/ --type markdown
# Verify the context around lines 113 and 117 to ensure they match the snippet
sed -n '110,120p' .claude/skills/add-model-page/SKILL.mdRepository: Comfy-Org/ComfyUI_frontend Length of output: 412 Populate empty Empty strings in translation keys prevent fallback to English because the i18n handler uses nullish coalescing ( Suggested fix 'models.MODEL-SLUG.displayName': {
en: 'Human Display Name',
- 'zh-CN': ''
+ 'zh-CN': 'Human Display Name'
},
'models.MODEL-SLUG.description': {
en: 'One sentence describing what this model does.',
- 'zh-CN': ''
+ 'zh-CN': 'One sentence describing what this model does.'
},🤖 Prompt for AI Agents |
||
| ``` | ||
|
|
||
| Use `suggestedDisplayName` from generate-models for the English `displayName`. | ||
|
|
||
| --- | ||
|
|
||
| ## Phase 4B — UPDATE: edit existing entry | ||
|
|
||
| Find the entry by slug. Apply only the fields requested. Update `modifiedDate` to | ||
| today. Leave all other fields unchanged. | ||
|
|
||
| --- | ||
|
|
||
| ## Phase 4C — REMOVE: delete entry | ||
|
|
||
| 1. Remove the entire object literal (including trailing comma) from the `models` array. | ||
| 2. Remove the two translation keys from `translations.ts`. | ||
| 3. Note in the PR description why the model was removed. | ||
|
|
||
| --- | ||
|
|
||
| ## Phase 5 — Verify TypeScript | ||
|
|
||
| ```bash | ||
| pnpm typecheck 2>&1 | grep -E "error|warning" | head -20 | ||
| ``` | ||
|
|
||
| Fix any type errors before proceeding. Common issues: | ||
| - Missing `as TranslationKey` cast on `displayName`/`description` | ||
| - New translation key not yet in `translations.ts` when `models.ts` references it | ||
|
|
||
| --- | ||
|
|
||
| ## Phase 6 — Create PR | ||
|
|
||
| ```bash | ||
| BRANCH="add-model-page-MODEL-SLUG" # or update- / remove- | ||
| git checkout -b $BRANCH | ||
| git add apps/website/src/config/models.ts apps/website/src/i18n/translations.ts | ||
| git commit -m "feat(models): add model page for MODEL-SLUG" | ||
| git push -u origin $BRANCH | ||
| gh pr create \ | ||
| --title "Add model page: MODEL-SLUG" \ | ||
| --body "$(cat <<'EOF' | ||
| Adds a new model page entry for MODEL-SLUG. | ||
|
|
||
| ## Changes | ||
| - `models.ts`: new entry with workflowCount N, directory DIRECTORY | ||
| - `translations.ts`: placeholder i18n keys (zh-CN needs translation) | ||
|
|
||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||
| ## Images needed | ||
| - `/images/models/MODEL-SLUG-og.png` (1200×630) | ||
| - `/images/models/MODEL-SLUG-thumb.webp` | ||
| EOF | ||
| )" | ||
| ``` | ||
|
|
||
| For UPDATE use branch `update-model-page-MODEL-SLUG`. | ||
| For REMOVE use `remove-model-page-MODEL-SLUG` and omit the images note. | ||
|
|
||
| --- | ||
|
|
||
| ## Error states | ||
|
|
||
| | Situation | Response | | ||
| |-----------|----------| | ||
| | Model not in workflow templates | Ask user to verify spelling or add it manually as a partner node | | ||
| | Slug already exists (add) | Switch to update flow automatically | | ||
| | Slug not found (update/remove) | Stop and ask user to confirm | | ||
| | Typecheck fails | Fix the error before pushing | | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,130 @@ | ||
| name: Model Page Discovery | ||
|
|
||
| on: | ||
| schedule: | ||
| - cron: '0 9 * * 1' | ||
| workflow_dispatch: | ||
|
|
||
| jobs: | ||
| discover: | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: read | ||
| issues: write | ||
|
|
||
| steps: | ||
| - name: Checkout ComfyUI_frontend | ||
| uses: actions/checkout@v6 | ||
| with: | ||
| path: ComfyUI_frontend | ||
|
|
||
| - name: Checkout workflow_templates | ||
| uses: actions/checkout@v6 | ||
| with: | ||
| repository: Comfy-Org/workflow_templates | ||
| path: workflow_templates | ||
|
|
||
| - name: Setup Node | ||
| uses: actions/setup-node@v6 | ||
| with: | ||
| node-version: '20' | ||
|
|
||
| - name: Setup pnpm | ||
| uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4.4.0 | ||
| with: | ||
| version: latest | ||
| run_install: false | ||
|
|
||
| - name: Install dependencies | ||
| run: pnpm install --frozen-lockfile | ||
| working-directory: ComfyUI_frontend | ||
|
|
||
| - name: Run model discovery script | ||
| run: pnpm tsx apps/website/scripts/generate-models.ts out.json | ||
| working-directory: ComfyUI_frontend | ||
| env: | ||
| WORKFLOW_TEMPLATES_PATH: ${{ github.workspace }}/workflow_templates | ||
|
|
||
| - name: Compare against existing models config | ||
| id: compare | ||
| shell: bash | ||
| run: | | ||
| set -euo pipefail | ||
| cd ComfyUI_frontend | ||
|
|
||
| NEW_SLUGS=$(node -e " | ||
| const fs = require('fs'); | ||
| const models = JSON.parse(fs.readFileSync('out.json', 'utf8')); | ||
| const arr = Array.isArray(models) ? models : Object.values(models); | ||
| const slugs = arr.map(m => m.suggestedSlug ?? m.slug).filter(Boolean); | ||
| console.log(JSON.stringify(slugs)); | ||
| ") | ||
|
|
||
| EXISTING_SLUGS=$(node -e " | ||
| const fs = require('fs'); | ||
| const content = fs.readFileSync( | ||
| 'apps/website/src/config/models.ts', | ||
| 'utf8' | ||
| ); | ||
| const matches = [ | ||
| ...content.matchAll(/slug\s*:\s*['\"]([^'\"]+)['\"]/g) | ||
| ]; | ||
| const slugs = matches.map(m => m[1]); | ||
| console.log(JSON.stringify(slugs)); | ||
| " 2>/dev/null || echo '[]') | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| ADDED_SLUGS=$(node -e " | ||
| const newSlugs = $NEW_SLUGS; | ||
| const existing = $EXISTING_SLUGS; | ||
| const existingSet = new Set(existing); | ||
| const added = newSlugs.filter(s => !existingSet.has(s)); | ||
| console.log(JSON.stringify(added)); | ||
| ") | ||
|
|
||
| COUNT=$(node -e "console.log($ADDED_SLUGS.length)") | ||
| echo "new_count=$COUNT" >> $GITHUB_OUTPUT | ||
| echo "new_slugs=$ADDED_SLUGS" >> $GITHUB_OUTPUT | ||
|
|
||
| if [ "$COUNT" -eq 0 ]; then | ||
| echo "No new models found." | ||
| else | ||
| echo "Found $COUNT new model(s): $ADDED_SLUGS" | ||
| fi | ||
|
|
||
| - name: Open GitHub issue for new models | ||
| if: steps.compare.outputs.new_count != '0' | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| NEW_SLUGS: ${{ steps.compare.outputs.new_slugs }} | ||
| NEW_COUNT: ${{ steps.compare.outputs.new_count }} | ||
| shell: bash | ||
| run: | | ||
| SLUG_LIST=$(node -e " | ||
| const slugs = $NEW_SLUGS; | ||
| console.log(slugs.map(s => '- \`' + s + '\`').join('\n')); | ||
| ") | ||
|
|
||
| gh issue create \ | ||
| --repo "$GITHUB_REPOSITORY" \ | ||
| --title "New models detected — add to model pages" \ | ||
| --body "## $NEW_COUNT new model(s) found in workflow_templates | ||
|
|
||
| The weekly model discovery scan found models not yet in | ||
| \`apps/website/src/config/models.ts\`. | ||
|
|
||
| ### New slugs ($NEW_COUNT) | ||
|
|
||
| $SLUG_LIST | ||
|
|
||
| ### Next steps | ||
|
|
||
| 1. Review which of these warrant an SEO model page | ||
| 2. Run \`pnpm tsx apps/website/scripts/generate-models.ts\` locally | ||
| 3. Add entries to \`apps/website/src/config/models.ts\` via PR | ||
|
|
||
| --- | ||
| *Generated by the [model-page-discovery workflow](https://github.com/$GITHUB_REPOSITORY/actions/workflows/model-page-discovery.yaml)*" | ||
|
|
||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||
| - name: No new models found | ||
| if: steps.compare.outputs.new_count == '0' | ||
| run: echo "No new models found — nothing to do." | ||
Uh oh!
There was an error while loading. Please reload this page.