centalize data model loading
This commit is contained in:
111
src/utils/dataService.ts
Normal file
111
src/utils/dataService.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
import { promises as fs } from 'fs';
|
||||
import { load } from 'js-yaml';
|
||||
import path from 'path';
|
||||
|
||||
interface ToolsData {
|
||||
tools: any[];
|
||||
domains: any[];
|
||||
phases: any[];
|
||||
'domain-agnostic-software': any[];
|
||||
}
|
||||
|
||||
interface CompressedToolsData extends Omit<ToolsData, 'tools'> {
|
||||
tools: any[];
|
||||
}
|
||||
|
||||
let cachedData: ToolsData | null = null;
|
||||
let cachedRandomizedData: ToolsData | null = null;
|
||||
let cachedCompressedData: CompressedToolsData | null = null;
|
||||
let lastRandomizationDate: string | null = null;
|
||||
|
||||
// Create a seeded random number generator
|
||||
function seededRandom(seed: number): () => number {
|
||||
let x = Math.sin(seed) * 10000;
|
||||
return function() {
|
||||
x = Math.sin(x) * 10000;
|
||||
return x - Math.floor(x);
|
||||
};
|
||||
}
|
||||
|
||||
// Get today's date as seed + process start time for consistency within day/session
|
||||
function getDailySeed(): number {
|
||||
const today = new Date().toDateString();
|
||||
const processStart = process.uptime();
|
||||
return today.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0) + Math.floor(processStart);
|
||||
}
|
||||
|
||||
// Fisher-Yates shuffle with seeded random
|
||||
function shuffleArray<T>(array: T[], randomFn: () => number): T[] {
|
||||
const shuffled = [...array];
|
||||
for (let i = shuffled.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(randomFn() * (i + 1));
|
||||
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
|
||||
}
|
||||
return shuffled;
|
||||
}
|
||||
|
||||
// Load raw data from YAML
|
||||
async function loadRawData(): Promise<ToolsData> {
|
||||
if (!cachedData) {
|
||||
const yamlPath = path.join(process.cwd(), 'src/data/tools.yaml');
|
||||
const yamlContent = await fs.readFile(yamlPath, 'utf8');
|
||||
cachedData = load(yamlContent) as ToolsData;
|
||||
}
|
||||
return cachedData;
|
||||
}
|
||||
|
||||
// Get tools data with randomized tool order (daily seed)
|
||||
export async function getToolsData(): Promise<ToolsData> {
|
||||
const today = new Date().toDateString();
|
||||
|
||||
// Check if we need to re-randomize (new day or first load)
|
||||
if (!cachedRandomizedData || lastRandomizationDate !== today) {
|
||||
const rawData = await loadRawData();
|
||||
const seed = getDailySeed();
|
||||
const randomFn = seededRandom(seed);
|
||||
|
||||
// Randomize tools array while keeping other data intact
|
||||
const randomizedTools = shuffleArray(rawData.tools, randomFn);
|
||||
|
||||
cachedRandomizedData = {
|
||||
...rawData,
|
||||
tools: randomizedTools
|
||||
};
|
||||
|
||||
lastRandomizationDate = today;
|
||||
|
||||
// Clear compressed cache when we re-randomize
|
||||
cachedCompressedData = null;
|
||||
}
|
||||
|
||||
return cachedRandomizedData;
|
||||
}
|
||||
|
||||
// Get compressed data for AI (removes projectUrl and statusUrl)
|
||||
export async function getCompressedToolsDataForAI(): Promise<CompressedToolsData> {
|
||||
if (!cachedCompressedData) {
|
||||
const data = await getToolsData();
|
||||
|
||||
const compressedTools = data.tools.map(tool => {
|
||||
const { projectUrl, statusUrl, ...compressedTool } = tool;
|
||||
return compressedTool;
|
||||
});
|
||||
|
||||
cachedCompressedData = {
|
||||
tools: compressedTools,
|
||||
domains: data.domains,
|
||||
phases: data.phases,
|
||||
'domain-agnostic-software': data['domain-agnostic-software']
|
||||
};
|
||||
}
|
||||
|
||||
return cachedCompressedData;
|
||||
}
|
||||
|
||||
// Force cache refresh (useful for development)
|
||||
export function clearCache(): void {
|
||||
cachedData = null;
|
||||
cachedRandomizedData = null;
|
||||
cachedCompressedData = null;
|
||||
lastRandomizationDate = null;
|
||||
}
|
||||
Reference in New Issue
Block a user