Files

258 lines
9.3 KiB
TypeScript

import type {
AIModel,
AIAttestation,
AIInferenceResult,
AIProvider,
} from './types';
import { getEnvValue } from 'configs/app/utils';
const ACHAIN_INDEXER_URL =
getEnvValue('NEXT_PUBLIC_ACHAIN_INDEXER_URL') || 'https://api-indexer-achain.lux.network';
const DEMO_MODELS: ReadonlyArray<AIModel> = [
{
id: 'model-001',
name: 'Qwen3-235B',
version: '3.0.0',
framework: 'PyTorch',
modelHash: '0xab12cd34ef56789001234567890abcdef01234567890abcdef01234567890ab',
parameters: 235_000_000_000,
registeredAt: '2026-02-20T10:30:00Z',
provider: '0x1234567890abcdef1234567890abcdef12345678',
},
{
id: 'model-002',
name: 'Qwen3-30B-A3B',
version: '3.0.0',
framework: 'PyTorch',
modelHash: '0xcd34ef56789001234567890abcdef01234567890abcdef01234567890abcdef',
parameters: 30_000_000_000,
registeredAt: '2026-02-19T14:15:00Z',
provider: '0x2345678901abcdef2345678901abcdef23456789',
},
{
id: 'model-003',
name: 'LuxVision-7B',
version: '1.2.0',
framework: 'Candle',
modelHash: '0xef56789001234567890abcdef01234567890abcdef01234567890abcdef0123',
parameters: 7_000_000_000,
registeredAt: '2026-02-18T08:45:00Z',
provider: '0x3456789012abcdef3456789012abcdef34567890',
},
{
id: 'model-004',
name: 'LuxAudio-3B',
version: '0.9.1',
framework: 'Candle',
modelHash: '0x1234567890abcdef01234567890abcdef01234567890abcdef01234567890ab',
parameters: 3_000_000_000,
registeredAt: '2026-02-17T16:00:00Z',
provider: '0x1234567890abcdef1234567890abcdef12345678',
},
{
id: 'model-005',
name: 'ZooClassifier-1B',
version: '2.1.0',
framework: 'PyTorch',
modelHash: '0x567890abcdef01234567890abcdef01234567890abcdef01234567890abcdef',
parameters: 1_000_000_000,
registeredAt: '2026-02-16T12:30:00Z',
provider: '0x4567890123abcdef4567890123abcdef45678901',
},
];
const DEMO_ATTESTATIONS: ReadonlyArray<AIAttestation> = [
{
id: 'att-001', type: 'inference',
provider: '0x1234567890abcdef1234567890abcdef12345678',
modelHash: '0xab12cd34ef56789001234567890abcdef01234567890abcdef01234567890ab',
timestamp: '2026-02-26T09:15:00Z', blockHeight: 142, status: 'verified',
},
{
id: 'att-002', type: 'compute',
provider: '0x2345678901abcdef2345678901abcdef23456789',
modelHash: '0xcd34ef56789001234567890abcdef01234567890abcdef01234567890abcdef',
timestamp: '2026-02-26T09:10:00Z', blockHeight: 141, status: 'verified',
},
{
id: 'att-003', type: 'training',
provider: '0x3456789012abcdef3456789012abcdef34567890',
modelHash: '0xef56789001234567890abcdef01234567890abcdef01234567890abcdef0123',
timestamp: '2026-02-26T09:05:00Z', blockHeight: 140, status: 'pending',
},
{
id: 'att-004', type: 'inference',
provider: '0x4567890123abcdef4567890123abcdef45678901',
modelHash: '0x567890abcdef01234567890abcdef01234567890abcdef01234567890abcdef',
timestamp: '2026-02-26T09:00:00Z', blockHeight: 139, status: 'verified',
},
{
id: 'att-005', type: 'compute',
provider: '0x1234567890abcdef1234567890abcdef12345678',
modelHash: '0x1234567890abcdef01234567890abcdef01234567890abcdef01234567890ab',
timestamp: '2026-02-26T08:55:00Z', blockHeight: 138, status: 'rejected',
},
{
id: 'att-006', type: 'inference',
provider: '0x2345678901abcdef2345678901abcdef23456789',
modelHash: '0xab12cd34ef56789001234567890abcdef01234567890abcdef01234567890ab',
timestamp: '2026-02-26T08:50:00Z', blockHeight: 137, status: 'verified',
},
{
id: 'att-007', type: 'training',
provider: '0x3456789012abcdef3456789012abcdef34567890',
modelHash: '0xcd34ef56789001234567890abcdef01234567890abcdef01234567890abcdef',
timestamp: '2026-02-26T08:45:00Z', blockHeight: 136, status: 'verified',
},
{
id: 'att-008', type: 'compute',
provider: '0x4567890123abcdef4567890123abcdef45678901',
modelHash: '0xef56789001234567890abcdef01234567890abcdef01234567890abcdef0123',
timestamp: '2026-02-26T08:40:00Z', blockHeight: 135, status: 'pending',
},
];
const DEMO_INFERENCE_RESULTS: ReadonlyArray<AIInferenceResult> = [
{
id: 'inf-001', modelId: 'model-001',
inputHash: '0xaaaa111122223333444455556666777788889999aaaabbbbccccddddeeee0001',
outputHash: '0xbbbb111122223333444455556666777788889999aaaabbbbccccddddeeee0001',
confidence: 0.97, latencyMs: 245, timestamp: '2026-02-26T09:15:00Z',
provider: '0x1234567890abcdef1234567890abcdef12345678',
},
{
id: 'inf-002', modelId: 'model-002',
inputHash: '0xaaaa111122223333444455556666777788889999aaaabbbbccccddddeeee0002',
outputHash: '0xbbbb111122223333444455556666777788889999aaaabbbbccccddddeeee0002',
confidence: 0.94, latencyMs: 180, timestamp: '2026-02-26T09:10:00Z',
provider: '0x2345678901abcdef2345678901abcdef23456789',
},
{
id: 'inf-003', modelId: 'model-003',
inputHash: '0xaaaa111122223333444455556666777788889999aaaabbbbccccddddeeee0003',
outputHash: '0xbbbb111122223333444455556666777788889999aaaabbbbccccddddeeee0003',
confidence: 0.91, latencyMs: 120, timestamp: '2026-02-26T09:05:00Z',
provider: '0x3456789012abcdef3456789012abcdef34567890',
},
{
id: 'inf-004', modelId: 'model-005',
inputHash: '0xaaaa111122223333444455556666777788889999aaaabbbbccccddddeeee0004',
outputHash: '0xbbbb111122223333444455556666777788889999aaaabbbbccccddddeeee0004',
confidence: 0.88, latencyMs: 95, timestamp: '2026-02-26T09:00:00Z',
provider: '0x4567890123abcdef4567890123abcdef45678901',
},
];
const DEMO_PROVIDERS: ReadonlyArray<AIProvider> = [
{
address: '0x1234567890abcdef1234567890abcdef12345678',
reputation: 98, capacity: 8, totalJobs: 1247, totalEarnings: '42500000000000000000', isActive: true,
},
{
address: '0x2345678901abcdef2345678901abcdef23456789',
reputation: 95, capacity: 4, totalJobs: 893, totalEarnings: '31200000000000000000', isActive: true,
},
{
address: '0x3456789012abcdef3456789012abcdef34567890',
reputation: 92, capacity: 16, totalJobs: 2156, totalEarnings: '78900000000000000000', isActive: true,
},
{
address: '0x4567890123abcdef4567890123abcdef45678901',
reputation: 87, capacity: 2, totalJobs: 456, totalEarnings: '12800000000000000000', isActive: false,
},
];
interface AChainStatsResponse {
readonly chain_stats: {
readonly total_attestations?: number;
readonly total_models?: number;
readonly total_inferences?: number;
readonly total_compute_units?: number;
readonly unique_providers?: number;
readonly attestations_by_type?: Record<string, number>;
};
readonly dag_stats: {
readonly total_vertices: number;
};
}
interface AChainVertex {
readonly id: string;
readonly data?: Record<string, unknown>;
readonly timestamp?: string;
readonly height?: number;
}
async function fetchIndexerStats(): Promise<AChainStatsResponse | null> {
try {
const res = await fetch(`${ ACHAIN_INDEXER_URL }/stats`);
if (!res.ok) return null;
return await res.json() as AChainStatsResponse;
} catch {
return null;
}
}
async function fetchIndexerVertices(): Promise<ReadonlyArray<AChainVertex>> {
try {
const res = await fetch(`${ ACHAIN_INDEXER_URL }/vertices`);
if (!res.ok) return [];
const data = await res.json() as { items: ReadonlyArray<AChainVertex> | null };
return data.items ?? [];
} catch {
return [];
}
}
export async function fetchModels(): Promise<ReadonlyArray<AIModel>> {
const stats = await fetchIndexerStats();
if (stats && (stats.chain_stats.total_models ?? 0) > 0) {
const vertices = await fetchIndexerVertices();
const models = vertices
.filter((v) => v.data && (v.data as Record<string, unknown>).type === 'model')
.map((v) => v.data as unknown as AIModel);
if (models.length > 0) return models;
}
return DEMO_MODELS;
}
export async function fetchAttestations(): Promise<ReadonlyArray<AIAttestation>> {
const stats = await fetchIndexerStats();
if (stats && (stats.chain_stats.total_attestations ?? 0) > 0) {
const vertices = await fetchIndexerVertices();
const attestations = vertices
.filter((v) => v.data && (v.data as Record<string, unknown>).type === 'attestation')
.map((v) => v.data as unknown as AIAttestation);
if (attestations.length > 0) return attestations;
}
return DEMO_ATTESTATIONS;
}
export async function fetchInferenceResults(): Promise<ReadonlyArray<AIInferenceResult>> {
const stats = await fetchIndexerStats();
if (stats && (stats.chain_stats.total_inferences ?? 0) > 0) {
const vertices = await fetchIndexerVertices();
const inferences = vertices
.filter((v) => v.data && (v.data as Record<string, unknown>).type === 'inference')
.map((v) => v.data as unknown as AIInferenceResult);
if (inferences.length > 0) return inferences;
}
return DEMO_INFERENCE_RESULTS;
}
export async function fetchProviders(): Promise<ReadonlyArray<AIProvider>> {
const stats = await fetchIndexerStats();
if (stats && (stats.chain_stats.unique_providers ?? 0) > 0) {
const vertices = await fetchIndexerVertices();
const providers = vertices
.filter((v) => v.data && (v.data as Record<string, unknown>).type === 'provider')
.map((v) => v.data as unknown as AIProvider);
if (providers.length > 0) return providers;
}
return DEMO_PROVIDERS;
}
export { ACHAIN_INDEXER_URL };