-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.ts
More file actions
75 lines (60 loc) · 2.71 KB
/
server.ts
File metadata and controls
75 lines (60 loc) · 2.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
import dotenv from 'dotenv';
import express, { Request, Response } from 'express';
import db from './src/config/db';
import { analyzeMenuWithAI } from './src/services/llm';
import { fetchPageContent } from './src/services/scraper';
import { ValidatedMenu, MenuRequest, CacheRow } from './src/schema/validation';
dotenv.config();
const app = express();
app.use(express.json());
app.post('/summarize', async (req: Request<{}, {}, MenuRequest>, res: Response) => {
try {
const { url, date } = req.body;
const forceRefresh = req.query.refresh === 'true';
if (!url || !date) {
return res.status(400).json({ error: 'Missing url or date' });
}
console.log(`\n Request: ${url} [${date}]`);
db.prepare('DELETE FROM cache WHERE expires_at < ?').run(Date.now());
const cacheKey = `${url}|${date}`;
if (!forceRefresh) {
const cachedRow = db.prepare('SELECT data FROM cache WHERE key = ?').get(cacheKey) as CacheRow | undefined;
if (cachedRow) {
console.log('Cache HIT');
const parsedData = JSON.parse(cachedRow.data) as ValidatedMenu;
return res.json({ ...parsedData, source: 'cache' });
}
}
console.log('Downloading...');
let pageText = "";
try {
pageText = await fetchPageContent(url);
} catch (err: any) {
console.error(`Download error: ${err.message || err.status}`);
const status = err.status || 500;
const message = status === 504 ? "Časový limit vypršel" : "Stránka není dostupná";
return res.status(status).json({ error: message });
}
console.log('AI Analysis...');
const menuData = await analyzeMenuWithAI(pageText, date);
const finalResult: ValidatedMenu = { ...menuData, source_url: url };
const ttl = (finalResult.is_closed || finalResult.menu_items.length === 0)
? 30 * 60 * 1000 // 30 min (Short TTL)
: 24 * 60 * 60 * 1000; // 24 hours (Long TTL)
db.prepare('INSERT OR REPLACE INTO cache (key, data, created_at, expires_at) VALUES (?, ?, ?, ?)')
.run(cacheKey, JSON.stringify(finalResult), Date.now(), Date.now() + ttl);
console.log('Success!');
// @ts-ignore
res.json({ ...finalResult, source: 'network' });
} catch (error: any) {
console.error('SERVER ERROR:', error);
res.status(500).json({ error: error.message || 'Internal Server Error' });
}
});
export default app;
if (require.main === module) {
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});
}