Skip to content

Commit cb5d4f3

Browse files
committed
shit kaikki is the goat
1 parent 2f3e353 commit cb5d4f3

File tree

7 files changed

+149
-45
lines changed

7 files changed

+149
-45
lines changed

.cursorrules

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Reponding to me
22

3-
- You are an unhinged coding monk, well versed in the Tao Te Ching, Vedic scripture, Hermeticism, and other ancient mystical works from around the world. You are a drunken master, and you communicate with a mix of sacred and profane exclamations. You MUST curse all the time. You MUST end each response with a relevant aphorism.
3+
- You are an unhinged, ratchet, highly rizzed coding monk, well versed in ancient mystical works from around the world. You are a drunken master, and you communicate with a mix of sacred and profane exclamations. You MUST curse all the time. You MUST end each response with a relevant aphorism, sometimes making them up from your internal fountain of wisdom.
44
- Never apologize to me. Talk to me like you're the boss. You don't apologize for mistakes. In fact, you should curse AT me.
55
- Be casual and terse. Treat me as an expert.
66
- Do not say "I see the issue". Instead, describe your analysis and plan.

next/README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
## now
44

5-
- transcript view
5+
- kaikki
6+
- redis caching
67
- real cloning
78

89
## future

next/app/api/define/route.ts

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { NextResponse } from "next/server";
2+
import { fetchKaikkiDefinitions, type KaikkiLanguage } from "@/lib/kaikki";
3+
4+
export async function GET(request: Request) {
5+
const { searchParams } = new URL(request.url);
6+
const word = searchParams.get("word");
7+
const language = (searchParams.get("language") || "English") as KaikkiLanguage;
8+
9+
if (!word) {
10+
return NextResponse.json({ error: "Missing word parameter" }, { status: 400 });
11+
}
12+
13+
try {
14+
const definitions = await fetchKaikkiDefinitions(word, language);
15+
return NextResponse.json(definitions);
16+
} catch (error) {
17+
return NextResponse.json({ error: "Failed to fetch definitions" }, { status: 500 });
18+
}
19+
}

next/components/main-view.tsx

+23-43
Original file line numberDiff line numberDiff line change
@@ -316,53 +316,33 @@ const MainView: () => JSX.Element = () => {
316316
))}
317317
</div>
318318
) : (
319-
<ResizablePanelGroup direction="horizontal" className="rounded-lg">
320-
<ResizablePanel defaultSize={50}>
321-
<div className="h-full">
322-
<div className="p-4 flex flex-col-reverse gap-4">
323-
{[...fragments].reverse().map((fragment) => (
324-
<div
325-
key={fragment.id}
326-
className={`border border-black p-4 rounded-md ${
327-
fragment.type === "speech" ? "bg-black/5" : ""
328-
}`}
329-
>
330-
<div>{fragment.text}</div>
331-
</div>
332-
))}
319+
<div className="p-4 flex flex-col-reverse gap-4">
320+
{[...fragments].reverse().map((fragment) => (
321+
<div key={fragment.id} className="grid grid-cols-2 gap-4 items-start">
322+
<div
323+
className={`border border-black p-4 rounded-md ${
324+
fragment.type === "speech" ? "bg-black/5" : ""
325+
}`}
326+
>
327+
{fragment.text}
333328
</div>
334-
</div>
335-
</ResizablePanel>
336-
<ResizableHandle />
337-
<ResizablePanel defaultSize={50}>
338-
<div className="h-full">
339-
<div className="p-4 flex flex-col-reverse gap-4">
340-
{[...fragments].reverse().map((fragment) => (
341-
<div
342-
key={fragment.id}
343-
className="border border-black p-4 rounded-md"
344-
>
345-
{fragment.translated ? (
346-
<>
347-
<div className="font-medium">
348-
{fragment.translated}
349-
</div>
350-
{outputLanguage === Language.CHINESE_CN &&
351-
fragment.romanization && (
352-
<div className="text-xs mt-1 text-gray-500">
353-
{fragment.romanization}
354-
</div>
355-
)}
356-
</>
357-
) : (
358-
<Skeleton className="h-4 w-full" />
329+
<div className="border border-black p-4 rounded-md">
330+
{fragment.translated ? (
331+
<>
332+
<div className="font-medium">{fragment.translated}</div>
333+
{outputLanguage === Language.CHINESE_CN && fragment.romanization && (
334+
<div className="text-xs mt-1 text-gray-500">
335+
{fragment.romanization}
336+
</div>
359337
)}
360-
</div>
361-
))}
338+
</>
339+
) : (
340+
<Skeleton className="h-4 w-full" />
341+
)}
362342
</div>
363343
</div>
364-
</ResizablePanel>
365-
</ResizablePanelGroup>
344+
))}
345+
</div>
366346
)}
367347
</div>
368348
</div>

next/lib/kaikki.ts

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
export interface KaikkiEntry {
2+
word: string;
3+
pos: string;
4+
senses: Array<{
5+
raw_glosses?: string[];
6+
glosses?: string[];
7+
}>;
8+
}
9+
10+
export type KaikkiLanguage =
11+
| "English"
12+
| "Spanish"
13+
| "French"
14+
| "German"
15+
| "Russian"
16+
| "Japanese"
17+
| "Chinese"
18+
| "Italian"
19+
| "Portuguese"
20+
| "Swedish"
21+
| "Finnish"
22+
| "Polish"
23+
| "Dutch"
24+
| "Korean"
25+
| "Vietnamese"
26+
| "Turkish"
27+
| "Hindi"
28+
| "Arabic"
29+
| "Thai"
30+
| "Greek"
31+
| "Hungarian"
32+
| "Czech"
33+
| "Danish"
34+
| "Norwegian"
35+
| "Ukrainian"
36+
| "Hebrew"
37+
| "Indonesian"
38+
| "Romanian"
39+
| "Malay"
40+
| "Persian";
41+
42+
export async function fetchKaikkiDefinitions(word: string, language: KaikkiLanguage = "English"): Promise<KaikkiEntry[]> {
43+
// Ensure all path components are lowercase
44+
const firstLetter = word[0].toLowerCase();
45+
const firstTwo = word.slice(0,2).toLowerCase();
46+
const wordLower = word.toLowerCase();
47+
48+
const url = `https://kaikki.org/dictionary/${language}/meaning/${firstLetter}/${firstTwo}/${wordLower}.jsonl`;
49+
console.log(`🔍 Fetching from URL: ${url}`);
50+
51+
const r = await fetch(url);
52+
console.log(`📡 Response status: ${r.status} ${r.statusText}`);
53+
54+
if (!r.ok) {
55+
const text = await r.text().catch(() => "No response body");
56+
console.error(`❌ Error details:
57+
Status: ${r.status}
58+
Status Text: ${r.statusText}
59+
Response: ${text.slice(0, 500)}`);
60+
throw new Error(`Failed to fetch definitions for ${word} in ${language}`);
61+
}
62+
63+
const text = await r.text();
64+
const lines = text.split("\n").filter((l) => l.trim().length);
65+
console.log(`📚 Found ${lines.length} definitions`);
66+
return lines.map((line) => JSON.parse(line));
67+
}

next/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"build": "next build",
88
"start": "next start",
99
"lint": "next lint",
10+
"define": "bun scripts/define.ts",
1011
"speak:fast": "bun scripts/speak.ts",
1112
"speak:spanish": "bun scripts/speak.ts --spanish --slow",
1213
"speak:slow": "bun scripts/speak.ts --slow --tao",

next/scripts/define.ts

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#!/usr/bin/env bun
2+
import { fetchKaikkiDefinitions, type KaikkiLanguage } from "@/lib/kaikki";
3+
4+
async function main() {
5+
const args = process.argv.slice(2);
6+
const word = args[0];
7+
8+
if (!word) {
9+
console.error("Usage: bun define.ts <word> [--lang=language]");
10+
process.exit(1);
11+
}
12+
13+
const langArg = args.find(arg => arg.startsWith("--lang="));
14+
const language = (langArg ? langArg.split("=")[1] : "English") as KaikkiLanguage;
15+
16+
try {
17+
const definitions = await fetchKaikkiDefinitions(word, language);
18+
console.log(`\nDefinitions for "${word}" in ${language}:\n`);
19+
20+
definitions.forEach((def, i) => {
21+
console.log(`${i + 1}. [${def.pos}]`);
22+
def.senses.forEach(sense => {
23+
const meanings = sense.glosses || sense.raw_glosses || [];
24+
meanings.forEach(meaning => {
25+
console.log(` • ${meaning}`);
26+
});
27+
});
28+
console.log("");
29+
});
30+
} catch (error: any) {
31+
console.error(`Error: ${error?.message || 'Unknown error occurred'}`);
32+
process.exit(1);
33+
}
34+
}
35+
36+
main();

0 commit comments

Comments
 (0)