Some checks are pending
E2E / Playwright e2e (push) Waiting to run
- 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.
102 lines
3.4 KiB
TypeScript
102 lines
3.4 KiB
TypeScript
"use client"
|
|
|
|
import { SettingsSectionHeader } from "@/components/gmail/settings/settings-section-header"
|
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
|
import {
|
|
Table,
|
|
TableBody,
|
|
TableCell,
|
|
TableHead,
|
|
TableHeader,
|
|
TableRow,
|
|
} from "@/components/ui/table"
|
|
import { AiSpendBar } from "@/components/ai/ai-spend-bar"
|
|
import { useAiConfig, useAiQuota, formatAiCostEUR } from "@/lib/api/hooks/use-ai-queries"
|
|
|
|
export function CompteAiUsageSection() {
|
|
const { data: config } = useAiConfig()
|
|
const { data: quota, isLoading } = useAiQuota(config?.enabled ?? false)
|
|
|
|
if (!config?.enabled) {
|
|
return (
|
|
<>
|
|
<SettingsSectionHeader
|
|
title="Usage IA"
|
|
description="UltiAI n'est pas activé sur cette instance."
|
|
/>
|
|
</>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<SettingsSectionHeader
|
|
title="Usage IA"
|
|
description="Consommation estimée de vos requêtes LLM ce mois-ci."
|
|
/>
|
|
|
|
{isLoading ? (
|
|
<p className="text-sm text-muted-foreground">Chargement…</p>
|
|
) : quota ? (
|
|
<div className="space-y-6 max-w-xl">
|
|
<Card>
|
|
<CardHeader className="pb-2">
|
|
<CardTitle className="text-sm font-medium">Budget mensuel</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<AiSpendBar quota={quota} />
|
|
<div className="mt-4 grid grid-cols-2 gap-4 text-sm">
|
|
<div>
|
|
<p className="text-muted-foreground">Aujourd'hui</p>
|
|
<p className="font-medium tabular-nums">
|
|
{formatAiCostEUR(quota.cost_used_today_micro_eur)}
|
|
</p>
|
|
</div>
|
|
<div>
|
|
<p className="text-muted-foreground">Ce mois</p>
|
|
<p className="font-medium tabular-nums">
|
|
{formatAiCostEUR(quota.cost_used_month_micro_eur)}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{(quota.by_provider_keys?.length ?? 0) > 0 ? (
|
|
<Card>
|
|
<CardHeader className="pb-2">
|
|
<CardTitle className="text-sm font-medium">Par clé API</CardTitle>
|
|
</CardHeader>
|
|
<CardContent className="p-0">
|
|
<Table>
|
|
<TableHeader>
|
|
<TableRow>
|
|
<TableHead>Clé / fournisseur</TableHead>
|
|
<TableHead className="text-right">Ce mois</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{quota.by_provider_keys!.map((k) => (
|
|
<TableRow key={k.fingerprint}>
|
|
<TableCell>
|
|
<div>{k.label}</div>
|
|
<div className="text-xs text-muted-foreground">
|
|
{k.billing_scope === "user" ? "Clé personnelle" : "Organisation"}
|
|
</div>
|
|
</TableCell>
|
|
<TableCell className="text-right tabular-nums">
|
|
{formatAiCostEUR(k.cost_month_micro_eur)}
|
|
</TableCell>
|
|
</TableRow>
|
|
))}
|
|
</TableBody>
|
|
</Table>
|
|
</CardContent>
|
|
</Card>
|
|
) : null}
|
|
</div>
|
|
) : null}
|
|
</>
|
|
)
|
|
}
|