export interface DirectAgentAngleEditOptions { horizontalAngle: number; verticalAngle: number; zoom: number; loraScale?: number; } export function clampAngleEditNumber( value: number | undefined, min: number, max: number, fallback: number, ) { if (!Number.isFinite(value)) return fallback; return Math.min(max, Math.max(min, Number(value))); } function parseFirstNumberMatch(text: string, patterns: RegExp[]) { for (const pattern of patterns) { const match = text.match(pattern); const value = Number(match?.[1]); if (Number.isFinite(value)) return value; } return undefined; } export function inferAngleEditOptionsFromText(text: string): DirectAgentAngleEditOptions { const normalizedText = String(text || "").toLowerCase().replace(/\s+/g, ""); const explicitHorizontal = parseFirstNumberMatch(normalizedText, [ /(?:水平角|水平|环绕|左右|horizontal|h)[::]?(-?\d{1,3})(?:度|°)?/, /(?:旋转|转|转到|换成|改成)(-?\d{1,3})(?:度|°)/, ]); const explicitVertical = parseFirstNumberMatch(normalizedText, [ /(?:垂直角|垂直|俯仰|上下|vertical|v)[::]?(-?\d{1,3})(?:度|°)?/, ]); const explicitZoom = parseFirstNumberMatch(normalizedText, [ /(?:zoom|缩放|景别)[::]?(\d{1,2})(?:倍|x)?/, ]); let horizontalAngle = explicitHorizontal ?? 45; if (explicitHorizontal === undefined) { if (/背面|背后|背视|后视|back/.test(normalizedText)) { horizontalAngle = 180; } else if (/左侧|左边|左视|left/.test(normalizedText)) { horizontalAngle = 270; } else if (/右侧|右边|右视|侧面|侧视|profile|side/.test(normalizedText)) { horizontalAngle = 90; } else if (/正面|正视|front/.test(normalizedText)) { horizontalAngle = 0; } else if (/三分之四|四分之三|斜侧|45度|45°/.test(normalizedText)) { horizontalAngle = 45; } } let verticalAngle = explicitVertical ?? 0; if (explicitVertical === undefined) { if (/俯视|俯拍|鸟瞰|高机位|top|overhead/.test(normalizedText)) { verticalAngle = 45; } else if (/仰视|仰拍|低机位|lowangle/.test(normalizedText)) { verticalAngle = -20; } else if (/平视|eyelevel/.test(normalizedText)) { verticalAngle = 0; } } let zoom = explicitZoom ?? 5; if (explicitZoom === undefined) { if (/特写|近景|拉近|推近|zoomin/.test(normalizedText)) { zoom = 7; } else if (/远景|全身|拉远|zoomout/.test(normalizedText)) { zoom = 3; } else if (/中景/.test(normalizedText)) { zoom = 5; } } return { horizontalAngle: clampAngleEditNumber(horizontalAngle, 0, 360, 45), verticalAngle: clampAngleEditNumber(verticalAngle, -30, 90, 0), zoom: clampAngleEditNumber(zoom, 0, 10, 5), }; }