mcmeszi commited on
Commit
42d8d37
·
verified ·
1 Parent(s): 6fcd392

Update server.js

Browse files
Files changed (1) hide show
  1. server.js +56 -117
server.js CHANGED
@@ -36,13 +36,16 @@ function toVerseArray(flatArr) {
36
  }
37
 
38
  function normaliseBook(raw) {
39
- if (Array.isArray(raw) && Array.isArray(raw[0])) return raw; // already [[…]]
 
 
40
  if (raw?.chapters) {
41
  return raw.chapters.map(ch => Array.isArray(ch) ? ch : ch.verses?.map(v => (v.text ?? v).trim()));
42
  }
 
43
  if (raw?.verses) {
44
  const tmp = toVerseArray(raw.verses);
45
- return tmp[Object.keys(tmp)[0]]; // array of chapters for this single book
46
  }
47
  return null;
48
  }
@@ -54,9 +57,18 @@ try {
54
  txt = txt.replace(/^[\uFEFF\u200B]+/, ""); // BOM/ZWSP strip
55
  const parsed = JSON.parse(txt);
56
 
57
- let structured = parsed;
58
- if (Array.isArray(parsed) && parsed[0]?.book) {
59
- structured = toVerseArray(parsed);
 
 
 
 
 
 
 
 
 
60
  }
61
 
62
  const normalised = {};
@@ -66,21 +78,21 @@ try {
66
  normalised[book] = norm;
67
  }
68
  LOCAL_BIBLE = normalised;
69
- console.log("📖 KJV memóriacache kész (", Object.keys(LOCAL_BIBLE).length, "könyv ).");
70
  }
71
  } catch (e) {
72
- console.warn("⚠️ Helyi kjv.json nem olvasható vagy hibás – BibleAPI fallback", e.message);
73
  LOCAL_BIBLE = null;
74
  }
75
 
76
  /* ------------------------------------------------------------------
77
- 2) Book → ID (BibleAPI /data)
78
  ------------------------------------------------------------------ */
79
- const BOOK_IDS = { Genesis: "GEN", Exodus: "EXO", Leviticus: "LEV", Numbers: "NUM", Deuteronomy: "DEU", Joshua: "JOS", Judges: "JDG", Ruth: "RUT", "1 Samuel": "1SA", "2 Samuel": "2SA", "1 Kings": "1KI", "2 Kings": "2KI", "1 Chronicles": "1CH", "2 Chronicles": "2CH", Ezra: "EZR", Nehemiah: "NEH", Esther: "EST", Job: "JOB", Psalms: "PSA", Proverbs: "PRO", Ecclesiastes: "ECC", "Song of Solomon": "SNG", Isaiah: "ISA", Jeremiah: "JER", Lamentations: "LAM", Ezekiel: "EZK", Daniel: "DAN", Hosea: "HOS", Joel: "JOL", Amos: "AMO", Obadiah: "OBA", Jonah: "JON", Micah: "MIC", Nahum: "NAM", Habakkuk: "HAB", Zephaniah: "ZEP", Haggai: "HAG", Zechariah: "ZEC", Malachi: "MAL", Matthew: "MAT", Mark: "MRK", Luke: "LUK", John: "JHN", Acts: "ACT", Romans: "ROM", "1 Corinthians": "1CO", "2 Corinthians": "2CO", Galatians: "GAL", Ephesians: "EPH", Philippians: "PHP", Colossians: "COL", "1 Thessalonians": "1TH", "2 Thessalonians": "2TH", "1 Timothy": "1TI", "2 Timothy": "2TI", Titus: "TIT", Philemon: "PHM", Hebrews: "HEB", James: "JAS", "1 Peter": "1PE", "2 Peter": "2PE", "1 John": "1JN", "2 John": "2JN", "3 John": "3JN", Jude: "JUD", Revelation: "REV" };
80
- const toBookId = name => BOOK_IDS[name] || name.slice(0, 3).toUpperCase();
81
 
82
  /* ------------------------------------------------------------------
83
- 3) Ratelimiter BibleAPI‑hoz (token‑bucket 15/30 s)
84
  ------------------------------------------------------------------ */
85
  let tokens = 15;
86
  setInterval(() => { tokens = 15; }, 30_000);
@@ -100,122 +112,49 @@ async function limitedFetch(url, opts) {
100
  4) Cache helpers
101
  ------------------------------------------------------------------ */
102
  const verseCache = new Map();
103
- const metaCache = new Map();
104
- const getCache = (map, k) => { const v = map.get(k); return v && v.exp > Date.now() ? v.data : undefined; };
105
- const setCache = (map, k, data, ttl = 3_600_000) => map.set(k, { data, exp: Date.now() + ttl });
106
 
107
  /* ------------------------------------------------------------------
108
- 5) Local helpers
109
  ------------------------------------------------------------------ */
110
- const getLocalVerse = (b, c, v) => LOCAL_BIBLE?.[b]?.[c - 1]?.[v - 1] ?? null;
111
- const getLocalChapterCounts = b => LOCAL_BIBLE?.[b]?.map(ch => ch.length) ?? null;
112
-
113
- async function fetchEnglishVerse(book, ch, v) {
114
- const ref = `${book} ${ch}:${v}`;
115
- const cached = getCache(verseCache, ref);
116
- if (cached) return cached;
117
- const local = getLocalVerse(book, ch, v);
118
- if (local) { setCache(verseCache, ref, local); return local; }
119
- const url = `https://bible-api.com/${encodeURIComponent(ref)}?translation=kjv`;
120
- const r = await limitedFetch(url);
121
- if (!r.ok) throw new Error(`Bible-API verse error ${r.status}`);
122
- const j = await r.json();
123
- const txt = j.text.trim();
124
- setCache(verseCache, ref, txt);
125
  return txt;
126
  }
127
 
128
  /* ------------------------------------------------------------------
129
- 6) Meta fetch
130
  ------------------------------------------------------------------ */
131
- async function bruteForceChapters(book) {
132
- const counts = [];
133
- for (let ch = 1; ch <= 200; ch++) {
134
- const url = `https://bible-api.com/${encodeURIComponent(book + " " + ch)}?translation=kjv`;
135
- const r = await limitedFetch(url);
136
- if (!r.ok) break;
137
- const j = await r.json();
138
  counts.push(j.verses.at(-1).verse);
139
  }
140
  return counts;
141
  }
142
 
143
- async function fetchMetaChapters(book) {
144
- const cached = getCache(metaCache, book);
145
- if (cached) return cached;
146
- const local = getLocalChapterCounts(book);
147
- if (local?.length) { setCache(metaCache, book, local); return local; }
148
- // Try /data endpoint
149
- try {
150
- const url = `https://bible-api.com/data/kjv/${toBookId(book)}`;
151
- const r = await limitedFetch(url);
152
- if (r.ok) {
153
- const j = await r.json();
154
- let chapters = [];
155
- if (Array.isArray(j.chapters)) {
156
- chapters = j.chapters.map(c => parseInt(
157
- c.verses_count ?? c.verse_count ?? (Array.isArray(c.verses) ? c.verses.length : 0) ?? (c.verse_ids?.length ?? 0),
158
- 10));
159
- } else if (j.chapters && typeof j.chapters === "object") {
160
- chapters = Object.keys(j.chapters).sort((a, b) => a - b).map(k => {
161
- const o = j.chapters[k];
162
- return parseInt(
163
- o.verses_count ?? o.verse_count ?? (Array.isArray(o.verses) ? o.verses.length : 0) ?? (o.verse_ids?.length ?? 0),
164
- 10);
165
- });
166
- }
167
- if (chapters.some(n => n > 1)) { setCache(metaCache, book, chapters); return chapters; }
168
- }
169
- } catch (e) {
170
- console.warn("/data endpoint fail", e.message);
171
- }
172
- const brute = await bruteForceChapters(book);
173
- if (brute.length) { setCache(metaCache, book, brute); return brute; }
174
- throw new Error("Meta fetch failed for " + book);
175
- }
176
-
177
- /* ------------------------------------------------------------------
178
- 7) Routes
179
- ------------------------------------------------------------------ */
180
- app.post("/api/analyze", async (req, res) => {
181
- const { book, chapter, verse } = req.body || {};
182
- try {
183
- const engVerse = await fetchEnglishVerse(book, +chapter, +verse);
184
- const openAIRes = await fetch("https://api.openai.com/v1/chat/completions", {
185
- method: "POST",
186
- headers: { "Content-Type": "application/json", Authorization: `Bearer ${process.env.OPENAI_KEY}` },
187
- body: JSON.stringify({
188
- model: "gpt-4o-mini",
189
- messages: [
190
- {
191
- role: "system",
192
- content: "Fordítsd magyarra a megadott Biblia-verset, majd első szám első személyben, legfeljebb két rövid bekezdésben magyarázd el, hogyan kapcsolódik a mai mesterséges intelligencia dilemmáihoz."
193
- },
194
- { role: "user", content: `Verse (KJV): \"${engVerse}\" — ${book} ${chapter}:${verse}` }
195
- ],
196
- temperature: 0.9,
197
- max_tokens: 300
198
- })
199
- });
200
- if (!openAIRes.ok) throw new Error("OpenAI API hiba");
201
- const data = await openAIRes.json();
202
- res.json({ output: data.choices[0].message.content.trim() });
203
- } catch (err) {
204
- console.error(err);
205
- res.status(500).json({ error: err.message });
206
- }
207
- });
208
-
209
- app.get("/api/meta", async (req, res) => {
210
- const { book } = req.query;
211
- if (!book) return res.status(400).json({ error: "Missing book" });
212
- try {
213
- const chapters = await fetchMetaChapters(book);
214
- res.json({ chapters });
215
- } catch (err) {
216
- console.error(err);
217
- res.status(500).json({ error: err.message });
218
- }
219
- });
220
-
221
- app.listen(PORT, () => console.log("🚀 Fut a", PORT, "porton"));
 
36
  }
37
 
38
  function normaliseBook(raw) {
39
+ // a) [[verseStrings]] már
40
+ if (Array.isArray(raw) && Array.isArray(raw[0])) return raw;
41
+ // b) aruljohn: {chapters:[ {verses:[…]} ]}
42
  if (raw?.chapters) {
43
  return raw.chapters.map(ch => Array.isArray(ch) ? ch : ch.verses?.map(v => (v.text ?? v).trim()));
44
  }
45
+ // c) thiagobodruk single-book: {verses:[…]}
46
  if (raw?.verses) {
47
  const tmp = toVerseArray(raw.verses);
48
+ return tmp[Object.keys(tmp)[0]]; // chapter tömb ehhez a könyvhöz
49
  }
50
  return null;
51
  }
 
57
  txt = txt.replace(/^[\uFEFF\u200B]+/, ""); // BOM/ZWSP strip
58
  const parsed = JSON.parse(txt);
59
 
60
+ let structured;
61
+ if (Array.isArray(parsed)) {
62
+ // thiagobodruk: 66 elemű tömb {name, abbrev, chapters}
63
+ structured = {};
64
+ for (const obj of parsed) {
65
+ if (obj.name && Array.isArray(obj.chapters)) structured[obj.name] = obj.chapters;
66
+ }
67
+ } else if (Array.isArray(parsed.verses)) {
68
+ // lapos verse-lista
69
+ structured = toVerseArray(parsed.verses);
70
+ } else {
71
+ structured = parsed; // { Genesis: … }
72
  }
73
 
74
  const normalised = {};
 
78
  normalised[book] = norm;
79
  }
80
  LOCAL_BIBLE = normalised;
81
+ console.log("📖 KJV memória-cache kész (", Object.keys(LOCAL_BIBLE).length, "könyv ).");
82
  }
83
  } catch (e) {
84
+ console.warn("⚠️ Helyi kjv.json nem olvasható vagy hibás – Bible-API fallback", e.message);
85
  LOCAL_BIBLE = null;
86
  }
87
 
88
  /* ------------------------------------------------------------------
89
+ 2) Book → ID (Bible-API /data)
90
  ------------------------------------------------------------------ */
91
+ const BOOK_IDS = { Genesis:"GEN", Exodus:"EXO", Leviticus:"LEV", Numbers:"NUM", Deuteronomy:"DEU", Joshua:"JOS", Judges:"JDG", Ruth:"RUT", "1 Samuel":"1SA", "2 Samuel":"2SA", "1 Kings":"1KI", "2 Kings":"2KI", "1 Chronicles":"1CH", "2 Chronicles":"2CH", Ezra:"EZR", Nehemiah:"NEH", Esther:"EST", Job:"JOB", Psalms:"PSA", Proverbs:"PRO", Ecclesiastes:"ECC", "Song of Solomon":"SNG", Isaiah:"ISA", Jeremiah:"JER", Lamentations:"LAM", Ezekiel:"EZK", Daniel:"DAN", Hosea:"HOS", Joel:"JOL", Amos:"AMO", Obadiah:"OBA", Jonah:"JON", Micah:"MIC", Nahum:"NAM", Habakkuk:"HAB", Zephaniah:"ZEP", Haggai:"HAG", Zechariah:"ZEC", Malachi:"MAL", Matthew:"MAT", Mark:"MRK", Luke:"LUK", John:"JHN", Acts:"ACT", Romans:"ROM", "1 Corinthians":"1CO", "2 Corinthians":"2CO", Galatians:"GAL", Ephesians:"EPH", Philippians:"PHP", Colossians:"COL", "1 Thessalonians":"1TH", "2 Thessalonians":"2TH", "1 Timothy":"1TI", "2 Timothy":"2TI", Titus:"TIT", Philemon:"PHM", Hebrews:"HEB", James:"JAS", "1 Peter":"1PE", "2 Peter":"2PE", "1 John":"1JN", "2 John":"2JN", "3 John":"3JN", Jude:"JUD", Revelation:"REV" };
92
+ const toBookId = name => BOOK_IDS[name] || name.slice(0,3).toUpperCase();
93
 
94
  /* ------------------------------------------------------------------
95
+ 3) Rate-limiter Bible-API (15 req / 30 s)
96
  ------------------------------------------------------------------ */
97
  let tokens = 15;
98
  setInterval(() => { tokens = 15; }, 30_000);
 
112
  4) Cache helpers
113
  ------------------------------------------------------------------ */
114
  const verseCache = new Map();
115
+ const metaCache = new Map();
116
+ const getCache = (map,key)=>{const v=map.get(key);return v&&v.exp>Date.now()?v.data:undefined;};
117
+ const setCache = (map,key,data,ttl=3_600_000)=>map.set(key,{data,exp:Date.now()+ttl});
118
 
119
  /* ------------------------------------------------------------------
120
+ 5) Local lookup helpers
121
  ------------------------------------------------------------------ */
122
+ const getLocalVerse = (b,c,v)=>LOCAL_BIBLE?.[b]?.[c-1]?.[v-1]??null;
123
+ const getLocalChapterCounts = b=>LOCAL_BIBLE?.[b]?.map(ch=>ch.length)??null;
124
+
125
+ async function fetchEnglishVerse(book,ch,v){
126
+ const ref=`${book} ${ch}:${v}`;
127
+ const hit=getCache(verseCache,ref);
128
+ if(hit) return hit;
129
+ const local=getLocalVerse(book,ch,v);
130
+ if(local){setCache(verseCache,ref,local);return local;}
131
+ const url=`https://bible-api.com/${encodeURIComponent(ref)}?translation=kjv`;
132
+ const r=await limitedFetch(url);
133
+ if(!r.ok) throw new Error(`Bible-API verse error ${r.status}`);
134
+ const j=await r.json();
135
+ const txt=j.text.trim();
136
+ setCache(verseCache,ref,txt);
137
  return txt;
138
  }
139
 
140
  /* ------------------------------------------------------------------
141
+ 6) Chapter meta (verse counts)
142
  ------------------------------------------------------------------ */
143
+ async function bruteForceChapters(book){
144
+ const counts=[];
145
+ for(let ch=1;ch<=200;ch++){
146
+ const url=`https://bible-api.com/${encodeURIComponent(book+" "+ch)}?translation=kjv`;
147
+ const r=await limitedFetch(url);
148
+ if(!r.ok) break;
149
+ const j=await r.json();
150
  counts.push(j.verses.at(-1).verse);
151
  }
152
  return counts;
153
  }
154
 
155
+ async function fetchMetaChapters(book){
156
+ const cached=getCache(metaCache,book); if(cached) return cached;
157
+ const local=getLocalChapterCounts(book); if(local?.length){setCache(metaCache,book,local);return local;}
158
+ // /data endpoint
159
+ try{
160
+ const url=`https://bible-api.com/data/kjv/${