Skip to content

feat(ai): add per-list keywords to guide AI classification - #3

Open
LIPiston wants to merge 1 commit into
GEMILUXVII:mainfrom
LIPiston:feat/list-keywords
Open

feat(ai): add per-list keywords to guide AI classification#3
LIPiston wants to merge 1 commit into
GEMILUXVII:mainfrom
LIPiston:feat/list-keywords

Conversation

@LIPiston

@LIPiston LIPiston commented Aug 28, 2026

Copy link
Copy Markdown

Closes #2

功能说明

在新建/编辑 List 时可填写「AI 分类关键词(可选)」,例如给 magisk List 填 lsposed, magisk, root。分类时这些关键词会提供给 AI,并明确要求优先按用户关键词匹配——自定义关键词比内置通用映射更可信。

适用范围:网页端单个 AI 分类、一键整理、浏览器扩展(扩展走同一个 /api/ai/classify 接口,自动生效)。

改动

  • 数据层:List 模型新增 keywords 字段(逗号分隔字符串,默认空)。项目无 migrations 目录,部署时需同步 schema(npx prisma db push)
  • AI 侧:分类 prompt(中/英)的「现有 Lists」列表展示每个 List 的关键词,规则新增「关键词优先」;classify 路由按中英文逗号/顿号/换行拆分关键词
  • API:/api/lists(GET/POST)、/api/lists/[listId](GET/PATCH)、/api/stats 支持并返回 keywords(上限 200 字符,空字符串即清空);/api/export/api/import 备份/恢复包含 keywords
  • 前端:新建/编辑 List 对话框增加关键词输入框与说明文字;顺带将这两个对话框接上已备好的 list.* i18n 键并补全新键(zh/en);sidebar 与 stars 页面类型/回调透传

验证

  • prisma generate + tsc --noEmit 通过
  • next build 成功
  • eslint 改动文件 0 error(仅 2 个改动前已存在的 unused-import warning)

Summary by Sourcery

Add user-configurable List keywords to improve AI classification and preserve them across the application’s List management and backup flows.

New Features:

  • Allow each List to store optional classification keywords that guide AI repository categorization with user-defined matches taking precedence.
  • Expose List keywords across creation, editing, listing, statistics, import, and export flows.
  • Add localized keyword fields and messaging to the List creation and editing dialogs.

Enhancements:

  • Include per-List keywords in English and Chinese AI classification prompts.
  • Propagate keyword data through sidebar and stars-page List types and callbacks.

Build:

  • Upgrade the Docker build image to Node.js 22, pin pnpm to version 11.11.0, and configure permitted dependency build scripts.

Closes GEMILUXVII#2

- Add `keywords` field to List model (comma-separated, optional)
- Provide each list's keywords to the AI in classify prompts (zh/en)
  and instruct the model to prioritize user-defined keyword matches
- Support keywords in lists APIs, stats, export and import
- Add keywords input to create/edit list dialogs (i18n zh/en)
@sourcery-ai

sourcery-ai Bot commented Aug 28, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds an optional per-List keywords field end to end: persisted and validated through APIs and backups, displayed and prioritized in bilingual AI classification prompts, and editable through localized create/edit List dialogs with propagation across the sidebar and Stars page.

Sequence diagram for keyword-guided AI classification

sequenceDiagram
    participant Client
    participant ClassifyAPI
    participant Database
    participant AIProvider

    Client->>ClassifyAPI: POST /api/ai/classify
    ClassifyAPI->>Database: findMany Lists with keywords
    Database-->>ClassifyAPI: List records
    ClassifyAPI->>ClassifyAPI: split keywords by comma, ideographic comma, delimiter, or newline
    ClassifyAPI->>AIProvider: buildPromptZh or buildPromptEn with listInfos
    AIProvider-->>ClassifyAPI: classification using keyword precedence
    ClassifyAPI-->>Client: classification result
Loading

File-Level Changes

Change Details Files
Add persistent per-List AI classification keywords and expose them throughout the data lifecycle.
  • Add an optional, default-empty keywords column to the List model.
  • Accept, validate, return, and persist keywords across list APIs, including empty-string clearing.
  • Include keywords in export/import backups and statistics responses.
prisma/schema.prisma
src/app/api/lists/route.ts
src/app/api/lists/[listId]/route.ts
src/app/api/stats/route.ts
src/app/api/export/route.ts
src/app/api/import/route.ts
Use user-defined List keywords to steer AI classification ahead of generic category mappings.
  • Fetch keywords with candidate Lists and split comma-, Chinese punctuation-, and newline-delimited values into trimmed arrays.
  • Render keywords in Chinese and English classification prompts.
  • Add explicit prompt rules requiring matching user keywords to take precedence.
src/app/api/ai/classify/route.ts
src/lib/ai/openai.ts
src/lib/ai/types.ts
Provide keyword editing in the List UI and propagate the field through list-related components.
  • Add keyword inputs, hints, reset/edit behavior, and localized labels to create and edit dialogs.
  • Pass keywords through sidebar and Stars page state, callbacks, and API requests.
  • Add corresponding Chinese and English translations.
src/components/create-list-dialog.tsx
src/components/edit-list-dialog.tsx
src/components/sidebar.tsx
src/app/stars/client.tsx
messages/zh.json
messages/en.json

Assessment against linked issues

Issue Objective Addressed Explanation
#2 Allow users to configure and persist per-List classification keywords when creating or editing a List. The PR adds keyword input and creation support, but the shown PATCH implementation for /api/lists/[listId] only extends validation and GET output; it does not appear to include keywords in the update data. Consequently, keywords submitted when editing a List may not be persisted.
#2 Provide each List's configured keywords to the AI classification prompt and instruct the AI to prioritize matching user-defined keywords.
#2 Include List keywords in List APIs and export/import data so the configuration is exposed and preserved across supported workflows.

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@LIPiston

Copy link
Copy Markdown
Author

用ai造的,我自己试用一段时间
也可以review之后直接合

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="src/components/create-list-dialog.tsx" line_range="74-79" />
<code_context>
             <div className="grid gap-2">
-              <Label htmlFor="name">名称</Label>
+              <Label htmlFor="name">{t("name")}</Label>
               <Input
                 id="name"
                 value={name}
                 onChange={(e) => setName(e.target.value)}
-                placeholder="例如:前端工具"
+                placeholder={t("namePlaceholder")}
                 autoFocus
               />
             </div>
             <div className="grid gap-2">
</code_context>
<issue_to_address>
**issue (bug_risk):** The keyword inputs have no client-side 200-character limit, so entering more than 200 characters causes the create or update API to return 400; the corresponding handlers ignore `response.ok`, still refresh/close the dialog, and present the failed save as successful.

**Triggers:** When a user enters more than 200 characters in the keyword field.

**Suggested fix:** Add `maxLength={200}` to both inputs and check the fetch response before closing the dialog or refreshing state.
</issue_to_address>

Sourcery assessment

Needs a human reviewer. 1 finding to address first, and the new keywords are persisted and fed into AI prompts, so incorrect values or precedence rules can cause repositories to be assigned to the wrong lists. Reverting stops the behavior but does not automatically undo existing classifications; those assignments are bounded and can be corrected or re-run.

Blocking findings: src/components/create-list-dialog.tsx:79


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +74 to +79
<Input
id="keywords"
value={keywords}
onChange={(e) => setKeywords(e.target.value)}
placeholder={t("keywordsPlaceholder")}
/>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): The keyword inputs have no client-side 200-character limit, so entering more than 200 characters causes the create or update API to return 400; the corresponding handlers ignore response.ok, still refresh/close the dialog, and present the failed save as successful.

Triggers: When a user enters more than 200 characters in the keyword field.

Suggested fix: Add maxLength={200} to both inputs and check the fetch response before closing the dialog or refreshing state.

@LIPiston
LIPiston force-pushed the feat/list-keywords branch 3 times, most recently from 68c8f60 to c5656a9 Compare August 28, 2026 20:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feature] 分类可以设置关键词

1 participant