इसे छोड़कर कंटेंट पर जाएं

आर्किटेक्चर प्राइमर

ऐप संस्करण: v0.1.1 (fork: DarrellThomas/en-parlant) स्टैक: Tauri v2 (Rust) + React 19 (TypeScript) + Vite


Tauri डेस्कटॉप ऐप बनाने के लिए एक फ्रेमवर्क है। Electron की तरह एक पूरा ब्राउज़र शिप करने के बजाय, Tauri UI के लिए ऑपरेटिंग सिस्टम के बिल्ट-इन वेबव्यू का और बैकएंड के लिए एक Rust प्रोसेस का उपयोग करता है। इसका परिणाम एक छोटी, तेज़ बाइनरी होता है।

दोनों हिस्से IPC (इंटर-प्रोसेस कम्युनिकेशन) के ज़रिए संवाद करते हैं:

+---------------------------+ IPC +---------------------------+
| Rust Backend | <--------------> | React/TS Frontend |
| | (commands + | |
| - Chess engines (UCI) | events) | - Chessboard UI |
| - SQLite database | | - Analysis panels |
| - File I/O | | - Settings |
| - PGN parsing | | - Game tree navigation |
| - Position search index | | - TTS narration |
+---------------------------+ +---------------------------+
src-tauri/src/ src/

Rust उन सभी कार्यों को संभालता है जिनमें गति या सिस्टम एक्सेस की आवश्यकता होती है।

एंट्री पॉइंट: main.rs

Section titled “एंट्री पॉइंट: main.rs”

यह ~50 कमांड रजिस्टर करता है जिन्हें फ्रंटएंड कॉल कर सकता है, प्लगइन्स (filesystem, dialog, HTTP, shell, logging, updater) को इनिशियलाइज़ करता है, और ऐप विंडो शुरू करता है।

कमांड एक मैक्रो से परिभाषित किए जाते हैं:

#[tauri::command]
async fn get_best_moves(id: String, engine: String, ...) -> Result<...> {
// spawn UCI engine, return analysis
}

specta क्रेट इन Rust फ़ंक्शंस से स्वचालित रूप से TypeScript टाइप डेफिनिशन जनरेट करता है, इसलिए फ्रंटएंड को बिना किसी मैनुअल प्रयास के पूर्ण टाइप सेफ्टी मिलती है।

मॉड्यूलकार्य
db/mod.rsDiesel ORM के ज़रिए SQLite डेटाबेस — गेम क्वेरीज़, प्लेयर स्टैट्स, इम्पोर्ट्स, पोज़िशन सर्च
game.rsलाइव गेम इंजन — इंजन-बनाम-मानव और इंजन-बनाम-इंजन गेम, टाइम कंट्रोल, मूव वैलिडेशन प्रबंधित करता है
chess.rsइंजन विश्लेषण — UCI इंजन स्पॉन करता है, इवेंट्स के ज़रिए बेस्ट-मूव परिणाम फ्रंटएंड को स्ट्रीम करता है
engine/UCI प्रोटोकॉल इम्प्लीमेंटेशन — प्रोसेस स्पॉनिंग, stdin/stdout पाइप्स, मल्टी-PV सपोर्ट
pgn.rsPGN फ़ाइल रीडिंग/राइटिंग/टोकनाइज़िंग
opening.rsFEN से ओपनिंग नाम लुकअप (ऐप में बेक की गई बाइनरी डेटा)
puzzle.rsLichess पज़ल डेटाबेस — मेमोरी-मैप्ड रैंडम एक्सेस
fs.rsरिज़्यूम के साथ फ़ाइल डाउनलोड, एक्ज़ीक्यूटेबल परमिशन सेटिंग
sound.rsऑडियो स्ट्रीमिंग के लिए लोकल HTTP सर्वर (Linux ऑडियो वर्कअराउंड)
tts.rsspeech-dispatcher (Linux) / नेटिव OS स्पीच APIs के ज़रिए सिस्टम TTS, साथ ही KittenTTS सर्वर मैनेजमेंट
oauth.rsLichess/Chess.com अकाउंट लिंकिंग के लिए OAuth2 फ्लो
  • हर जगह Async: Tokio रनटाइम, नॉन-ब्लॉकिंग I/O
  • कंकरेंट स्टेट: इंजन प्रोसेसेज़, DB कनेक्शंस, कैशेज़ के लिए DashMap (कंकरेंट HashMap)
  • कनेक्शन पूलिंग: r2d2 SQLite कनेक्शन पूल्स को मैनेज करता है
  • मेमोरी-मैप्ड सर्च: तत्काल परिणामों के लिए mmap’d बाइनरी इंडेक्स के ज़रिए पोज़िशन लुकअप
  • इवेंट स्ट्रीमिंग: Rust इवेंट्स (बेस्ट मूव्स, क्लॉक टिक्स, गेम ओवर) एमिट करता है जिन्हें React रीयल-टाइम में सुनता है

बिल्ड पाइपलाइन: Vite

Section titled “बिल्ड पाइपलाइन: Vite”

vite.config.ts कॉन्फ़िगर करता है:

  • Babel कंपाइलर के साथ React प्लगइन
  • TanStack Router प्लगइनroutes/ फ़ोल्डर से रूट ट्री ऑटो-जनरेट करता है
  • Vanilla Extract — ज़ीरो-रनटाइम CSS-in-JS
  • पाथ एलियास: @ मैप करता है ./src को
  • पोर्ट 1420 पर डेव सर्वर

बिल्ड फ्लो:

pnpm dev → Vite on :1420 + Tauri opens webview pointing to it
pnpm build → tsc (typecheck) → vite build (bundle to dist/) → tauri build (native binary)

रूट कंपोनेंट:

  • Tauri प्लगइन्स (log, process, updater) इनिशियलाइज़ करता है
  • पर्सिस्टेंट एटम्स से यूज़र प्रेफरेंसेज़ लोड करता है
  • Mantine UI थीम सेट करता है
  • राउटर रजिस्टर करता है
  • ऐप अपडेट्स की जाँच करता है

स्टेट मैनेजमेंट

Section titled “स्टेट मैनेजमेंट”

Jotai एटम्स (src/state/atoms.ts) — हल्का रिएक्टिव स्टेट:

श्रेणीउदाहरण
टैब्सtabsAtom, activeTabAtom (मल्टी-डॉक्यूमेंट इंटरफ़ेस)
डायरेक्टरीज़storedDocumentDirAtom, storedDatabasesDirAtom
UI प्रेफरेंसेज़primaryColorAtom, fontSizeAtom, pieceSetAtom
इंजनengineMovesFamily, engineProgressFamily (atomFamily के ज़रिए प्रति-टैब)
TTSttsEnabledAtom, ttsProviderAtom, ttsVoiceIdAtom, ttsVolumeAtom, ttsSpeedAtom, ttsLanguageAtom

atomWithStorage() वाले एटम्स स्वचालित रूप से localStorage में पर्सिस्ट होते हैं।

Zustand स्टोर्स जटिल डोमेन स्टेट के लिए:

  • src/state/store/tree.ts — गेम ट्री नेविगेशन, मूव ब्रांचिंग, एनोटेशंस, कमेंट्स। इम्यूटेबल अपडेट्स के लिए Immer का उपयोग करता है।
  • src/state/store/database.ts — डेटाबेस व्यू फ़िल्टर्स, चयनित गेम, पेजिनेशन

src/routes/ में फ़ाइल-आधारित राउटिंग:

routes/
__root.tsx # Root layout (AppShell, menu bar)
index.tsx # Home/dashboard
databases/ # Database browsing
accounts.tsx # Lichess/Chess.com accounts
settings.tsx # App preferences
engines.tsx # Engine management

कंपोनेंट्स: src/components/

Section titled “कंपोनेंट्स: src/components/”
समूहउद्देश्य
boards/चेसबोर्ड (chessground), मूव इनपुट, eval बार, एनालिसिस डिस्प्ले, प्रमोशन मोडल, एरो ड्रॉइंग
panels/साइड पैनल: इंजन विश्लेषण (BestMoves), डेटाबेस पोज़िशन सर्च, एनोटेशन एडिटिंग, गेम इन्फो, प्रैक्टिस मोड
databases/डेटाबेस UI: गेम टेबल, प्लेयर टेबल, डिटेल कार्ड्स, फ़िल्टरिंग
settings/प्रेफरेंस फ़ॉर्म्स, इंजन पाथ्स, TTS सेटिंग्स
home/अकाउंट कार्ड्स, इम्पोर्ट UI
common/शेयर्ड: TreeStateContext, मैटेरियल डिस्प्ले, कमेंट स्पीकर आइकन
tabs/मल्टी-टैब बार

फ्रंटएंड Rust को कैसे कॉल करता है

Section titled “फ्रंटएंड Rust को कैसे कॉल करता है”

कमांड्स (रिक्वेस्ट/रिस्पॉन्स)

Section titled “कमांड्स (रिक्वेस्ट/रिस्पॉन्स)”

Specta src/bindings/generated.ts में TypeScript बाइंडिंग्स जनरेट करता है:

// Auto-generated from Rust #[tauri::command] functions
export const commands = {
async getBestMoves(id, engine, tab, goMode, options) {
return await TAURI_INVOKE("get_best_moves", { id, engine, tab, goMode, options });
},
// ~50 more commands...
}

React कंपोनेंट्स इन्हें सामान्य async फ़ंक्शंस की तरह कॉल करते हैं:

import { commands } from "@/bindings";
const result = await commands.getBestMoves(id, engine, tab, goMode, options);

इवेंट्स (स्ट्रीमिंग, Rust से React तक)

Section titled “इवेंट्स (स्ट्रीमिंग, Rust से React तक)”

रीयल-टाइम डेटा (इंजन विश्लेषण, क्लॉक टिक्स, गेम मूव्स) के लिए:

Rust: app.emit("best_moves_payload", BestMovesPayload { depth: 24, ... })
React: listen("best_moves_payload", (event) => updateBestMoves(event.payload))

ऐप सिस्टम एक्सेस के लिए कई आधिकारिक प्लगइन्स का उपयोग करता है:

प्लगइनउद्देश्य
@tauri-apps/plugin-fsफ़ाइलें पढ़ना/लिखना
@tauri-apps/plugin-dialogफ़ाइल पिकर्स, मैसेज बॉक्सेज़
@tauri-apps/plugin-httpHTTP क्लाइंट (इंजन डाउनलोड्स, क्लाउड TTS)
@tauri-apps/plugin-shellUCI इंजन एक्ज़ीक्यूट करना
@tauri-apps/plugin-updaterऑटो-अपडेट जाँच
@tauri-apps/plugin-logस्ट्रक्चर्ड लॉगिंग
@tauri-apps/plugin-osCPU/RAM डिटेक्शन

टेक्स्ट-टू-स्पीच (TTS): एक प्राइमर

Section titled “टेक्स्ट-टू-स्पीच (TTS): एक प्राइमर”

En Parlant~ जब आप किसी गेम में कदम-दर-कदम आगे बढ़ते हैं तो शतरंज की चालें और कमेंटरी ज़ोर से पढ़ सकता है। यह अनुभाग बताता है कि TTS सिस्टम कैसे बनाया गया है — प्रीप्रोसेसिंग पाइपलाइन, प्रोवाइडर आर्किटेक्चर, और कैशिंग रणनीति। सेटअप निर्देशों के लिए, TTS मेनू में TTS गाइड देखें।

TTS कैसे काम करता है (संक्षिप्त संस्करण)

Section titled “TTS कैसे काम करता है (संक्षिप्त संस्करण)”

टेक्स्ट-टू-स्पीच लिखित टेक्स्ट को बोले गए ऑडियो में बदलता है। आधुनिक TTS सिस्टम हज़ारों घंटों की मानव वाणी पर प्रशिक्षित गहरे न्यूरल नेटवर्क पर बने हैं। मॉडल टेक्स्ट (अक्षर, शब्द, विराम चिह्न) और वाणी की ध्वनिक विशेषताओं (पिच, समय, ज़ोर, श्वास विराम) के बीच संबंध सीखता है। इन्फरेंस के समय, आप टेक्स्ट भेजते हैं और एक ऑडियो वेवफ़ॉर्म वापस पाते हैं।

दो व्यापक दृष्टिकोण हैं:

  • क्लाउड TTS — टेक्स्ट एक रिमोट सर्वर (Google, ElevenLabs, आदि) को भेजा जाता है, जो GPU हार्डवेयर पर एक बड़ा न्यूरल नेटवर्क चलाता है और ऑडियो लौटाता है। उत्कृष्ट गुणवत्ता, लेकिन इंटरनेट आवश्यक है और प्रति-रिक्वेस्ट लागत होती है (हालाँकि अधिकांश प्रदाता फ्री टियर प्रदान करते हैं)।

  • लोकल TTS — एक मॉडल सीधे आपकी मशीन पर चलता है। इंटरनेट की आवश्यकता नहीं, कोई प्रति-रिक्वेस्ट लागत नहीं, और आपका टेक्स्ट कभी आपके कंप्यूटर से बाहर नहीं जाता। हाल के ओपन-सोर्स मॉडल्स (जैसे Kokoro और Piper) ने गुणवत्ता के अंतर को काफ़ी कम कर दिया है।

यदि आप जानना चाहते हैं कि TTS मॉडल आंतरिक रूप से कैसे काम करते हैं, तो HuggingFace (huggingface.co) पर सैकड़ों ओपन-सोर्स स्पीच सिंथेसिस मॉडल होस्ट किए गए हैं जिन्हें आप एक्सप्लोर, डाउनलोड और लोकली चला सकते हैं। हल्के CPU-फ्रेंडली विकल्पों से लेकर अत्याधुनिक रिसर्च मॉडल्स तक खोजने के लिए “text-to-speech” सर्च करें।

प्रोवाइडर आर्किटेक्चर

Section titled “प्रोवाइडर आर्किटेक्चर”

कोर TTS इम्प्लीमेंटेशन src/utils/tts.ts में है। यह एक सिंगल पब्लिक इंटरफ़ेस (speakText()) के इर्द-गिर्द डिज़ाइन किया गया है जिसमें स्वैपेबल बैकएंड हैं। ऐप का बाकी हिस्सा कभी नहीं जानता और न परवाह करता है कि कौन सा प्रोवाइडर सक्रिय है — यह बस speakText() कॉल करता है और ऑडियो आ जाता है।

पाँच प्रोवाइडर समर्थित हैं:

प्रोवाइडरप्रकारबैकएंड
ElevenLabsक्लाउडREST API के ज़रिए न्यूरल वॉइसेज़। MP3 लौटाता है।
Google Cloud TTSक्लाउडREST API के ज़रिए WaveNet वॉइसेज़। Base64-एनकोडेड MP3 लौटाता है।
KittenTTSलोकलबंडल किया गया TTS सर्वर, Rust बैकएंड द्वारा ऑटो-स्टार्ट। localhost पर HTTP के ज़रिए कम्युनिकेट करता है।
OpenTTSलोकलसेल्फ-होस्टेड TTS सर्वर। कई इंजनों (espeak, MaryTTS, Piper, आदि) को सपोर्ट करता है।
System TTSलोकलRust/Tauri कमांड्स के ज़रिए OS-नेटिव स्पीच इंजन (Linux पर speech-dispatcher, Windows पर SAPI, macOS पर AVSpeechSynthesizer)।

प्रोवाइडर चयन एक सिंगल Jotai एटम (ttsProviderAtom) में स्टोर होता है। प्रोवाइडर स्विच करना तत्काल है — एटम बदलें, और अगला speakText() कॉल नए बैकएंड पर रूट हो जाता है।

चुनौती: शतरंज नोटेशन अंग्रेज़ी नहीं है

Section titled “चुनौती: शतरंज नोटेशन अंग्रेज़ी नहीं है”

शतरंज की चालें स्टैंडर्ड अल्जेब्रेइक नोटेशन (SAN) में लिखी जाती हैं: Nf3, Bxe5+, O-O-O, e8=Q#। अगर आप इसे सीधे TTS इंजन में डालें, तो बकवास निकलती है — यह “Nf3” को एक शब्द की तरह उच्चारित करने की कोशिश कर सकता है, या “O-O-O” को “ओ ओ ओ” पढ़ सकता है।

समाधान एक प्रीप्रोसेसिंग पाइपलाइन है जो TTS इंजन तक पहुँचने से पहले शतरंज नोटेशन को प्राकृतिक भाषा में अनुवाद करती है:

SAN Input → Preprocessing → Spoken Output
─────────────────────────────────────────────────────
"Nf3" → sanToSpoken() → "Knight f3"
"Bxe5+" → sanToSpoken() → "Bishop takes e5, check"
"O-O-O" → sanToSpoken() → "castles queenside"
"e8=Q#" → sanToSpoken() → "e8 promotes to Queen, checkmate"

sanToSpoken() फ़ंक्शन किसी भी SAN स्ट्रिंग को उसके घटकों (पीस, डिसएम्बिग्यूएशन, कैप्चर, डेस्टिनेशन, प्रमोशन, चेक/चेकमेट) में विघटित करने के लिए regex पैटर्न मैचिंग का उपयोग करता है और एक शब्दावली तालिका से प्राकृतिक भाषा का उपयोग करके उन्हें पुनः संयोजित करता है।

शतरंज शब्दावली कई भाषाओं में अनुवादित है (अंग्रेज़ी, फ्रेंच, स्पेनिश, जर्मन, जापानी, रूसी, चीनी, कोरियाई, और अन्य)। CHESS_VOCAB तालिका प्रत्येक शब्द को मैप करती है:

English: "Knight takes e5, check"
French: "Cavalier prend e5, échec"
German: "Springer schlägt e5, Schach"
Japanese: "ナイト テイクス e5, チェック"
Russian: "Конь берёт e5, шах"

भाषा सेटिंग यह निर्धारित करती है कि प्रीप्रोसेसिंग के लिए कौन सी शब्दावली तालिका उपयोग की जाती है और TTS इंजन सिंथेसिस के लिए कौन सी वॉइस/एक्सेंट उपयोग करता है।

गेम एनोटेशंस में अक्सर PGN-विशिष्ट मार्कअप होता है जो ज़ोर से पढ़ने पर भयानक लगेगा:

Raw comment: "BLUNDER. 7.Nf3 was better [%eval -2.3] [%cal Gg1f3]"
After cleaning: "7, Knight f3 was better"

cleanCommentForTTS() फ़ंक्शन:

  1. PGN टैग्स हटाता है: [%eval ...], [%csl ...], [%cal ...], [%clk ...]
  2. डुप्लिकेट एनोटेशन शब्द हटाता है (जब ”??” पहले ही “Blunder” कह चुका हो)
  3. गद्य में इनलाइन SAN को विस्तारित करता है: "7.Nf3 controls e5""7, Knight f3 controls e5"
  4. शतरंज शब्दों को ठीक करता है जिन्हें TTS इंजन गलत उच्चारित करते हैं (जैसे, “en prise” → “on preez”)
  5. गद्य में पीस संक्षेपों को विस्तारित करता है: "R vs R""Rook versus Rook"

पूर्ण नैरेशन का निर्माण

Section titled “पूर्ण नैरेशन का निर्माण”

जब आप एक नई चाल पर जाते हैं, तो buildNarration() तीन स्रोतों से पूर्ण बोला गया टेक्स्ट तैयार करता है:

Move: "12, Knight f3, check." ← from sanToSpoken()
Annotation: "Good move." ← from annotation symbol (!)
Comment: "Developing with tempo." ← from cleanCommentForTTS()
Full narration: "12, Knight f3, check. Good move. Developing with tempo."

भागों के बीच डबल-स्पेस TTS इंजनों को एक प्राकृतिक श्वास विराम देता है।

कैशिंग और प्लेबैक

Section titled “कैशिंग और प्लेबैक”

क्लाउड TTS कॉल्स पर पैसे खर्च होते हैं और समय लगता है (~200-500ms राउंड ट्रिप)। एक ही ऑडियो को दोबारा फ़ेच करने से बचने के लिए, प्रत्येक जनरेट की गई क्लिप मेमोरी में blob URL के रूप में कैश की जाती है:

Cache key: "elevenlabs:pNInz6obpgDQGcFmaJgB:en:12, Knight f3, check."
Cache value: blob:http://localhost/abc123 (the MP3 audio in browser memory)

कैश हिट पर, प्लेबैक तत्काल होता है। कैश provider:voice:language:text से कीड होता है, इसलिए वॉइस या भाषा बदलने पर अलग एंट्रीज़ बनती हैं।

बहुत सारे एनोटेशंस वाले गेम्स के लिए, आप पूरे गेम ट्री को बैकग्राउंड में प्रीकैश कर सकते हैं। ऐप हर नोड पर जाता है, नैरेशन टेक्स्ट बनाता है, और आपके नेविगेट शुरू करने से पहले कैश भरने के लिए क्रमिक API कॉल फ़ायर करता है।

कंकरेंसी और कैंसलेशन

Section titled “कंकरेंसी और कैंसलेशन”

तेज़ एरो-की नेविगेशन एक समस्या पैदा करता है: अगर उपयोगकर्ता तेज़ी से 5 बार आगे बढ़ता है, तो आप नहीं चाहते कि 5 ओवरलैपिंग ऑडियो क्लिप्स एक-दूसरे से लड़ें। समाधान एक जनरेशन काउंटर है:

const thisGeneration = ++requestGeneration;
// ... fetch audio ...
if (thisGeneration !== requestGeneration) return; // stale — discard

प्रत्येक नया speakText() कॉल काउंटर बढ़ाता है और AbortController के ज़रिए किसी भी इन-फ्लाइट HTTP रिक्वेस्ट को एबॉर्ट करता है। जब ऑडियो आता है, तो यह जाँचता है कि उसकी जनरेशन अभी भी करंट है या नहीं। अगर उपयोगकर्ता पहले ही आगे बढ़ चुका है, तो रिस्पॉन्स चुपचाप डिस्कार्ड कर दिया जाता है। यह चालों के बीच तेज़ी से क्लिक करने पर भी स्वच्छ, ग्लिच-फ्री ऑडियो देता है।

TTS ऐप में कहाँ जुड़ता है

Section titled “TTS ऐप में कहाँ जुड़ता है”

इंटीग्रेशन पॉइंट्स न्यूनतम हैं:

फ़ाइलक्या होता है
src/state/store/tree.tsहर नेविगेशन फ़ंक्शन (goToNext, goToPrevious, आदि) stopSpeaking() कॉल करता है। जब ऑटो-नैरेट चालू होता है, तो goToNext speakMoveNarration() भी कॉल करता है।
src/components/common/Comment.tsxप्रत्येक कमेंट के बगल में एक स्पीकर आइकन आपको उस कमेंट के लिए TTS मैन्युअली ट्रिगर करने देता है।
src/components/settings/TTSSettings.tsxप्रोवाइडर, वॉइस, भाषा, वॉल्यूम, स्पीड, और API कीज़ दर्ज करने के लिए सेटिंग्स UI।

जब TTS बंद होता है, तो इसमें से कुछ भी कोड नहीं चलता। ऐप अपस्ट्रीम En Croissant के समान ही व्यवहार करता है।


डेटा फ्लो उदाहरण

Section titled “डेटा फ्लो उदाहरण”
User clicks "Analyze"
→ React calls commands.getBestMoves(position, engine, settings)
→ Rust spawns UCI engine process, sends position via stdin
→ Engine writes "info depth 18 score cp 45 pv e2e4 ..." to stdout
→ Rust parses UCI output, emits BestMovesPayload event
→ React's EvalListener receives event, updates atoms
→ UI re-renders: eval bar moves, best move arrows appear
→ User clicks "Stop" → commands.stopEngine() → Rust sets AtomicBool flag

डेटाबेस पोज़िशन सर्च

Section titled “डेटाबेस पोज़िशन सर्च”
User reaches a position on the board
→ React calls commands.searchPosition(fen, gameQuery)
→ Rust queries memory-mapped binary search index
→ Returns: PositionStats (wins/losses/draws) + matching games
→ React renders DatabasePanel with results table
User steps forward with arrow key
→ tree.ts calls stopSpeaking(), then checks isAutoNarrateEnabled()
→ Calls speakMoveNarration(san, comment, annotations, halfMoves)
→ buildNarration() assembles text:
sanToSpoken("Nf3+") → "Knight f3, check"
annotationsToSpoken(["!"]) → "Good move."
cleanCommentForTTS(comment) → strips [%eval], expands inline SAN
→ speakText() checks audioCache
HIT → play blob URL instantly
MISS → fetch from provider API → cache as blob URL → play
→ HTMLAudioElement.play() with volume and playbackRate from atoms

en-parlant/
├── src-tauri/ # RUST BACKEND
│ ├── src/
│ │ ├── main.rs # Entry, command registration, plugins
│ │ ├── chess.rs # Engine analysis
│ │ ├── game.rs # Live game management
│ │ ├── db/ # SQLite database (largest module)
│ │ ├── engine/ # UCI protocol
│ │ ├── pgn.rs # PGN parsing
│ │ ├── puzzle.rs # Puzzle database
│ │ ├── opening.rs # Opening lookup
│ │ └── tts.rs # System TTS + KittenTTS management
│ ├── Cargo.toml # Rust dependencies
│ ├── tauri.conf.json # Tauri config
│ └── capabilities/main.json # Security permissions
├── src/ # REACT/TS FRONTEND
│ ├── App.tsx # Root component
│ ├── state/
│ │ ├── atoms.ts # Jotai atoms (all app state)
│ │ └── store/tree.ts # Game tree (Zustand + TTS hooks)
│ ├── routes/ # TanStack Router (file-based)
│ ├── components/
│ │ ├── boards/ # Chessboard + analysis
│ │ ├── panels/ # Side panels
│ │ ├── databases/ # DB browsing UI
│ │ ├── common/ # Comment display (with TTS speaker icon)
│ │ └── settings/ # Preferences, TTS settings
│ ├── utils/
│ │ ├── chess.ts # Game logic
│ │ ├── tts.ts # TTS engine (SAN-to-spoken, caching, 5 providers)
│ │ └── treeReducer.ts # Tree data structure
│ ├── bindings/ # Auto-generated TS from Rust
│ └── translation/ # i18n (13 languages)
├── docs/ # Bundled documentation (shown in Help menu)
├── vite.config.ts # Build config
└── package.json # Frontend deps

  1. Rust भारी काम करता है — इंजन, डेटाबेस, फ़ाइल I/O, PGN पार्सिंग। React कभी सीधे फ़ाइलसिस्टम को छूता या प्रोसेस स्पॉन नहीं करता।

  2. सीमा के आर-पार टाइप सेफ्टी — Specta Rust स्ट्रक्ट्स से TypeScript टाइप्स जनरेट करता है, इसलिए अगर कोई Rust कमांड अपना सिग्नेचर बदलता है, तो TypeScript बिल्ड तुरंत टूट जाता है।

  3. दो स्टेट सिस्टम — सरल रिएक्टिव स्टेट (सेटिंग्स, UI प्रेफरेंसेज़, प्रति-टैब इंजन स्टेट) के लिए Jotai, जटिल डोमेन स्टेट (ब्रांचिंग और इम्यूटेबल अपडेट्स के साथ गेम ट्री) के लिए Zustand।

  4. TTS एक प्रीप्रोसेसिंग समस्या है — कठिन हिस्सा स्पीच API कॉल करना नहीं है, बल्कि शतरंज नोटेशन और PGN मार्कअप को कई भाषाओं में स्वच्छ, प्राकृतिक-लगने वाले टेक्स्ट में अनुवाद करना है। sanToSpoken() और cleanCommentForTTS() पाइपलाइन्स वहाँ हैं जहाँ असली काम होता है।

  5. पाँच प्रोवाइडर, एक इंटरफ़ेस — चाहे ऑडियो ElevenLabs, Google Cloud, KittenTTS, OpenTTS, या आपके OS के स्पीच इंजन से आए, ऐप का बाकी हिस्सा हमेशा केवल speakText() कॉल करता है। प्रोवाइडर चयन एक सिंगल एटम टॉगल है।

  6. बिल्ड एक सिंगल बाइनरी बनाता है src-tauri/target/release/en-parlant पर जो Rust बैकएंड + Vite-बिल्ट फ्रंटएंड एसेट्स को बंडल करती है।