feat(models): show LangBot Models pricing

This commit is contained in:
RockChinQ
2026-09-12 00:53:47 +08:00
parent a3509b3626
commit 33b4035140
17 changed files with 233 additions and 103 deletions
@@ -1,30 +1,30 @@
import { useEffect, useState } from 'react';
import type { LangBotModelAvailability } from '@/app/infra/entities/api';
import type { LangBotModelAvailabilityItem } from '@/app/infra/entities/api';
import { httpClient } from '@/app/infra/http/HttpClient';
const CACHE_TTL_MS = 60_000;
type AvailabilityMap = Record<string, LangBotModelAvailability>;
type ModelMetadataMap = Record<string, LangBotModelAvailabilityItem>;
let cachedAvailability: AvailabilityMap | null = null;
let cachedMetadata: ModelMetadataMap | null = null;
let cacheExpiresAt = 0;
let pendingRequest: Promise<AvailabilityMap> | null = null;
let pendingRequest: Promise<ModelMetadataMap> | null = null;
async function loadAvailability(): Promise<AvailabilityMap> {
if (cachedAvailability && Date.now() < cacheExpiresAt) {
return cachedAvailability;
async function loadMetadata(): Promise<ModelMetadataMap> {
if (cachedMetadata && Date.now() < cacheExpiresAt) {
return cachedMetadata;
}
if (pendingRequest) return pendingRequest;
pendingRequest = httpClient
.getLangBotModelAvailability()
.then((response) => {
const next: AvailabilityMap = {};
const next: ModelMetadataMap = {};
for (const item of response.models) {
next[item.uuid] = item.availability;
next[item.model_id] = item.availability;
next[item.uuid] = item;
next[item.model_id] = item;
}
cachedAvailability = next;
cachedMetadata = next;
cacheExpiresAt = Date.now() + CACHE_TTL_MS;
return next;
})
@@ -35,29 +35,29 @@ async function loadAvailability(): Promise<AvailabilityMap> {
}
export function useLangBotModelAvailability(enabled = true) {
const [availability, setAvailability] = useState<AvailabilityMap>(
cachedAvailability ?? {},
const [metadata, setMetadata] = useState<ModelMetadataMap>(
cachedMetadata ?? {},
);
const [loaded, setLoaded] = useState(
cachedAvailability !== null && Date.now() < cacheExpiresAt,
cachedMetadata !== null && Date.now() < cacheExpiresAt,
);
useEffect(() => {
if (!enabled) return;
let active = true;
loadAvailability()
loadMetadata()
.then((result) => {
if (!active) return;
setAvailability(result);
setMetadata(result);
setLoaded(true);
})
.catch(() => {
// Availability is supplementary; model configuration remains usable.
// Catalog metadata is supplementary; model configuration remains usable.
});
return () => {
active = false;
};
}, [enabled]);
return { availability, loaded };
return { metadata, loaded };
}