An open API service indexing awesome lists of open source software.

https://github.com/fodydev/afrim-py

afrim-py is a python bindings for library, helping to build input method applications using python.
https://github.com/fodydev/afrim-py

afrim ime python typing

Last synced: 5 months ago
JSON representation

afrim-py is a python bindings for library, helping to build input method applications using python.

Awesome Lists containing this project

README

          

afrim-py

Python bindings for the afrim ime engine.


Python
Rust
License
Changelog


Repository

Built with πŸ¦€πŸ by @esubaalew

## About

`afrim-py` provides Python bindings for the powerful afrim input method engine, enabling developers to build sophisticated input method applications in Python. This project brings the capabilities of the Rust-based afrim engine to the Python ecosystem through PyO3 bindings.

## πŸ”‹ Features Included

* **Preprocessor** - Advanced key sequence processing and input transformation
* **Translator** - Dictionary-based text translation with multiple candidates
* **TOML Support** - Easy configuration through TOML files
* **Unicode Support** - Full support for international characters
* **Rhai Scripting** - Dynamic translation scripts (when `rhai` feature is enabled)
* **String Similarity** - Fuzzy matching with `strsim` feature

## Installation

`afrim-py` is available on pypi.

```bash
pip install afrim-py
```

## Usage

### Basic Example

```python
from afrim_py import Preprocessor, Translator, Config

# Configure the preprocessor with key mappings
preprocessor_data = {
"a1": "Γ ",
"e1": "Γ©",
"u1": "ΓΉ",
"hello": "hi"
}

# Configure the translator with dictionary
translator_dict = {
"hello": ["hi", "hey", "greetings"],
"world": ["earth", "globe", "planet"],
"python": ["snake", "programming language"]
}

# Create instances
preprocessor = Preprocessor(preprocessor_data, buffer_size=64)
translator = Translator(translator_dict, auto_commit=True)

# Process keyboard events
changed = preprocessor.process("h", "keydown")
changed = preprocessor.process("e", "keydown")
changed = preprocessor.process("l", "keydown")
changed = preprocessor.process("l", "keydown")
changed = preprocessor.process("o", "keydown")

# Get the processed input
current_input = preprocessor.get_input() # "hello"

# Translate the input
translations = translator.translate(current_input)
print(translations)
# [{'texts': ['hi', 'hey', 'greetings'], 'code': 'hello', 'remaining_code': '', 'can_commit': True}]

# Process commands from the queue
while True:
command = preprocessor.pop_queue()
if command == "NOP":
break
print(f"Command: {command}")
```

### Configuration

```python
from afrim_py import Config
import json

# Configuration file `config.toml`
'''
[core]
buffer_size = 64
auto_capitalize = false
auto_commit = false
page_size = 10

[data]
a1 = "Γ "
e2 = "Γ©"

[translators]
datetime = { path = "./scripts/datetime.toml" }

[translation]
hi = 'hello'
'''
config = Config('config.toml')

# Use the configuration
preprocessor_data = config.extract_data()
preprocessor = Preprocessor(preprocessor_data, 64)
translator_dict = config.extract_translation()
translator = Translator(translator_dict, True)
```

### Advanced Usage with Command Processing

```python
import asyncio
from afrim_py import Preprocessor, Translator, Config

class InputMethodEngine:
def __init__(self, config_file: str):
config = Config(config_file)
self.preprocessor = Preprocessor(config.extract_data(), 64)
self.translator = Translator(config.extract_translation(), True)
self.running = False

async def process_commands(self):
"""Process commands from the preprocessor queue"""
while self.running:
command = self.preprocessor.pop_queue()

if command == "NOP":
await asyncio.sleep(0.01) # Small delay
continue

# Handle different command types
if isinstance(command, dict):
if "Insert" in command:
text = command["Insert"]["text"]
print(f"Insert: {text}")
elif "Delete" in command:
count = command["Delete"]["count"]
print(f"Delete: {count} characters")
else:
print(f"Command: {command}")

def handle_key_event(self, key, state="keydown"):
"""Handle keyboard events"""
changed = self.preprocessor.process(key, state)

if changed:
current_input = self.preprocessor.get_input()
if current_input:
translations = self.translator.translate(current_input)
return translations
return []

def commit_text(self, text):
"""Commit selected text"""
self.preprocessor.commit(text)

async def start(self):
"""Start the input method engine"""
self.running = True
await self.process_commands()

def stop(self):
"""Stop the input method engine"""
self.running = False

# Usage
async def main():
ime = InputMethodEngine(
preprocessor_data={"A": "α‹•", "Aa": "α‹“", "C": "ጭ"},
translator_dict={"Atarah": ["α‹“αŒ£αˆ«"], "Adiel": ["α‹“α‹²α‹”αˆ"]}
)

# Simulate key events
translations = ime.handle_key_event("A")
translations = ime.handle_key_event("a")
translations = ime.handle_key_event("C")

print("Translations:", translations)

# Commit text
if translations:
ime.commit_text(translations[0]["texts"][0])

# Run the example
# asyncio.run(main())
```

## Development

### Build requirements

- Rust 1.70+
- Cargo

- Python 3.8+ and and [maturin](https://www.maturin.rs/installation.html)
- [uv](https://docs.astral.sh/uv/getting-started/installation/) *(optional)*

### Build from source

To simplify the development, we recommend to use `uv`.

**Using maturin**

```bash
# Clone the repository
git clone https://github.com/fodydev/afrim-py.git
cd afrim-py

# Create virtual environment
python -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate

# Development build
maturin develop

# Release build
maturin build --release

# Build wheel
maturin build --interpreter python
```

**Using uv**

```bash
# Clone the repository
git clone https://github.com/fodydev/afrim-py.git
cd afrim-py

# Prerelease build
uv build --prerelease

# Release build
uv build
```

### Testing

The project includes tests that represent a real user scenario:

```bash
# Run all tests
python -m pytest tests/ -v
```

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

## Acknowledgments

- **[afrim-js](https://github.com/pythonbrad/afrim-js)** - Web bindings that inspired this project

## License

Licensed under the [MIT LICENSE](LICENSE).