ultisuite-client/components/ai/ai-chat-iframe.tsx
R3D347HR4Y 9e9fd208ad
Some checks are pending
E2E / Playwright e2e (push) Waiting to run
feat(admin-settings): enhance admin settings with new components and layout improvements
- Introduced new components for managing admin settings, including AdminListControls, AdminSettingsCard, and TechBrandSelectLabel.
- Implemented dynamic loading for admin settings sections to optimize performance.
- Enhanced the layout of various admin settings sections for better user experience.
- Updated the AiAssistantSection to include LLM provider management and improved model selection.
- Refactored authentication settings to streamline configuration and improve accessibility.
2026-06-15 00:22:20 +02:00

144 lines
4.1 KiB
TypeScript

"use client"
import { useEffect, useMemo, useRef, useState } from "react"
import type { AiChatContext } from "@/lib/ai/chat-context"
import { buildEmbedSearchParams, systemPromptFromContext } from "@/lib/ai/chat-context"
import { buildAiEmbedUrl, resolveAiEmbedOrigin } from "@/lib/ai/embed-url"
import { useAiIframeExternalLinks } from "@/lib/ai/use-ai-iframe-navigation"
import { useAiConfig, useCreateAiSession } from "@/lib/api/hooks/use-ai-queries"
import { useTheme } from "next-themes"
type AiChatIframeProps = {
publicPath?: string
context: AiChatContext
className?: string
}
export function AiChatIframe({ publicPath = "/ai", context, className }: AiChatIframeProps) {
const iframeRef = useRef<HTMLIFrameElement>(null)
const { resolvedTheme } = useTheme()
const { data: config, isSuccess } = useAiConfig()
const createSession = useCreateAiSession()
const [sessionToken, setSessionToken] = useState<string | undefined>()
const [sessionId, setSessionId] = useState<string | undefined>()
const sessionContextKey = useMemo(
() =>
[
context.app,
context.temporary,
context.messageId,
context.accountId,
context.drivePath,
context.fileId,
context.contactId,
].join("|"),
[
context.app,
context.temporary,
context.messageId,
context.accountId,
context.drivePath,
context.fileId,
context.contactId,
]
)
const embedOrigin = useMemo(() => resolveAiEmbedOrigin(publicPath), [publicPath])
const enabledTools = config?.enabled_tools ?? []
const mcpUrl = config?.mcp_url ?? "/api/v1/ai/mcp"
const iframeSrc = useMemo(() => {
if (!isSuccess || !config?.enabled) return null
const qs = buildEmbedSearchParams(context, config.default_model)
return buildAiEmbedUrl(publicPath, qs)
}, [isSuccess, config, publicPath, context])
useAiIframeExternalLinks(embedOrigin)
useEffect(() => {
if (!config?.enabled) return
let cancelled = false
createSession
.mutateAsync(context)
.then((session) => {
if (cancelled) return
setSessionToken(session.token_secret)
setSessionId(session.session_id)
})
.catch(() => {
if (!cancelled) {
setSessionToken(undefined)
setSessionId(undefined)
}
})
return () => {
cancelled = true
}
}, [config?.enabled, sessionContextKey, context, createSession.mutateAsync])
useEffect(() => {
const iframe = iframeRef.current
if (!iframe?.contentWindow || !embedOrigin) return
iframe.contentWindow.postMessage(
{ type: "ULTI_THEME", theme: resolvedTheme === "dark" ? "dark" : "light" },
embedOrigin
)
}, [resolvedTheme, embedOrigin])
useEffect(() => {
const iframe = iframeRef.current
if (!iframe?.contentWindow || !embedOrigin) return
const systemPrompt = [
systemPromptFromContext(context),
context.systemPromptExtra,
]
.filter(Boolean)
.join("\n\n")
iframe.contentWindow.postMessage(
{
type: "ULTI_CONTEXT_UPDATE",
context,
systemPrompt: systemPrompt || undefined,
},
embedOrigin
)
}, [context, embedOrigin])
useEffect(() => {
const iframe = iframeRef.current
if (!iframe?.contentWindow || !embedOrigin || !sessionToken) return
iframe.contentWindow.postMessage(
{
type: "ULTI_SESSION",
token_secret: sessionToken,
session_id: sessionId,
mcp_url: mcpUrl,
enabled_tools: enabledTools,
default_model: config?.default_model,
},
embedOrigin
)
}, [sessionToken, sessionId, mcpUrl, enabledTools, config?.default_model, embedOrigin])
if (!iframeSrc) {
return (
<div
className={className}
aria-busy="true"
aria-label="Chargement UltiAI"
/>
)
}
return (
<iframe
key={iframeSrc}
ref={iframeRef}
title="UltiAI"
src={iframeSrc}
className={className}
sandbox="allow-scripts allow-same-origin allow-forms allow-popups allow-downloads"
allow="clipboard-read; clipboard-write"
/>
)
}