Merge github/main into embeddings

This commit is contained in:
George Powell
2025-12-30 15:34:03 -05:00
8 changed files with 136 additions and 34 deletions

2
.gitignore vendored
View File

@@ -27,6 +27,6 @@ vite.config.ts.timestamp-*
llms-*
engwebu_usfx.xml
embeddings-cache-L12.json
embeddings-cache-L6.json
engwebu_usfx.xml

View File

@@ -20271,7 +20271,7 @@
<chapter number="56">
<verse number="1">Thus says the Lord: “Keep justice, and do righteousness, For My salvation is about to come, And My righteousness to be revealed.</verse>
<verse number="2">Blessed is the man who does this, And the son of man who lays hold on it; Who keeps from defiling the Sabbath, And keeps his hand from doing any evil.”</verse>
<verse number="3">Do not let the son of the foreigner Who has joined himself to the LordSpeak, saying, “The Lord has utterly separated me from His people”; Nor let the eunuch say, “Here I am, a dry tree.”</verse>
<verse number="3">Do not let the son of the foreigner Who has joined himself to the Lord speak, saying, “The Lord has utterly separated me from His people”; Nor let the eunuch say, “Here I am, a dry tree.”</verse>
<verse number="4">For thus says the Lord: “To the eunuchs who keep My Sabbaths, And choose what pleases Me, And hold fast My covenant,</verse>
<verse number="5">Even to them I will give in My house And within My walls a place and a name Better than that of sons and daughters; I will give them an everlasting name That shall not be cut off.</verse>
<verse number="6">“Also the sons of the foreigner Who join themselves to the Lord, to serve Him, And to love the name of the Lord, to be His servants— Everyone who keeps from defiling the Sabbath, And holds fast My covenant—</verse>

View File

@@ -0,0 +1,53 @@
import Database from 'bun:sqlite';
// Database path - adjust if your database is located elsewhere
const dbPath = process.env.DATABASE_URL || './local.db';
console.log(`Connecting to database: ${dbPath}`);
const db = new Database(dbPath);
// Query all rows from daily_completions
const query = db.query(`
SELECT date, guess_count
FROM daily_completions
ORDER BY date
`);
const rows = query.all() as { date: string; guess_count: number }[];
if (rows.length === 0) {
console.log('No completions found in the database.');
db.close();
process.exit(0);
}
// Group by date and calculate average guesses
const dateStats = new Map<string, { total: number; count: number }>();
for (const row of rows) {
const existing = dateStats.get(row.date) || { total: 0, count: 0 };
existing.total += row.guess_count;
existing.count += 1;
dateStats.set(row.date, existing);
}
// Display results
console.log('\n=== Average Guesses Per Day ===\n');
console.log('Date | Avg Guesses | Total Completions');
console.log('--------------|-------------|-------------------');
for (const [date, stats] of dateStats) {
const avg = (stats.total / stats.count).toFixed(2);
console.log(`${date.padEnd(14)}| ${avg.padStart(11)}| ${stats.count.toString().padStart(19)}`);
}
// Calculate overall average
const totalGuesses = Array.from(dateStats.values()).reduce((sum, s) => sum + s.total, 0);
const totalCompletions = Array.from(dateStats.values()).reduce((sum, s) => sum + s.count, 0);
const overallAvg = (totalGuesses / totalCompletions).toFixed(2);
console.log('--------------|-------------|-------------------');
console.log(`Overall Average: ${overallAvg} guesses across ${totalCompletions} completions`);
db.close();

View File

@@ -6,13 +6,16 @@
let displayReference = $derived(
dailyVerse.reference.replace(/^Psalms /, "Psalm ")
);
let displayVerseText = $derived(
dailyVerse.verseText.replace(/^([a-z])/, (c) => c.toUpperCase())
);
</script>
<div class="bg-gray-50 rounded-2xl shadow-xl p-8 sm:p-12 mb-4 sm:mb-12 w-full">
<blockquote
class="text-xl sm:text-2xl font-triodion leading-relaxed text-gray-700 text-center"
>
{dailyVerse.verseText}
{displayVerseText}
</blockquote>
{#if isWon}
<p class="text-center text-lg! big-text text-green-600! font-bold mt-8">

View File

@@ -1,6 +1,7 @@
<script lang="ts">
import { fade } from "svelte/transition";
import { getBookById, toOrdinal, getNextGradeMessage } from "$lib/utils/game";
import { onMount } from "svelte";
interface StatsData {
solveRank: number;
@@ -33,10 +34,10 @@
// List of congratulations messages with weights
const congratulationsMessages: WeightedMessage[] = [
{ text: "🎉 Congratulations! 🎉", weight: 1000 },
{ text: "You got it!", weight: 10 },
{ text: "🎉 Yup 🎉", weight: 5 },
{ text: "👍🏻 Very nice! 👍🏻", weight: 1 },
{ text: "Congratulations!", weight: 10 },
{ text: "You got it!", weight: 1000 },
{ text: "Yup,", weight: 100 },
{ text: "Very nice!", weight: 1 },
];
// Function to select a random message based on weights
@@ -45,9 +46,9 @@
if (guessCount === 1) {
const n = Math.random();
if (n < 0.99) {
return "🤯 First try! 🤯";
return "🌟 First try! 🌟";
} else {
return " Axios";
return "🗣 Axios! 🗣";
}
}
@@ -75,13 +76,12 @@
<div
class="p-8 sm:p-12 w-full bg-linear-to-r from-green-400 to-green-600 text-white rounded-2xl shadow-2xl text-center fade-in"
>
<h2 class="text-2xl sm:text-4xl font-black mb-4 drop-shadow-lg">
<!-- <h2 class="text-2xl sm:text-4xl font-black mb-4 drop-shadow-lg">
{congratulationsMessage}
</h2>
<p class="text-lg sm:text-xl md:text-2xl">
The verse is from <span class="font-black text-xl sm:text-2xl md:text-3xl"
>{bookName}</span
>
</h2> -->
<p class="text-xl sm:text-3xl md:text-4xl">
{congratulationsMessage} The verse is from
<span class="font-black text-xl sm:text-2xl md:text-3xl">{bookName}</span>.
</p>
<p
class="text-2xl font-bold mt-6 p-2 mx-2 bg-black/20 rounded-lg inline-block"
@@ -167,8 +167,8 @@
{statsData.averageGuesses}
</div>
<div class="text-xs sm:text-sm opacity-90 mt-1">
People guessed correctly after {statsData.averageGuesses} guesses on
average
People guessed correctly after {statsData.averageGuesses}
{statsData.averageGuesses === 1 ? "guess" : "guesses"} on average
</div>
</div>
</div>

View File

@@ -86,6 +86,18 @@
`Guess: ${book.name} (order ${book.order}), Correct: ${correctBook.name} (order ${correctBook.order}), Adjacent: ${adjacent}`
);
if (guesses.length === 0) {
const key = `bibdle-first-guess-${dailyVerse.date}`;
if (
localStorage.getItem(key) !== "true" &&
browser &&
(window as any).umami
) {
(window as any).umami.track("First guess");
localStorage.setItem(key, "true");
}
}
guesses = [
{
book,
@@ -260,6 +272,18 @@
submitStats();
});
$effect(() => {
if (!browser || !isWon) return;
const key = `bibdle-win-tracked-${dailyVerse.date}`;
if (localStorage.getItem(key) === "true") return;
if ((window as any).umami) {
(window as any).umami.track("Guessed correctly", {
totalGuesses: guesses.length,
});
}
localStorage.setItem(key, "true");
});
function generateShareText(): string {
const emojis = guesses
.slice()
@@ -362,11 +386,12 @@
</script>
<svelte:head>
<title>Bibdle &mdash; A daily bible game{isDev ? " (dev)" : ""}</title>
<meta
<!-- <title>Bibdle &mdash; A daily bible game{isDev ? " (dev)" : ""}</title> -->
<title>A daily bible game{isDev ? " (dev)" : ""}</title>
<!-- <meta
name="description"
content="A Wordle-inspired Bible game (short for Bible Daily)"
/>
content="Guess which book of the Bible a verse comes from."
/> -->
</svelte:head>
<div class="min-h-dvh md:bg-linear-to-br md:from-blue-50 md:to-indigo-200 py-8">

View File

@@ -7,7 +7,7 @@
}
html, body {
background: oklch(98.11% 0.02777 158.93);
background: oklch(89.126% 0.06134 298.626);
}
.big-text {

45
todo.md
View File

@@ -1,26 +1,37 @@
# in progress
- root menu: classic / imposter mode / impossible mode (complete today's classic and imposter modes to unlock)
# todo
- Difficulty levels
- difficult mode (guess old or new testament, first try _only_)
- impossible mode (1894 scrivener koine greek NT or some hebrew version for OT) three guesses only
- impossible mode (1904 greek bible) three guesses only.
- "login to see your stats, unlock practice mode, and more"
- share both classic and impossible mode with both buttons
- add imposter mode
- instructions
- classic mode: identify what book the verse is from (e.g. Genesis, John, Revelations...) in as few guesses as possible.
- imposter mode: out of four options, identify the verse that is not in the Bible
- impossible mode: identify which book of the bible the verse is from in less than three guesses.
- add login + saved stats + streak etc.
- add deuterocanonical books
<!-- Login features -->
- Practice mode: Unlimited verses
- Create public or private leaderboards
- Passport book with badges:
- Passport book with awards:
- Guess each Gospel first try
- "Guessed all Gospels", "Perfect week", "Old Testament expert"
- Theologian: Guess each book first try
- If chapter is 6 and verse 7, earn award "Six seven"
- instructions
# places to send
- linkedin post
- ocf discord server ✅
- nick makiej ✅
- difficult mode (guess old or new testament, first try _only_) (???)
# About this game
@@ -36,6 +47,16 @@ I created Bibdle from a combination of two things. The first is my lifelong desi
# done
## december 27th
- add event log to submitting first-guess or correct-guess to umami (to make bounce rate more accurate)
## december 26th
- created embeddings for every bible verse (verse similarity finder)
- failed at having AI write a USFX format parser
- found a npm library for parsing USFX
## december 23rd
- switched to local copy of NKJV