ultisuite-client/lib/api/hooks/use-ai-queries.ts
R3D347HR4Y 2a0958b70d
Some checks are pending
E2E / Playwright e2e (push) Waiting to run
feat: update agenda references to use ULTICAL_APP_NAME and enhance AI usage sections
- Replaced hardcoded "Agenda" labels with dynamic ULTICAL_APP_NAME in various components for consistency.
- Introduced new AiUsageSection and CompteAiUsageSection components to track AI usage and costs.
- Updated settings and metadata to reflect changes in AI cost policies and usage limits.
- Enhanced user interface elements for better accessibility and user experience across admin settings.
2026-06-16 10:46:31 +02:00

103 lines
2.8 KiB
TypeScript

"use client"
import { useMutation, useQuery } from "@tanstack/react-query"
import { apiClient } from "@/lib/api/client"
import type { AiChatContext } from "@/lib/ai/chat-context"
export type AiConfig = {
enabled: boolean
public_path: string
mcp_url?: string
embed_default_temporary: boolean
default_model: string
enabled_tools: string[]
chat_sync_enabled: boolean
models?: { model_id: string; label: string; enabled: boolean }[]
restrict_models?: boolean
}
export type AiQuota = {
cost_used_today_micro_eur: number
cost_limit_today_micro_eur?: number | null
cost_used_month_micro_eur: number
cost_limit_month_micro_eur?: number | null
cost_remaining_today_micro_eur?: number | null
cost_remaining_month_micro_eur?: number | null
warn_threshold_pct: number
currency: string
billing_scope_org: boolean
by_provider_keys?: {
fingerprint: string
label: string
cost_month_micro_eur: number
cost_month_eur: number
billing_scope: string
}[]
/** @deprecated */
requests_used_today?: number
requests_limit?: number
tokens_used_month?: number
tokens_limit?: number
requests_remaining?: number
tokens_remaining?: number
}
export function formatAiCostEUR(microEur: number | null | undefined): string {
const value = typeof microEur === "number" && Number.isFinite(microEur) ? microEur : 0
return new Intl.NumberFormat("fr-FR", {
style: "currency",
currency: "EUR",
minimumFractionDigits: 2,
maximumFractionDigits: 4,
}).format(value / 1_000_000)
}
export function aiQuotaUsedMonthPct(quota: AiQuota): number | null {
const limit = quota.cost_limit_month_micro_eur
if (!limit || limit <= 0) return null
return Math.min(100, Math.round((quota.cost_used_month_micro_eur / limit) * 100))
}
export type AiSessionResponse = {
session_id: string
embed_url: string
token_secret?: string
temporary: boolean
mcp_url?: string
enabled_tools?: string[]
}
export function useAiConfig() {
return useQuery({
queryKey: ["ai", "config"],
queryFn: () => apiClient.get<AiConfig>("/ai/config"),
staleTime: 60_000,
})
}
export function useAiQuota(enabled = true) {
return useQuery({
queryKey: ["ai", "quota"],
queryFn: () => apiClient.get<AiQuota>("/ai/quota"),
enabled,
staleTime: 30_000,
})
}
export function useCreateAiSession() {
return useMutation({
mutationFn: (context: AiChatContext) =>
apiClient.post<AiSessionResponse>("/ai/sessions", {
app: context.app,
temporary: context.temporary ?? true,
message_id: context.messageId,
account_id: context.accountId,
drive_path: context.drivePath,
file_id: context.fileId,
contact_id: context.contactId,
subject: context.subject,
snippet: context.snippet,
}),
})
}