# Japanese Furigana, JLPT Level & Counter Checker (`noisy_jubilee/japanese-text-tools`) Actor

Add furigana to Japanese text, estimate its JLPT level (N5-N1) and check counter words (猫が三個 → 三匹). Offline kuromoji/IPADIC analysis, no API key.

- **URL**: https://apify.com/noisy_jubilee/japanese-text-tools.md
- **Developed by:** [Stephen](https://apify.com/noisy_jubilee) (community)
- **Categories:** AI, Education
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.50 / 1,000 furigana results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Japanese Furigana, JLPT Level & Counter Checker

Three offline tools for Japanese text, in one Actor:

- **Furigana**: adds readings to kanji as ruby HTML (`<ruby>友達<rt>ともだち</rt></ruby>`), plus a per-token list with reading, dictionary form, part of speech and character offsets.
- **JLPT level estimate**: estimates the JLPT level (N5–N1) of a text and lists the words and kanji that are harder than your learner's target level.
- **Counter checker**: finds number + counter words (三本, 二匹, 五個…), gives their correct reading (さんぼん, にひき, ごこ) and flags a counter that doesn't fit the noun (猫が三個 → 三匹), with a corrected text.

Use it for graded readers and learning apps, checking LLM-generated Japanese, or adding furigana to a dataset of texts. Runs fully offline with the kuromoji analyzer and the IPADIC dictionary: **no API key and no calls to external services**; texts are processed inside the Actor run.

### Input

| Field | Default | Meaning |
|---|---|---|
| `texts` | (required) | List of Japanese texts (sentences or short passages) |
| `tools` | all three | Any of `furigana`, `jlptLevel`, `counters` |
| `jlptTarget` | `N4` | Learner level for `aboveTarget` (N5–N1) |
| `includeTokens` | `true` | Include the per-token list in furigana results |
| `maxCharsPerText` | 1000 | Longer texts are skipped and not charged (max 5,000) |
| `maxTexts` | 100 | Texts beyond this are skipped and not charged (max 10,000) |

Example: `{"texts": ["猫が三個いる。", "昨日、友達と三本の映画を見ました。"]}`. More in [listing/input-examples.md](listing/input-examples.md).

### Output

One dataset item per text **per tool**, with `inputIndex`, `tool`, `text` and a `credit` line.

- `furigana`: `html` (ruby markup), `tokens[]` (`surface`, `reading`, `base`, `pos`, `start`, `end`, `segments`)
- `jlptLevel`: `estimatedLevel`, `target`, `coverage[]` per level, `words[]`, `kanji[]`, `aboveTarget.words/kanji`, `stats`, `notes`
- `counters`: `ok`, `items[]` (number, counter, what it counts, correct `readings`, the noun it counts, `issues`), `issues[]`, `correctedText`

Full example output for the input above: [listing/output-example.json](listing/output-example.json).

A `SUMMARY` record in the key-value store gives counts, skipped texts and peak memory.

### Pricing (pay per event)

| Event | Price |
|---|---|
| Furigana result (one text) | $0.0005 |
| JLPT level result (one text) | $0.001 |
| Counter check result (one text) | $0.001 |
| Actor start (Apify standard, once per run) | $0.0003 |

All three tools on 1,000 texts cost $2.50 (plus $0.0003 per run). Skipped texts and failed runs are not charged. The run stops cleanly when your maximum charge per run is reached.

### Limits and accuracy (please read)

- **JLPT levels are unofficial.** The JLPT has not published word or kanji lists since 2010. Levels come from community lists (see credits) and the result is an estimate, most useful for passages of a few sentences or more. For one short sentence a single kanji can move the level (e.g. 個 is listed at N2, so 「猫が三個いる。」 grades N2).
- **Readings come from a dictionary-based analyzer** (IPADIC, 2007). It picks one reading per word by context, so rare readings, names and new words can be wrong. Proper nouns may get a common reading.
- **Counter checks cover common counters** and common noun–counter pairs. A text with no issue found is not proof that every counter is right, and unusual but valid choices may be flagged.
- Up to 5,000 characters per text. Japanese only; other languages pass through without readings.
- Memory: the dictionary needs about 300–380 MB, so the Actor runs at 512 MB (the default and the minimum). More memory does not make it faster.

### Data sources and credit

- Morphological analysis: [kuromoji.js](https://github.com/patdx/kuromoji.js) (Apache-2.0) with **mecab-ipadic 2.7.0** (© NAIST / ICOT; notice in [NOTICE-kuromoji-ipadic.md](NOTICE-kuromoji-ipadic.md)).
- JLPT vocabulary levels: [open-anki-jlpt-decks](https://github.com/jamsinclair/open-anki-jlpt-decks) (MIT, © Jamie Sinclair), based on Jonathan Waller's JLPT lists at [tanos.co.uk](http://www.tanos.co.uk/jlpt/) (CC BY).
- Kanji levels: [kanji-data](https://github.com/davidluzgouveia/kanji-data) (MIT, © David Gouveia), also from Waller's lists.
- Details and the share-alike note on the derived level file: [LICENSES.md](LICENSES.md).

### No warranty

This Actor is provided as is, without warranty of any kind. Readings, levels and counter suggestions are automatic estimates and can be wrong. Check important output (teaching material, published text) yourself. The JLPT (Japanese-Language Proficiency Test) is run by the Japan Foundation and JEES; this Actor is not affiliated with or endorsed by them.

# Actor input Schema

## `texts` (type: `array`):

One Japanese text per line or item (sentences or short passages). Each text is processed by every selected tool.

## `tools` (type: `array`):

Which tools to run on each text. Each (text, tool) pair is one result and one charge. Default: all three.

## `jlptTarget` (type: `string`):

Words and kanji harder than this level are listed in aboveTarget.

## `includeTokens` (type: `boolean`):

Include the per-token list (reading, dictionary form, part of speech, offsets). Turn off for smaller output with just the ruby HTML.

## `maxCharsPerText` (type: `integer`):

Longer texts are skipped (not charged). Up to 5,000.

## `maxTexts` (type: `integer`):

Texts beyond this number are skipped (not charged). Up to 10,000.

## Actor input object example

```json
{
  "texts": [
    "猫が三個いる。",
    "昨日、友達と三本の映画を見ました。"
  ],
  "tools": [
    "furigana",
    "jlptLevel",
    "counters"
  ],
  "jlptTarget": "N4",
  "includeTokens": true,
  "maxCharsPerText": 1000,
  "maxTexts": 100
}
```

# Actor output Schema

## `results` (type: `string`):

One row per input text and tool (furigana, jlpt-level, counter-check).

## `summary` (type: `string`):

SUMMARY record in the default key-value store: counts, charges and status of the run.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "texts": [
        "猫が三個いる。",
        "昨日、友達と三本の映画を見ました。"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("noisy_jubilee/japanese-text-tools").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "texts": [
        "猫が三個いる。",
        "昨日、友達と三本の映画を見ました。",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("noisy_jubilee/japanese-text-tools").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "texts": [
    "猫が三個いる。",
    "昨日、友達と三本の映画を見ました。"
  ]
}' |
apify call noisy_jubilee/japanese-text-tools --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,noisy_jubilee/japanese-text-tools"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/EBcuiCc4nbVvKCLnN/builds/j71YxRjTdVuOOeaDB/openapi.json
