Metadata-Version: 2.4
Name: pinyinIME
Version: 0.1.12
Summary: A simple Input Method Engine, inspired by Rime.
Project-URL: bugs, https://github.com/wwj718/pinyinIME/issues
Project-URL: changelog, https://github.com/wwj718/pinyinIME/blob/main/HISTORY.md
Project-URL: documentation, https://wwj718.github.io/pinyinIME/
Project-URL: homepage, https://github.com/wwj718/pinyinIME
Author-email: Wenjie Wu <wuwenjie718@gmail.com>
Maintainer-email: Wenjie Wu <wuwenjie718@gmail.com>
License: MIT
License-File: LICENSE
Classifier: Typing :: Typed
Requires-Python: >=3.10
Provides-Extra: traditional
Requires-Dist: opencc>=1.2.0; extra == 'traditional'
Description-Content-Type: text/markdown

# pinyinIME

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

A simple Pinyin Input Method Engine, inspired by [Rime](https://rime.im/).

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.

* Author: [Wenjie Wu](https://wwj718.github.io)
* PyPI: https://pypi.org/project/pinyinIME/
* Free software: MIT License

## Features

* **Full pinyin & abbreviation** — `nihao` → 你好；`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

```bash
pip install pinyinIME
```

Or with [uv](https://github.com/astral-sh/uv):

```bash
uv tool install pinyinIME
```

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

```bash
pip install "pinyinIME[traditional]"
```



## Python API

```python
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

```bash
# 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`

```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

```bash
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](https://wwj718.github.io).

Built with the [cookiecutter-pypackage](https://github.com/audreyfeldroy/cookiecutter-pypackage) project template.

