diff --git a/backend/app/api/system_config.py b/backend/app/api/system_config.py index e7d6749..9307453 100644 --- a/backend/app/api/system_config.py +++ b/backend/app/api/system_config.py @@ -66,7 +66,7 @@ async def update_config( ): """Update a single config key. Only directors can change settings.""" value = body.get("value", "") - valid_keys = {"notification_time", "holidays"} + valid_keys = {"notification_time", "holidays", "ai_summary_prompt"} if key not in valid_keys: raise HTTPException(status_code=400, detail=f"不支持的配置项: {key}") diff --git a/backend/app/services/ai_summary.py b/backend/app/services/ai_summary.py index 005b4aa..496218c 100644 --- a/backend/app/services/ai_summary.py +++ b/backend/app/services/ai_summary.py @@ -6,6 +6,7 @@ from app.config import settings from app.services.dashboard import get_weekly_report, get_week_range from app.services.light_board import get_light_board from app.models.ai_summary import AISummary +from app.models.system_config import SystemConfig from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from uuid import UUID @@ -240,6 +241,12 @@ async def generate_summary( leaves=leave_overview.get("leave_list", []), ) + # Load custom system prompt (director/leader can override via system settings) + custom_row = await db.get(SystemConfig, "ai_summary_prompt") + system_prompt = SUMMARY_SYSTEM_PROMPT + if custom_row and custom_row.value and custom_row.value.strip(): + system_prompt = custom_row.value.strip() + # Call LLM headers = {"Content-Type": "application/json"} if settings.AI_API_KEY: @@ -248,7 +255,7 @@ async def generate_summary( payload = { "model": settings.AI_MODEL, "messages": [ - {"role": "system", "content": SUMMARY_SYSTEM_PROMPT}, + {"role": "system", "content": system_prompt}, {"role": "user", "content": user_prompt}, ], "max_tokens": settings.AI_MAX_TOKENS, diff --git a/frontend/src/views/desktop/Settings.vue b/frontend/src/views/desktop/Settings.vue index db8d4be..7913b2b 100644 --- a/frontend/src/views/desktop/Settings.vue +++ b/frontend/src/views/desktop/Settings.vue @@ -18,6 +18,8 @@ const notificationTimeLoading = ref(false) const holidays = ref('') const holidaysLoading = ref(false) const holidaysRefreshing = ref(false) +const aiPrompt = ref('') +const aiPromptLoading = ref(false) const importLoading = ref(false) const importFile = ref(null) @@ -38,6 +40,9 @@ onMounted(async () => { if (res.data?.holidays) { holidays.value = res.data.holidays } + if (res.data?.ai_summary_prompt) { + aiPrompt.value = res.data.ai_summary_prompt + } } catch (_) {} }) @@ -91,6 +96,16 @@ async function handleSaveHolidays() { } finally { holidaysLoading.value = false } } +async function handleSaveAiPrompt() { + aiPromptLoading.value = true + try { + await api.put('/system-config/ai_summary_prompt', { value: aiPrompt.value }) + ElMessage.success(aiPrompt.value.trim() ? 'AI 提示词已保存' : '已恢复默认提示词') + } catch (e: any) { + ElMessage.error(e.response?.data?.detail || '保存失败') + } finally { aiPromptLoading.value = false } +} + async function handleRefreshHolidays() { holidaysRefreshing.value = true try { @@ -268,6 +283,36 @@ async function handleImportPreview() { + + + +
+
+ +
+ + 保存 +
+

+ 自定义 AI 生成周报摘要时的行为风格。支持 Markdown 格式约束。留空则恢复默认提示词。 +

+
+
+
+