From 57c8a26147df30df68fa916bb3484166c94e4440 Mon Sep 17 00:00:00 2001 From: selfrelease Date: Sun, 19 Jul 2026 09:36:42 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20LLM=E5=A4=9A=E9=98=B6=E6=AE=B5=E4=BA=A4?= =?UTF-8?q?=E4=BA=92=E5=BC=8FSchema=E7=94=9F=E6=88=90=20+=20UI=E5=B8=83?= =?UTF-8?q?=E5=B1=80=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - AI Service: 多阶段对话模型(理解→澄清→生成→校验→确认),支持对话历史和当前Schema上下文 - Backend: 适配多阶段AI模型,Gateway/Service/Controller传递history和currentSchema - Frontend: AiDesignerChat组件重写,支持阶段徽章、快速回复、Schema校验展示 - Frontend: 表单/流程设计器布局优化,AI助手和Schema预览作为独立列 - Frontend: 流程设计器元数据和模式选择器合并为一行 - Keycloak: 自定义登录主题(中文化) - 修复CSS媒体查询括号平衡问题 --- admin-web/src/AiDesignerChat.tsx | 150 ++++++++++++++++++ admin-web/src/App.tsx | 15 +- admin-web/src/ProcessDesigner.tsx | 23 ++- admin-web/src/auth.ts | 1 + admin-web/src/schema.ts | 8 +- admin-web/src/styles.css | 25 ++- ai-service/app/main.py | 24 ++- ai-service/app/models.py | 78 +++++++++ ai-service/app/qwen.py | 99 +++++++++++- .../aioa/ai/api/AiDesignerController.kt | 43 +++++ .../aioa/ai/application/AiDesignerService.kt | 47 ++++++ .../aioa/ai/domain/DesignerSuggestion.kt | 57 +++++++ .../infrastructure/HttpAiDesignerGateway.kt | 31 ++++ deploy/compose/compose.yaml | 1 + deploy/compose/keycloak/realm-aioa.json | 6 +- .../login/messages/messages_zh_CN.properties | 105 ++++++++++++ .../themes/aioa/login/resources/css/login.css | 124 +++++++++++++++ .../themes/aioa/login/resources/js/prefill.js | 18 +++ .../themes/aioa/login/theme.properties | 12 ++ 19 files changed, 853 insertions(+), 14 deletions(-) create mode 100644 admin-web/src/AiDesignerChat.tsx create mode 100644 backend/boot/src/main/kotlin/com/all8ai/aioa/ai/api/AiDesignerController.kt create mode 100644 backend/boot/src/main/kotlin/com/all8ai/aioa/ai/application/AiDesignerService.kt create mode 100644 backend/boot/src/main/kotlin/com/all8ai/aioa/ai/domain/DesignerSuggestion.kt create mode 100644 backend/boot/src/main/kotlin/com/all8ai/aioa/ai/infrastructure/HttpAiDesignerGateway.kt create mode 100644 deploy/compose/keycloak/themes/aioa/login/messages/messages_zh_CN.properties create mode 100644 deploy/compose/keycloak/themes/aioa/login/resources/css/login.css create mode 100644 deploy/compose/keycloak/themes/aioa/login/resources/js/prefill.js create mode 100644 deploy/compose/keycloak/themes/aioa/login/theme.properties diff --git a/admin-web/src/AiDesignerChat.tsx b/admin-web/src/AiDesignerChat.tsx new file mode 100644 index 0000000..7d34996 --- /dev/null +++ b/admin-web/src/AiDesignerChat.tsx @@ -0,0 +1,150 @@ +import { useState, useRef, useEffect } from 'react'; +import { api } from './api'; +import type { Field, ControlType } from './schema'; + +export type DesignerStage = 'UNDERSTANDING' | 'CLARIFYING' | 'GENERATING' | 'VALIDATING' | 'CONFIRMING'; + +export type DesignerSuggestion = { + stage: DesignerStage; + formTitle?: string; + formKey?: string; + fields: { + key: string; label: string; control: string; required: boolean; + placeholder?: string; options?: string[]; helperText?: string; + }[]; + process?: { + mode: string; + steps: { name: string; assigneeVariable: string }[]; + conditionThresholdDays?: number | null; + }; + summary: string; + understanding: string; + assumptions: string[]; + needsClarification: string[]; + validationIssues?: { field: string; issue: string; severity: string }[]; + schemaReady: boolean; +}; + +type ChatMessage = { + role: 'user' | 'assistant'; + content: string; + suggestion?: DesignerSuggestion; +}; + +export type ApplySuggestion = (s: DesignerSuggestion) => void; + +const stageLabels: Record = { + UNDERSTANDING: '🧠 理解需求', + CLARIFYING: '❓ 澄清确认', + GENERATING: '📋 生成 Schema', + VALIDATING: '✅ 校验 Schema', + CONFIRMING: '🎯 等待确认', +}; + +export function AiDesignerChat({ onApply, contextLabel, getCurrentSchema }: { onApply: ApplySuggestion; contextLabel: string; getCurrentSchema?: () => string }) { + const [messages, setMessages] = useState([ + { role: 'assistant', content: '你好!我是 AI 设计助手。用自然语言描述你想要的表单或审批流程,我来帮你生成。\n\n例如:\n• "报销申请表单,包含报销人、金额、日期、事由"\n• "报销审批:先部门主管审批,超过5000元加财务复核,最后OA管理员审批"' }, + ]); + const [input, setInput] = useState(''); + const [loading, setLoading] = useState(false); + const [currentStage, setCurrentStage] = useState('UNDERSTANDING'); + const scrollRef = useRef(null); + + useEffect(() => { + scrollRef.current?.scrollTo({ top: scrollRef.current.scrollHeight, behavior: 'smooth' }); + }, [messages, loading]); + + function buildHistory(msgs: ChatMessage[]) { + return msgs.slice(1).map(m => ({ role: m.role, content: m.content })); + } + + async function send(presetText?: string) { + const text = (presetText ?? input).trim(); + if (!text || loading) return; + setInput(''); + const next = [...messages, { role: 'user' as const, content: text }]; + setMessages(next); + setLoading(true); + try { + const result = await api<{ suggestion: DesignerSuggestion; model: string }>('/ai/designer-suggestions', { + method: 'POST', + body: JSON.stringify({ + message: text, + history: buildHistory(next.slice(0, -1)), + currentSchema: getCurrentSchema?.() ?? null, + timezone: Intl.DateTimeFormat().resolvedOptions().timeZone || 'Asia/Shanghai', + }), + }); + const s = result.suggestion; + setCurrentStage(s.stage); + const parts = formatSuggestionMessage(s); + setMessages([...next, { role: 'assistant', content: parts, suggestion: s }]); + } catch (e) { + setMessages([...next, { role: 'assistant', content: `⚠️ ${e instanceof Error ? e.message : 'AI 服务暂时不可用'}` }]); + } finally { + setLoading(false); + } + } + + return
+
+ ✨ AI 设计助手 + {contextLabel} + {stageLabels[currentStage]} +
+
+ {messages.map((m, i) =>
+
{m.content}
+ {m.suggestion && m.suggestion.fields.length > 0 && (m.suggestion.stage === 'GENERATING' || m.suggestion.stage === 'VALIDATING' || m.suggestion.stage === 'CONFIRMING') && ( + + )} + {m.suggestion && m.suggestion.needsClarification.length > 0 && m.suggestion.stage === 'CLARIFYING' && ( +
+ {m.suggestion.needsClarification.map((q, qi) => )} +
+ )} + {m.suggestion && m.suggestion.schemaReady && ( +
✅ Schema 已确认,可应用到设计器
+ )} +
)} + {loading &&
思考中…
} +
+
+