Book-to-Skill Strategies for Estimating Tokens in Different Text Types
Book-to-Skill employs a dual heuristic approach that divides word counts by 0.75 for Latin text and CJK character counts by 1.5 for Asian scripts, with an optional fallback to the exact tiktoken BPE tokenizer when available.
The virgiliojr94/book-to-skill repository needs deterministic token counts to forecast API costs and manage context window limits when processing books and documents. It implements language-aware strategies for estimating tokens that avoid heavy dependencies while maintaining accuracy across different writing systems.
Heuristic-Based Estimation Strategy
Book-to-Skill categorizes text into two processing paths based on the presence of CJK (Chinese, Japanese, Korean) characters. This approach accounts for the fundamental difference in tokenization density between whitespace-delimited languages and logographic scripts.
Latin and Whitespace-Delimited Text
For text containing only Latin characters and whitespace, the system applies a deterministic word-to-token ratio. The implementation in book_to_skill/utils.py splits the text on whitespace and divides the word count by the WORDS_PER_TOKEN constant defined in book_to_skill/config.py.
Key implementation details:
- The constant
WORDS_PER_TOKEN = 0.75represents the approximate inverse of the average tokens per word in English prose - This ratio aligns with OpenAI's
cl100k_basetokenizer behavior for common Latin-script content - The function
len(text.split())provides the word count basis
CJK Character Handling
When the input contains CJK code points, Book-to-Skill switches to a character-based estimation model. The repository uses a compiled regex _CJK_RE to identify characters in the CJK Unicode blocks.
The calculation strategy:
- Each CJK character counts as approximately
1 / 1.5tokens based on theCJK_CHARS_PER_TOKEN = 1.5constant - For mixed content, the system separates Latin words (with CJK characters substituted by spaces) and adds the CJK character count separately
- This handles supplementary plane characters correctly, as validated in
tests/test_cjk_supplementary_plane.py
Optional Exact Tokenization with Tiktoken
For tooling that requires precise token counts rather than estimates, tools/discovery_tax.py provides a real BPE tokenizer implementation.
The count_tokens function attempts to import tiktoken and encode text using the cl100k_base encoding:
def count_tokens(text: str) -> int:
"""Real BPE count via tiktoken if available; else words/0.75 heuristic."""
try:
import tiktoken
enc = tiktoken.get_encoding("cl100k_base")
return len(enc.encode(text))
except Exception:
# Fallback to the deterministic heuristic
return int(len(text.split()) / WORDS_PER_TOKEN)
If the tiktoken library is not installed or the import fails, the function falls back to the standard word-count heuristic, ensuring the tool remains functional without optional dependencies.
Configuration Constants and Sources
The estimation ratios live in book_to_skill/config.py and serve as the single source of truth for both the core utilities and discovery tools:
WORDS_PER_TOKEN = 0.75— Calibrated for Latin-based textCJK_CHARS_PER_TOKEN = 1.5— Calibrated for CJK ideographic content
These constants allow users to adjust estimation aggressiveness globally without modifying the calculation logic.
Core Implementation Files
book_to_skill/utils.py
The primary estimate_tokens function implements the dual-path logic. It first checks for CJK characters using the compiled regex _CJK_RE. If none exist, it returns len(text.split()) / WORDS_PER_TOKEN. For mixed or pure CJK content, it calculates:
def estimate_tokens(text: str) -> int:
"""Estimate the token count of ``text`` with a deterministic heuristic."""
if not text:
return 0
cjk = len(_CJK_RE.findall(text))
if not cjk:
return int(len(text.split()) / WORDS_PER_TOKEN)
latin_words = len(_CJK_RE.sub(" ", text).split())
return int(latin_words / WORDS_PER_TOKEN + cjk / CJK_CHARS_PER_TOKEN)
This implementation ensures that a sentence like "Hello 世界" correctly separates the Latin word ("Hello") from the CJK characters ("世界") and applies the appropriate ratio to each segment.
tools/discovery_tax.py
This analysis script exposes the count_tokens wrapper function. It prioritizes accuracy over speed by attempting to use the actual OpenAI tokenizer when available, making it suitable for auditing the heuristic's accuracy or processing small text samples where exact counts matter.
Practical Usage Examples
Estimating Tokens for English Prose
For pure Latin text, the heuristic provides fast, battery-friendly estimates without importing heavy tokenization libraries:
from book_to_skill.utils import estimate_tokens
english = "The quick brown fox jumps over the lazy dog."
print(estimate_tokens(english)) # ≈ 13 tokens (13 words / 0.75)
Calculating CJK Content Costs
For Chinese, Japanese, or Korean content where characters dominate over whitespace, the character-based ratio prevents underestimation:
from book_to_skill.utils import estimate_tokens
chinese = "中" * 1500 # 1500 Chinese characters, no spaces
print(estimate_tokens(chinese)) # ≈ 1000 tokens (1500 / 1.5)
Using Real BPE Tokenization
When tiktoken is installed, developers can obtain exact token counts for billing reconciliation:
from tools.discovery_tax import count_tokens
mixed_text = "Hello, 世界!"
print(count_tokens(mixed_text)) # Accurate token count from tiktoken encoder
Summary
- Book-to-Skill uses a dual heuristic that applies
0.75words-per-token for Latin text and1.5characters-per-token for CJK content - Configuration constants reside in
book_to_skill/config.pyand control both estimation paths - The
estimate_tokensfunction inbook_to_skill/utils.pyhandles mixed-language content by separating Latin words from CJK characters - Optional exact counting is available through
tools/discovery_tax.pywhen thetiktokenlibrary is present - Test coverage in
tests/test_cjk_supplementary_plane.pyensures accurate handling of extended Unicode planes
Frequently Asked Questions
How accurate is the heuristic compared to OpenAI's tokenizer?
The heuristic provides estimates within 10-20% of actual cl100k_base token counts for most content. The constant values (0.75 for words, 1.5 for CJK) were chosen to match the average density observed in OpenAI's tokenizer, though exact counts require the optional tiktoken dependency.
Why does Book-to-Skill use different ratios for CJK and Latin text?
CJK characters typically consume fewer bytes per token in modern BPE tokenizers compared to Latin words. While a Latin word averages 1.3 tokens, a CJK character averages approximately 0.67 tokens. The ratios 0.75 and 1.5 represent the inverse of these densities to convert character/word counts into estimated token quantities.
What happens if tiktoken is not installed?
The system gracefully degrades to the heuristic estimator. In tools/discovery_tax.py, the count_tokens function catches import exceptions and falls back to int(len(text.split()) / WORDS_PER_TOKEN), ensuring all functionality remains available without the heavy tokenization library.
Where are the token estimation constants defined?
The constants WORDS_PER_TOKEN and CJK_CHARS_PER_TOKEN are defined in book_to_skill/config.py. Centralizing these values allows users to adjust estimation parameters globally without modifying the calculation logic in utils.py or discovery_tax.py.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →