Files
e-tib.com/lib/image-matcher.ts
Marc Mintel f0ba5321bb
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 44s
Build & Deploy / 🧪 QA (push) Successful in 1m4s
Build & Deploy / 🏗️ Build (push) Successful in 1m54s
Build & Deploy / 🚀 Deploy (push) Successful in 28s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 43s
Build & Deploy / 🔔 Notify (push) Successful in 2s
feat: AI image classification and dynamic fallback assignment
2026-06-16 14:16:39 +02:00

71 lines
2.2 KiB
TypeScript

import metadataJson from '../public/assets/image-metadata.json';
export interface ImageMeta {
file: string;
category: 'pv' | 'wind' | 'fiber' | 'power' | 'battery' | 'unknown';
environment: 'freies_feld' | 'urban' | 'wald' | 'indoor' | 'unknown';
quality_score: number;
description: string;
}
const metadata = metadataJson as Record<string, ImageMeta>;
// Create a deterministic pseudo-random number based on a string
function hashString(str: string): number {
let hash = 0;
for (let i = 0; i < str.length; i++) {
const char = str.charCodeAt(i);
hash = (hash << 5) - hash + char;
hash = hash & hash; // Convert to 32bit integer
}
return Math.abs(hash);
}
/**
* Returns a fitting, highly-rated image for a specific project type.
* It is deterministic based on the seed (e.g. project ID).
*/
export function getImageForProject(seed: string, category: string): string {
const allImages = Object.values(metadata);
// 1. Filter by category
let candidates = allImages.filter(img => img.category === category);
// If no candidates for category, fallback to fiber (Kabeltiefbau is safe default for ETIB)
if (candidates.length === 0) {
candidates = allImages.filter(img => img.category === 'fiber');
}
// Still empty? Just get anything highly rated
if (candidates.length === 0) {
candidates = allImages;
}
// 2. Sort by quality score (descending)
candidates.sort((a, b) => b.quality_score - a.quality_score);
// 3. For PV and Wind, strongly prefer 'freies_feld'
if (category === 'pv' || category === 'wind') {
const fieldCandidates = candidates.filter(img => img.environment === 'freies_feld' && img.quality_score >= 6);
if (fieldCandidates.length > 0) {
candidates = fieldCandidates;
}
} else {
// For others, just take top 30% quality to have some variation
candidates = candidates.filter(img => img.quality_score >= 6);
if (candidates.length === 0) {
candidates = allImages.filter(img => img.category === category);
}
}
if (candidates.length === 0) {
return '/assets/logo.png'; // Ultimate fallback
}
// 4. Deterministically pick one based on the seed
const hash = hashString(seed);
const index = hash % candidates.length;
return candidates[index].file;
}