Files
nav-carte/server/api/stats.get.ts
2026-04-28 14:00:05 +02:00

107 lines
4.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* GET /api/stats
*
* Statistiques d'usage pour le bandeau bas (transparence IA + compteurs semaine).
*
* Query params :
* periode = "mois" (défaut) | "semaine"
*
* Payload retourné :
* cout_mois_eur number — somme cout_eur du mois courant
* budget_mois 20 — budget fixe mensuel
* tokens_mois number — somme tokens_in + tokens_out du mois
* co2_kg number — estimation CO2 (tokens × 0.000001 × 0.052 kgCO2eq/kWh mix RTE)
* requetes_mois number — count rows du mois
* fiches_semaine number — orgs approuvées créées dans les 7 derniers jours
* requetes_chatbot_semaine number — count stats_usage endpoint=chatbot dans les 7j
*/
export default defineEventHandler(async (event) => {
const config = useRuntimeConfig()
const nocodbUrl = config.nocodbUrl as string
const nocodbToken = config.nocodbToken as string
const statsTableId = (config.statsTableId as string) || 'mbbq7n47ixy19mc'
const orgTableId = config.orgTableId as string
const nocoBaseId = process.env.NOCODB_BASE_ID || 'p_nav_v2'
const headers = { 'xc-token': nocodbToken }
// ── Dates ────────────────────────────────────────────────────────────────
const now = new Date()
const moisDebut = new Date(now.getFullYear(), now.getMonth(), 1).toISOString().slice(0, 10)
const semaineDebut = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000).toISOString().slice(0, 10)
// ── Helpers fetch NocoDB ─────────────────────────────────────────────────
async function fetchStats(where: string): Promise<{ list: Record<string, any>[] }> {
try {
return await $fetch(`${nocodbUrl}/api/v1/db/data/noco/${nocoBaseId}/${statsTableId}`, {
headers,
query: { where, limit: 1000, fields: 'cout_eur,tokens_in,tokens_out,endpoint,created_at' },
}) as { list: Record<string, any>[] }
} catch {
return { list: [] }
}
}
async function fetchOrgsRecentes(since: string): Promise<number> {
if (!orgTableId) return 0
try {
const res = await $fetch<{ pageInfo?: { totalRows?: number } }>(
`${nocodbUrl}/api/v1/db/data/noco/${nocoBaseId}/${orgTableId}`,
{
headers,
query: {
where: `(moderation_status,eq,approved)~and(created_at,gte,${since})`,
limit: 1,
fields: 'Id',
},
}
)
return (res as any)?.pageInfo?.totalRows ?? 0
} catch {
return 0
}
}
// ── Fetch parallèle ──────────────────────────────────────────────────────
const [statsMois, statsSemaine, fichesAjoutees] = await Promise.all([
fetchStats(`(created_at,gte,${moisDebut})`),
fetchStats(`(created_at,gte,${semaineDebut})`),
fetchOrgsRecentes(semaineDebut),
])
// ── Agrégation mois ──────────────────────────────────────────────────────
let cout_mois_eur = 0
let tokens_mois = 0
const requetes_mois = statsMois.list.length
for (const row of statsMois.list) {
cout_mois_eur += Number(row.cout_eur ?? 0)
tokens_mois += Number(row.tokens_in ?? 0) + Number(row.tokens_out ?? 0)
}
const co2_kg = tokens_mois * 0.000001 * 0.052
// ── Agrégation semaine chatbot ───────────────────────────────────────────
const requetes_chatbot_semaine = statsSemaine.list.filter(
(r) => (r.endpoint ?? '') === 'chatbot'
).length
// ── Réponse ──────────────────────────────────────────────────────────────
return {
cout_mois_eur: Math.round(cout_mois_eur * 1000) / 1000,
budget_mois: 20,
tokens_mois,
co2_kg: Math.round(co2_kg * 1e6) / 1e6,
requetes_mois,
fiches_semaine: fichesAjoutees,
requetes_chatbot_semaine,
}
})