Skip to main content

A simple Input Method Engine, inspired by Rime.

Project description

pinyinIME

Know how to solve every problem that has been solved. -- Feynman

A simple Pinyin Input Method Engine, inspired by Rime.

Pure Python implementation, with no dependencies on any third-party libraries.

The current codebase is 700+ lines, with efforts underway to reduce it to under 500 lines.

It is the Chinese input method I currently use in my daily life.

Features

  • Full pinyin & abbreviationnihao → 你好;nh → 你好(声母缩写)

  • Manual syllable separation(configurable)xi'an → 西安; ke'neng → 可能

  • User learning — records your word choices and promotes them in future lookups

  • Custom phrases — add your own words via ~/.config/pinyinIME/custom_phrase.txt

  • Emoji input — type Chinese keywords to get emoji candidates

  • Traditional Chinese — optional simplified → traditional conversion

  • Python API — embed the engine directly in your own Python app

  • HTTP server — local HTTP daemon for integration with native input method frameworks (e.g. macOS IMKit / Swift)

  • Interactive terminal UI — optional TUI for trying the IME in your terminal (connects to the HTTP server)

Installation

pip install pinyinIME

Or with uv:

uv tool install pinyinIME

To enable traditional Chinese output, install with the optional dependency:

pip install "pinyinIME[traditional]"

Python API

from pinyinIME import PinyinEngine

engine = PinyinEngine.default()

# Get candidate words (page=0, page_size=9)
engine.query("nihao", 0, 9)
# {
#   "syllables": ["ni", "hao"],
#   "candidates": [{"word": "你好", "syllables": ["ni", "hao"]}, ...],
#   "max_page": 20
# }

# Get candidates with full pinyin and frequency score
engine.lookup("nh")
# [('你好', 'ni hao', 135314), ('那好', 'na hao', 812), ...]

# FMM syllable segmentation
engine.segment("nihao")      # ['ni', 'hao']

# Record a user selection (triggers learning)
engine.commit("你好", ["ni", "hao"])

CLI Usage

# Look up candidates for a pinyin string
pinyinIME lookup nihao
pinyinIME lookup nh           # abbreviation: 声母缩写
pinyinIME lookup "xi'an"      # manual syllable split → 西安

# Open debug playground in browser (requires server running)
uv run --with bottle pinyinIME serve   # start HTTP server first
pinyinIME playground                   # then open playground in browser

# Clear disk index cache
pinyinIME clear-cache

# Enable debug logging
pinyinIME --verbose lookup nihao

# Interactive terminal UI (requires bottle + rich; start server first)
uv run --with bottle pinyinIME serve                              # start HTTP server (default 127.0.0.1:12358)
uv run --with bottle pinyinIME serve --no-user-history            # disable user history
uv run --with bottle pinyinIME serve --no-custom-phrases          # disable custom phrases
uv run --with rich pinyinIME interactive     # then launch interactive UI

Configuration

User data is stored in ~/.config/pinyinIME/:

File Purpose
custom_phrase.txt Custom words, one per line, loaded at startup
pinyin.userdb User selection history (plain text log)
config.json Engine config (see defaults below)

Default config.json

{
  "engine": {
    "segment_delimiter": "'",
    "top_n": 10,
    "max_abbrev_fanout": 10,
    "search_timeout": 0.5
  },
  "log": {
    "level": "INFO"
  }
}

Custom Phrases

Add your own words to ~/.config/pinyinIME/custom_phrase.txt, one word per line:

# 每行一个词条,格式:词[, 音节][, 权重](后两项可选)
一丹中心
阅读场
π, pi, 100

艾伦·凯, ai lun kai
动态媒介

Pinyin is auto-annotated from the built-in character dictionary.

Development

git clone https://github.com/wwj718/pinyinIME.git
cd pinyinIME

# Install in editable mode (changes take effect immediately)
uv tool install --editable .

# Run tests
uv run pytest

# Full QA (format, lint, type check, test)
just qa

Architecture Overview

PinyinEngine
├── index/
│   ├── dict_loader.py           Dictionary data (luna_pinyin.dict.yaml)
│   ├── essay_loader.py          Word frequency data (essay.txt)
│   ├── custom_phrase_loader.py  User custom phrases (~/.config/pinyinIME/custom_phrase.txt)
│   ├── emoji_loader.py          Emoji entries
│   ├── builder.py               IndexBuilder → (Prism, Table); PhraseAnnotator
│   ├── prism.py                 Spelling → [(syllable_id, SpellingType)]
│   └── table.py                 Trie: syllable_id[] → DictEntry[] (sorted by score)
├── pipeline/
│   ├── types.py        SpellingType enum, SPELLING_PENALTY constants
│   ├── segmentor.py    FmmStrategy; SegmentationStrategy Protocol
│   ├── translator.py   Querier: DFS over segments, Prism+Table lookup, timeout protection
│   └── filter.py       Filter Protocol; DeduplicateFilter; TraditionalFilter (simp→trad)
├── userdata/
│   ├── user_paths.py   Config dir & file path management
│   └── user_history.py UserHistory: plain-text frequency log (pinyin.userdb)
├── server.py           HTTP daemon (bottle); exposes query/commit/segment API
├── interactive.py      Interactive terminal UI (HTTP client mode)
└── utils.py            Logging format constants

Scoring

Candidates are ranked by an adjusted score:

adjusted_score = round((log(max(raw_score, 1)) + spelling_penalty) × 1_000_000)

Weight multipliers before the log:

Source Multiplier
User history 10,000,000
Custom phrases 1,000,0 * (1-100)
Emoji 1,000
Essay (Rime) base 1

Spelling penalties: NORMAL → 0.0, ABBREVIATION → log(0.1) ≈ −2.303

Author

pinyinIME was created in 2026 by Wenjie Wu.

Built with the cookiecutter-pypackage project template.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pinyinime-0.1.11-py3-none-any.whl (3.1 MB view details)

Uploaded Python 3

File details

Details for the file pinyinime-0.1.11-py3-none-any.whl.

File metadata

  • Download URL: pinyinime-0.1.11-py3-none-any.whl
  • Upload date:
  • Size: 3.1 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.13

File hashes

Hashes for pinyinime-0.1.11-py3-none-any.whl
Algorithm Hash digest
SHA256 d6f7689606fbf89226442d9fc179437efe550298e14007c57e6e3c8c7481498a
MD5 e372c9d572ca32c42d38654268a66da1
BLAKE2b-256 0bba22f3f0c2e330c7559d4e676a8ab2e730dac1c733f6d952a8fbfdb84cc887

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page