|
This version is still in development and is not considered stable yet. For the latest stable version, please use dengjen-tashkeel 3.x! |
Architecture
This page shows dengjen-tashkeel’s own structure as a C4 Container, Component, and Code diagram. For how it fits into the wider ZirekHQ speech stack, see the org-wide System Context diagram. No source code in this repository references dengjen-nvda, dengjen-tts, or dengjen-piper-rs — as far as this codebase shows, it’s a standalone tool. (dengjen-tts optionally depends on it, feature-gated, from its side; that’s a reference the other way, not from here.)
Container
The same core inference logic is exposed through three frontends: a CLI, a C ABI, and a Python package. Java bindings load that same C ABI directly rather than being a separate frontend, and dengjen-tts consumes the Rust crate directly via Cargo (optional, feature-gated) rather than through any of these frontends.
C4Container
Person(caller, "Caller", "A CLI user, another process, or a bound language")
System_Boundary(tashkeel, "dengjen-tashkeel") {
Container(cli, "CLI", "Rust binary (crates/cli)")
Container(capi, "C ABI", "Shared library (crates/capi, ffi_support)", "Packaged for GitHub Releases and a self-hosted vcpkg registry")
Container(pyext, "dengjen-tashkeel-py", "Python extension (PyO3)", "Published to PyPI")
Container(core, "Core", "Rust library (crates/core)", "ONNX-based inference -- see Component diagram")
}
Container_Ext(java, "Java bindings", "bindings/java (separate Gradle project)", "Loads the C ABI's native library directly (JDK Foreign Function & Memory API)")
System_Ext(dengjentts, "dengjen-tts", "Optionally links this crate for Arabic phonemization (feature-gated)")
Rel(caller, cli, "Invokes")
Rel(cli, core, "Uses")
Rel(capi, core, "Uses")
Rel(pyext, core, "Uses")
Rel(java, capi, "Loads native library")
Rel(dengjentts, core, "Depends on (Cargo, optional feature)")
Component
do_tashkeel() segments input text into sentences, then runs each sentence
through a pluggable inference engine — currently only implemented for ONNX
Runtime, but factored so other backends could be added.
C4Component
Container_Boundary(core, "crates/core") {
Component(libpub, "lib.rs", "Rust module", "Public API: do_tashkeel(); segments text via libtqsm, then runs per-sentence inference")
Component(backendmod, "backend/mod.rs", "Rust module", "create_inference_engine() factory; DynamicInferenceEngine wrapper")
Component(ort, "backend/ort.rs", "Rust module", "OrtEngine -- the concrete ONNX Runtime backend")
Component(pool, "backend/ort/session_pool.rs", "Rust module", "SessionPool -- bounded pool of ONNX Runtime sessions")
}
Rel(libpub, backendmod, "Obtains an engine from")
Rel(backendmod, ort, "Constructs")
Rel(ort, pool, "Checks sessions out of")
Code
DynamicInferenceEngine is a thin decorator around a boxed trait object — it exists purely so callers depend on one concrete type instead of a raw
Box<dyn InferenceEngine> everywhere. OrtEngine is the only real
implementor today, and wraps a SessionPool of ONNX Runtime sessions: each call checks a
session out of the bounded pool, so concurrent callers run on separate sessions.
classDiagram
class InferenceEngine {
<<trait>>
+infer(input_ids, diac_ids, seq_length) InferResult
+infer_batch(batch) Vec~InferResult~
}
class DynamicInferenceEngine {
-0: Box~InferenceEngine~
}
class OrtEngine {
-0: SessionPool~Session~
}
InferenceEngine <|.. DynamicInferenceEngine
InferenceEngine <|.. OrtEngine
DynamicInferenceEngine o-- InferenceEngine : delegates to
Decisions
Lockstep versioning (kept)
All 4 workspace crates (core, capi, cli, python) share one version
via version.workspace = true in the root Cargo.toml. The alternative — independent per-crate semver — was considered and rejected for now:
-
The release pipeline (
scripts/next-version.sh,scripts/bump-version.sh,release.yaml, and everypublish-*.yaml) derives one version from conventional-commit subjects and publishes crates.io, PyPI, Maven Central, and a GitHub Release from that single tag. Independent versioning means rewriting that whole chain for per-crate commit ranges and per-crate tags. -
All 4 crates change at a similar rate (no crate is being needlessly dragged along by unrelated churn in the others).
Revisit this if the workspace grows past roughly 8 crates, or a specific crate’s forced-republish churn becomes a measured release-cadence problem.