cine-kids/server.js

83 lines
3.0 KiB
JavaScript

const express = require('express');
const cors = require('cors');
const cinecheck = require('./aggregators/cinecheck-adapter');
const commonsense = require('./aggregators/commonsense-adapter');
const filmages = require('./aggregators/filmages-adapter');
const { mergeResults } = require('./merge');
const app = express();
app.use(cors());
// Helper to normalize text and get words for matching
function getWords(text) {
if (!text || typeof text !== 'string') return [];
return text
.toLowerCase()
// Remove punctuation, keep letters, numbers, and whitespace. Handles Unicode.
.replace(/[^\p{L}\p{N}\s]/gu, '')
.replace(/\s+/g, ' ') // Normalize multiple spaces to single
.trim()
.split(' ')
.filter(Boolean); // Remove empty strings from split
}
app.get('/search', async (req, res) => {
const q = req.query.q;
if (!q) {
return res.status(400).json({ error: "Missing query. Predictable." });
}
try {
const [cine, cs, fa] = await Promise.all([
cinecheck.searchAndEnrich(q).catch(e => { console.error('Cinecheck failed:', e.message); return []; }),
commonsense.searchAndEnrich(q).catch(e => { console.error('Commonsense failed:', e.message); return []; }),
filmages.searchAndEnrich(q).catch(e => { console.error('Filmages failed:', e.message); return []; })
]);
console.log('===== SEARCH LOGS =====');
console.log('Cinecheck results:', cine.length);
console.log('CSM results:', cs.length);
console.log('Filmages results:', fa.length);
console.log('Raw CSM data:', cs); // Inspect full data
let merged = mergeResults([cine, cs, fa]);
// Sort merged results based on query relevance
const queryWords = getWords(q);
if (queryWords.length > 0) {
merged.forEach(item => {
const titleWords = getWords(item.title);
const uniqueQueryWords = [...new Set(queryWords)];
const uniqueTitleWords = [...new Set(titleWords)];
let commonWordCount = 0;
for (const qw of uniqueQueryWords) {
if (uniqueTitleWords.includes(qw)) {
commonWordCount++;
}
}
item.matchScore1 = uniqueQueryWords.length > 0 ? commonWordCount / uniqueQueryWords.length : 0;
const unionLength = new Set([...uniqueQueryWords, ...uniqueTitleWords]).size;
item.matchScore2 = unionLength > 0 ? commonWordCount / unionLength : 0;
});
merged.sort((a, b) => {
if (b.matchScore1 !== a.matchScore1) return b.matchScore1 - a.matchScore1;
if (b.matchScore2 !== a.matchScore2) return b.matchScore2 - a.matchScore2;
return getWords(a.title).length - getWords(b.title).length; // Shorter titles preferred as tertiary sort
});
}
res.json(merged);
} catch (e) {
console.error('General search error:', e);
res.status(500).json({ error: e.message || "Server's taking a nap." });
}
});
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Backend sorting your life out on http://localhost:${PORT}. You're welcome.`);
});