%% 坐席端 AI 辅助消息框 — 类图 %% 文档版本: v1.0 %% 创建日期: 2026-07-11 classDiagram direction TB class WingmanService { -str api_url -str api_key -float timeout -httpx.AsyncClient _client -aioredis.Redis _redis -str _COMPLETION_SYSTEM_PROMPT -str _TONE_ADJUST_SYSTEM_PROMPT -str _POLISH_SYSTEM_PROMPT -str _REWRITE_SYSTEM_PROMPT +__init__(redis_client: Optional[Redis]) +async generate_completion(conversation_id: str, current_text: str, messages: List[Dict], max_length: int) Dict +async adjust_tone(conversation_id: str, selected_text: str, full_text: str, tone: str, messages: List[Dict]) Dict +async polish_text(conversation_id: str, text: str, action: str, messages: List[Dict]) Dict +async rewrite_versions(conversation_id: str, current_text: str, messages: List[Dict], generate_count: int, include_knowledge: bool) Dict -async _call_wingman_api(context_messages: List[Dict], temperature: float) Optional[str] -_build_context_messages(messages: List[Dict], system_prompt: str) List[Dict] -async _get_cache(key: str) Optional[Dict] -async _set_cache(key: str, value: Dict, ttl: int) void -_make_cache_key(text: str, conversation_id: str) str -async _search_knowledge(query: str) Optional[str] -_parse_json_response(content: str, default: Dict) Dict } class WingmanAPIRouter { +POST autocomplete(conversation_id, request: AutocompleteRequest, agent, db, wingman_service) +POST tone_adjust(conversation_id, request: ToneAdjustRequest, agent, db, wingman_service) +POST polish(conversation_id, request: PolishRequest, agent, db, wingman_service) +POST rewrite(conversation_id, request: RewriteRequest, agent, db, wingman_service) -async _validate_conversation(conversation_id, agent, db) Conversation -async _get_recent_messages(conversation_id, db, limit) List[Dict] } class AutocompleteRequest { +str current_text +int cursor_position +int max_length } class ToneAdjustRequest { +str selected_text +str full_text +str tone } class PolishRequest { +str text +str action +bool conversation_context } class RewriteRequest { +str current_text +int generate_count +bool include_knowledge } class WingmanTS { +autocomplete(convId: str, text: str, cursorPos: int, signal: AbortSignal) Promise~AutocompleteResult~ +adjustTone(convId: str, selectedText: str, fullText: str, tone: ToneType, signal: AbortSignal) Promise~ToneAdjustResult~ +polishText(convId: str, text: str, action: PolishAction, signal: AbortSignal) Promise~PolishResult~ +rewriteVersions(convId: str, currentText: str, signal: AbortSignal) Promise~RewriteResult~ } class UseAiAssist { +Ref~string~ ghostText +Ref~boolean~ isCompletLoading +Ref~boolean~ autocompleteEnabled +Ref~boolean~ tonePopoverVisible +Ref~boolean~ polishPanelVisible +Ref~boolean~ rewritePanelVisible +triggerAutocomplete() void +acceptGhostText() void +clearGhostText() void +adjustTone(selectedText: str, fullText: str, tone: ToneType) Promise~void~ +polishText(action: PolishAction) Promise~void~ +rewriteVersions() Promise~void~ +cleanup() void } class GhostText { +Props: ghostText: string, textareaRef: HTMLTextAreaElement +Emits: accept, dismiss -calculateCursorPos(textarea: HTMLTextAreaElement) {x: number, y: number} } class AiAssistToolbar { +Props: autocompleteEnabled: boolean, hasSelection: boolean, hasText: boolean +Emits: toggleAutocomplete, toneAdjust, polish, rewrite } class ToneAdjustPopover { +Props: visible: boolean, loading: boolean, result: ToneAdjustResult|null, originalText: string +Emits: select(tone: ToneType), replace, cancel } class PolishPanel { +Props: visible: boolean, loading: boolean, result: PolishResult|null, originalText: string +Emits: action(action: PolishAction), replace(text: string), cancel } class RewritePanel { +Props: visible: boolean, loading: boolean, result: RewriteResult|null +Emits: replace(text: string), append(text: string), cancel } class ReplyBox { -UseAiAssist aiAssist -Ref~string~ inputText -HTMLTextAreaElement inputRef +handleKeydown(event: KeyboardEvent) void +handleInput() void } %% 后端关系 WingmanAPIRouter --> WingmanService : Depends (DI) WingmanAPIRouter --> AutocompleteRequest : 验证请求体 WingmanAPIRouter --> ToneAdjustRequest : 验证请求体 WingmanAPIRouter --> PolishRequest : 验证请求体 WingmanAPIRouter --> RewriteRequest : 验证请求体 %% 前端关系 WingmanTS --> AutocompleteRequest : HTTP 请求 UseAiAssist --> WingmanTS : 调用 API ReplyBox --> UseAiAssist : composable ReplyBox --> GhostText : 渲染幽灵文字 ReplyBox --> AiAssistToolbar : 渲染工具栏 ReplyBox --> ToneAdjustPopover : 弹出浮层 ReplyBox --> PolishPanel : 弹出面板 ReplyBox --> RewritePanel : 弹出面板