feat(agent): add LLM-powered metadata enrichment system with AgentCLI and PostProcessor

Introduce an agent skill framework for LLM-driven metadata enrichment:

- AgentCLI (py/agent_cli/): in-process wrappers around internal services
  using standard relative imports, eliminating the need for sys.path hacks
- LLMService: centralized BYOK (bring-your-own-key) LLM client supporting
  OpenAI, Ollama, and custom OpenAI-compatible endpoints
- PostProcessor: deterministic engine that applies LLM output via AgentCLI
  (replaces old handler.py + _BASE_MODEL_ALIASES approach)
- SkillRegistry: filesystem-based skill discovery (skill.yaml + prompt.md)
- AgentService: orchestrates skill execution with WebSocket progress
- Frontend AgentManager: WebSocket listeners, skill execution, config UI
- Context menu entries (single + bulk) for "Enrich Metadata (Agent)"
- Settings UI for AI Provider configuration (BYOK)
- Full i18n support across 9 locales

Bug fixes found during review:
- aiohttp.web.json_response: status_code= -> status=
- settings_modal cancelEditApiKey: wrong argument position
- AgentManager.isLlmConfigured: allow Ollama without API key
- PostProcessor._merge_tags: lowercase all tags to match TagUpdateService
This commit is contained in:
Will Miao
2026-07-02 20:51:11 +08:00
parent fe90f7f9b1
commit cf898da193
44 changed files with 5937 additions and 2180 deletions

View File

@@ -657,6 +657,23 @@
"proxyPassword": "Пароль (необязательно)",
"proxyPasswordPlaceholder": "пароль",
"proxyPasswordHelp": "Пароль для аутентификации на прокси (если требуется)"
},
"aiProvider": {
"title": "Поставщик ИИ",
"provider": "Поставщик",
"providerHelp": "Выберите поставщика LLM. OpenAI и Ollama используют предустановленные API-эндпоинты. Пользовательский позволяет указать любой совместимый с OpenAI эндпоинт.",
"custom": "Пользовательский (совместимый с OpenAI)",
"apiBase": "Базовый URL API",
"apiBaseHelp": "Базовый URL для LLM API (например, https://api.openai.com/v1). Оставьте пустым, чтобы использовать значение по умолчанию.",
"apiBasePlaceholder": "https://api.openai.com/v1",
"apiKey": "API-ключ",
"apiKeyHelp": "Ваш API-ключ поставщика LLM. Хранится локально и никогда не отправляется на другие серверы, кроме выбранного поставщика LLM.",
"apiKeyPlaceholder": "sk-...",
"apiKeyNotSet": "Не задан",
"apiKeyConfigured": "Настроен",
"apiKeySet": "Настроить",
"model": "Модель",
"modelHelp": "Имя модели для использования (например, deepseek-v4-flash, gemini-2.5-flash, gemma4:12b). Проверьте доступные модели у вашего поставщика."
}
},
"loras": {
@@ -754,7 +771,8 @@
"completed": "Завершено: {success} перемещено, {skipped} пропущено, {failures} не удалось",
"complete": "Автоматическая организация завершена",
"error": "Ошибка: {error}"
}
},
"enrichHfAgent": "Обогатить метаданные (ИИ)"
},
"contextMenu": {
"refreshMetadata": "Обновить данные Civitai",
@@ -778,7 +796,8 @@
"shareRecipe": "Поделиться рецептом",
"viewAllLoras": "Посмотреть все LoRAs",
"downloadMissingLoras": "Загрузить отсутствующие LoRAs",
"deleteRecipe": "Удалить рецепт"
"deleteRecipe": "Удалить рецепт",
"enrichHfAgent": "Обогатить метаданные (ИИ)"
}
},
"recipes": {
@@ -2081,6 +2100,12 @@
"moveFailed": "Failed to move item: {message}",
"copiedToClipboard": "Скопировано в буфер обмена",
"downloadStarted": "Загрузка начата"
},
"agent": {
"llmNotConfigured": "Поставщик ИИ не настроен. Включите его в Настройки → Поставщик ИИ.",
"enrichStarted": "Обогащение метаданных с помощью ИИ...",
"enrichComplete": "Обогащение метаданных завершено: {{summary}}",
"enrichFailed": "Ошибка обогащения метаданных: {{error}}"
}
},
"doctor": {