feat: add AI service client and implement tenant AI management dashboards

This commit is contained in:
sibarchannayak 2026-05-29 18:14:08 +05:30
parent 85ecd9dac1
commit 0a672619ea
3 changed files with 160 additions and 131 deletions

View File

@ -42,6 +42,7 @@ import { formatDate } from "@/utils/format-date";
import AuditLogs from "@/pages/tenant/AuditLogs"; import AuditLogs from "@/pages/tenant/AuditLogs";
import TenantSettings from "@/pages/tenant/Settings"; import TenantSettings from "@/pages/tenant/Settings";
import TenantAIProviders from "@/pages/tenant/TenantAIProviders"; import TenantAIProviders from "@/pages/tenant/TenantAIProviders";
import { TenantAIDashboard } from "@/pages/tenant/TenantAIDashboard";
// import DepartmentsTable from "@/components/superadmin/DepartmentsTable"; // import DepartmentsTable from "@/components/superadmin/DepartmentsTable";
import DesignationsTable from "@/components/superadmin/DesignationsTable"; import DesignationsTable from "@/components/superadmin/DesignationsTable";
@ -59,7 +60,8 @@ type TabType =
| "license" | "license"
| "audit-logs" | "audit-logs"
| "billing" | "billing"
| "ai-providers"; | "ai-providers"
| "ai-dashboard";
const tabs: Array<{ id: TabType; label: string; icon: ReactElement }> = [ const tabs: Array<{ id: TabType; label: string; icon: ReactElement }> = [
{ id: "overview", label: "Overview", icon: <FileText className="w-4 h-4" /> }, { id: "overview", label: "Overview", icon: <FileText className="w-4 h-4" /> },
@ -89,6 +91,7 @@ const tabs: Array<{ id: TabType; label: string; icon: ReactElement }> = [
{ id: "modules", label: "Modules", icon: <Package className="w-4 h-4" /> }, { id: "modules", label: "Modules", icon: <Package className="w-4 h-4" /> },
{ id: "settings", label: "Settings", icon: <Settings className="w-4 h-4" /> }, { id: "settings", label: "Settings", icon: <Settings className="w-4 h-4" /> },
{ id: "ai-providers", label: "AI Providers", icon: <Brain className="w-4 h-4" /> }, { id: "ai-providers", label: "AI Providers", icon: <Brain className="w-4 h-4" /> },
{ id: "ai-dashboard", label: "AI Dashboard", icon: <Brain className="w-4 h-4" /> },
{ id: "license", label: "License", icon: <FileText className="w-4 h-4" /> }, { id: "license", label: "License", icon: <FileText className="w-4 h-4" /> },
{ {
id: "audit-logs", id: "audit-logs",
@ -381,6 +384,9 @@ const TenantDetails = (): ReactElement => {
{activeTab === "ai-providers" && id && ( {activeTab === "ai-providers" && id && (
<TenantAIProviders customTenantId={id} hideLayout={true} /> <TenantAIProviders customTenantId={id} hideLayout={true} />
)} )}
{activeTab === "ai-dashboard" && id && (
<TenantAIDashboard customTenantId={id} hideLayout={true} />
)}
{activeTab === "license" && <LicenseTab tenant={tenant} />} {activeTab === "license" && <LicenseTab tenant={tenant} />}
{activeTab === "audit-logs" && id && ( {activeTab === "audit-logs" && id && (
<AuditLogs customTenantId={id} hideLayout={true} /> <AuditLogs customTenantId={id} hideLayout={true} />

View File

@ -21,7 +21,15 @@ import { formatDate } from "@/utils/format-date";
type GroupBy = "day" | "week" | "month"; type GroupBy = "day" | "week" | "month";
export const TenantAIDashboard = (): ReactElement => { interface TenantAIDashboardProps {
customTenantId?: string;
hideLayout?: boolean;
}
export const TenantAIDashboard = ({
customTenantId,
hideLayout = false,
}: TenantAIDashboardProps): ReactElement => {
const [groupBy, setGroupBy] = useState<GroupBy | null>(null); const [groupBy, setGroupBy] = useState<GroupBy | null>(null);
const [startDate, setStartDate] = useState<string>(""); const [startDate, setStartDate] = useState<string>("");
const [endDate, setEndDate] = useState<string>(""); const [endDate, setEndDate] = useState<string>("");
@ -54,11 +62,14 @@ export const TenantAIDashboard = (): ReactElement => {
) => { ) => {
setIsLoading(true); setIsLoading(true);
try { try {
const data = await aiService.getCostSummary({ const data = await aiService.getCostSummary(
{
group_by: group || undefined, group_by: group || undefined,
start_date: group && start ? `${start}T00:00:00.000Z` : undefined, start_date: group && start ? `${start}T00:00:00.000Z` : undefined,
end_date: group && end ? `${end}T23:59:59.999Z` : undefined, end_date: group && end ? `${end}T23:59:59.999Z` : undefined,
}); },
customTenantId
);
setCosts(data); setCosts(data);
} catch (err: any) { } catch (err: any) {
showToast.error( showToast.error(
@ -73,7 +84,7 @@ export const TenantAIDashboard = (): ReactElement => {
if (!groupBy || (startDate && endDate)) { if (!groupBy || (startDate && endDate)) {
void fetchCostSummary(groupBy, startDate, endDate); void fetchCostSummary(groupBy, startDate, endDate);
} }
}, [groupBy, startDate, endDate]); }, [groupBy, startDate, endDate, customTenantId]);
const providerColumns: Column<any>[] = [ const providerColumns: Column<any>[] = [
{ {
@ -170,15 +181,7 @@ export const TenantAIDashboard = (): ReactElement => {
return `${Math.round(ms)}ms`; return `${Math.round(ms)}ms`;
}; };
return ( const content = (
<Layout
currentPage="AI Services"
pageHeader={{
title: "AI Usage & Cost Dashboard",
description:
"Monitor AI completions, tokens, and billing analytics across all providers.",
}}
>
<div className="space-y-6"> <div className="space-y-6">
{/* Top Controls Row */} {/* Top Controls Row */}
@ -296,6 +299,22 @@ export const TenantAIDashboard = (): ReactElement => {
</div> </div>
</div> </div>
</div> </div>
);
if (hideLayout) {
return content;
}
return (
<Layout
currentPage="AI Services"
pageHeader={{
title: "AI Usage & Cost Dashboard",
description:
"Monitor AI completions, tokens, and billing analytics across all providers.",
}}
>
{content}
</Layout> </Layout>
); );
}; };

View File

@ -84,12 +84,16 @@ class AIService {
return unwrap<AICompletion>(response); return unwrap<AICompletion>(response);
} }
async getCostSummary(params: { async getCostSummary(
params: {
group_by?: "day" | "week" | "month"; group_by?: "day" | "week" | "month";
start_date?: string; start_date?: string;
end_date?: string; end_date?: string;
} = {}): Promise<AICostSummary> { } = {},
const response = await apiClient.get("/ai/costs", { params }); tenantId?: string
): Promise<AICostSummary> {
const headers = tenantId ? { "x-tenant-id": tenantId } : undefined;
const response = await apiClient.get("/ai/costs", { params, headers });
return unwrap<AICostSummary>(response); return unwrap<AICostSummary>(response);
} }