Skills Artificial Intelligence Japanese NLP Resource Comparison

Japanese NLP Resource Comparison

v20260916
compare
Compare multiple Japanese NLP libraries, models, or datasets across user-selected criteria, rendered as a clear table with ratings. Ideal for choosing between alternatives like MeCab vs Sudachi, or evaluating tools for tasks such as morphological analysis, embeddings, or OCR.
Get Skill
321 downloads
Overview

Compare Japanese NLP resources for: "$ARGUMENTS" across a few criteria, as a table.

Instructions

Step 0 — Validate input

If $ARGUMENTS is empty or blank, stop immediately and output:

Usage: /awesome-japanese-nlp-resources:compare <tool-name | topic>

Examples:
  /awesome-japanese-nlp-resources:compare mecab
  /awesome-japanese-nlp-resources:compare 形態素解析
  /awesome-japanese-nlp-resources:compare japanese sentence embedding models
  /awesome-japanese-nlp-resources:compare OCR

Pass a tool name (to compare it against its closest alternatives) or a topic/function (to compare the leading options for that task).

---

使い方: /awesome-japanese-nlp-resources:compare <ツール名 | トピック>

例:
  /awesome-japanese-nlp-resources:compare mecab
  /awesome-japanese-nlp-resources:compare 形態素解析
  /awesome-japanese-nlp-resources:compare 日本語 文埋め込み モデル
  /awesome-japanese-nlp-resources:compare OCR

比較したいツール名(その代替と比較)、またはトピック/機能名(その分野の主要な選択肢を比較)を引数に指定してください。

Do not proceed if $ARGUMENTS is empty. Unlike discover, this skill has no empty-argument default — a comparison needs something to compare.

Step 1 — Classify the input: seed mode or topic mode

$ARGUMENTS is: "$ARGUMENTS"

Seed mode — names ONE specific existing tool/library/model (a full GitHub/Hugging Face URL, owner/repo, or a bare tool name, e.g. mecab, fugashi). Pass it through as SEED and proceed to Step 3 in seed mode — the comparison set will be the seed plus its closest peers.

Topic mode — a descriptive/functional phrase with no single specific name (e.g. 形態素解析, japanese sentence embedding models, OCR). Proceed to Step 3 in topic mode — the comparison set will be the leading local matches for the topic.

Step 2 — Locate the data file

RESOURCES_PATH="${CLAUDE_PLUGIN_ROOT}/data/resources.json"
[ -f "$RESOURCES_PATH" ] || RESOURCES_PATH="$(find "${HOME}/.claude/plugins" -type f -name resources.json 2>/dev/null | grep "awesome-japanese-nlp-resources/" | head -1)"
echo "RESOURCES_PATH=$RESOURCES_PATH"

Step 3 — Find comparison candidates (inline Python)

Do NOT use the Read tool on resources.json. Run one of the two scripts below, substituting RESOURCES_PATH (Step 2) and, for seed mode, SEED (from Step 1).

Seed mode — locate the seed and score peers by shared category, shared semantic labels, and shared description tokens (IDF-weighted):

python3 << 'EOF'
import json, re, math
from collections import Counter

RESOURCES_PATH = "RESOURCES_PATH"   # from Step 2
SEED_RAW       = "SEED"             # from Step 1

with open(RESOURCES_PATH) as f:
    data = json.load(f)
N = len(data)

STOP = {
    "the","and","for","with","that","this","from","into","your","you","are","was",
    "japanese","nlp","python","library","tool","tools","text","based","using","use",
    "used","language","data","model","models","repository","repo","support","simple",
    "fast","easy","also","can","via","etc","https","http","github","com","www","org",
    "not","but","all","any","other","such","more","most","than","its","each","which",
}

def norm_url(u): return (u or "").lower().rstrip("/")
def subs_of(it): return set(t.strip().lower() for t in (it.get("s") or []))
def family(c):   return (c or "").split("(")[0].strip().lower()
def toks(text):
    return set(w for w in re.findall(r"[a-z0-9]+", (text or "").lower())
               if len(w) >= 4 and w not in STOP)

seed = SEED_RAW.strip().lower().rstrip("/")
gh_m = re.search(r"github\.com/([^/#?]+/[^/#?]+)", seed)
hf_m = re.search(r"huggingface\.co/(?:datasets/)?([^/#?]+/[^/#?]+)", seed)
slug = (gh_m or hf_m).group(1) if (gh_m or hf_m) else (seed if seed.count("/") == 1 else None)
basename = seed.split("/")[-1]

def find_matches():
    exact = [x for x in data if norm_url(x["u"]) == seed]
    if exact: return exact, "exact URL"
    if slug:
        sm = [x for x in data if norm_url(x["u"]).endswith("/" + slug)]
        if sm: return sm, "owner/repo"
        return [], None
    nm = [x for x in data if x["n"].lower() == basename]
    if nm: return nm, "name"
    loose = [x for x in data if basename and (basename in x["n"].lower() or ("/" + basename) in norm_url(x["u"]))]
    if loose: return loose, "loose substring"
    return [], None

matches, how = find_matches()
matches.sort(key=lambda x: -(max(x.get("ns") or 0, x.get("nd") or 0)))
seed_item = matches[0] if matches else None

if not seed_item:
    print("SEED_NOT_FOUND")
    raise SystemExit

print(f"SEED_FOUND via {how}: {seed_item['n']}")
print(f"  url={seed_item['u']}  c={seed_item['c']}")
print(f"  d={seed_item.get('d','')[:200]}")
print()

sub_df, tok_df = Counter(), Counter()
for x in data:
    for s in subs_of(x): sub_df[s] += 1
    for t in toks((x.get("d") or "") + " " + x["n"] + " " + " ".join(x.get("s") or [])): tok_df[t] += 1
def idf_sub(l): return max(0.0, math.log(N / sub_df.get(l, 1)) - 1.5)
def idf_tok(t): return max(0.0, math.log(N / tok_df.get(t, 1)) - 1.5)

seed_cat  = seed_item["c"]; seed_fam = family(seed_cat)
seed_subs = subs_of(seed_item)
seed_tok  = toks((seed_item.get("d") or "") + " " + seed_item["n"] + " " + " ".join(seed_item.get("s") or []))
seed_name = seed_item["n"].lower()
seed_urls = {norm_url(seed_item["u"])} | {norm_url(x["u"]) for x in matches if x["n"].lower() == seed_name}

results = []
for x in data:
    if x.get("status") == "not_found" or norm_url(x["u"]) in seed_urls:
        continue
    score = 0.0
    if x["c"] == seed_cat:            score += 10
    elif family(x["c"]) == seed_fam:  score += 5
    sh_subs = seed_subs & subs_of(x)
    score += 3.0 * sum(idf_sub(l) for l in sh_subs)
    sh_tok = seed_tok & toks((x.get("d") or "") + " " + x["n"] + " " + " ".join(x.get("s") or []))
    score += 1.5 * sum(idf_tok(t) for t in sh_tok)
    if score < 8.0:
        continue
    pop = max(x.get("ns") or 0, x.get("nd") or 0)
    results.append((score + 0.5 * pop, x))

results.sort(key=lambda r: -r[0])
print(f"=== CANDIDATES ({len(results)} peers found; seed + top 6 shown) ===")
print(f"[seed] n={seed_item['n']}  u={seed_item['u']}  c={seed_item['c']}  d={seed_item.get('d','')[:150]}")
for score, x in results[:6]:
    print(f"score={score:.1f}  n={x['n']}  u={x['u']}  c={x['c']}  d={x.get('d','')[:150]}")
EOF

Topic mode — score by keyword match (3–5 stems from Step 1, same conventions as search):

python3 << 'EOF'
import json

with open("RESOURCES_PATH") as f:    # from Step 2
    data = json.load(f)

keywords = ["keyword1", "keyword2", "keyword3"]  # short stems, from Step 1

results = []
for item in data:
    if item.get("status") == "not_found":
        continue
    n = item.get("n", "").lower(); d = item.get("d", "").lower()
    s = " ".join(item.get("s") or []).lower(); c = item.get("c", "").lower()
    al = " ".join(item.get("al") or []).lower()
    text_score = 0
    for kw in keywords:
        kw = kw.lower()
        if n == kw:       text_score += 20
        elif kw in n:     text_score += 10
        if kw in d:       text_score += 5
        if kw in s:       text_score += 3
        if kw in c:       text_score += 2
        if kw in al:      text_score += 10
    if text_score < 8:
        continue
    ns = item.get("ns") or 0; nd = item.get("nd") or 0
    results.append((text_score + max(ns, nd) * 2.5, item))

results.sort(key=lambda x: -x[0])
print(f"=== CANDIDATES ({len(results)} matches; top 6 shown) ===")
for combined, item in results[:6]:
    print(f"score={combined:.1f}  n={item['n']}  u={item['u']}  c={item['c']}  d={item.get('d','')[:150]}")
EOF

Step 4 — Select the comparison set

From Step 3's output, pick 3–6 candidates for the table:

  • Seed mode: the seed itself plus its 2–5 closest peers (drop peers that don't actually do a comparable job, even if they scored).
  • Topic mode: the top 3–6 matches, preferring ones that are genuinely distinct approaches rather than near-duplicates (e.g. don't list mecab and 3 thin wrappers around mecab as if they were independent options — pick the one or two that matter, plus other real alternatives).

If fewer than 3 solid local candidates exist, run 2–3 WebSearch queries (<topic-en> japanese library, japanese <topic-en> alternatives, <topic-en> japanese huggingface) to find 1–3 more well-known options. You don't need to filter these against the dataset the way discover does — the goal here is just enough real, comparable candidates for a meaningful table, not a completeness audit.

If, even after this, fewer than 2 comparable resources exist, stop and say so — a 1-row table isn't a comparison. Suggest /awesome-japanese-nlp-resources:search "$ARGUMENTS" instead.

Step 5 — Choose comparison axes

Pick 3–5 axes that a practitioner would actually use to decide between these specific candidates — do not reuse a generic checklist. Good axes:

  • Actually differ across the candidates (an axis where every row is the same is not useful — drop it).
  • Are concrete and checkable, not vague ("license" or "supports custom dictionaries", not "good" or "quality").
  • Are relevant to the domain. Examples of the kind of axis to look for (not a fixed list — invent axes suited to the actual topic):
    • Libraries/tools: speed, ease of installation/setup, customization (e.g. custom dictionaries, fine-tuning support), language/platform coverage, license permissiveness, active maintenance
    • Models: parameter count / resource requirements, context length, license permissiveness, Japanese-specific tuning vs. multilingual, benchmark performance if known
    • Datasets: size, license/commercial-use permissiveness, annotation quality/type, domain coverage, whether it's still actively updated

Step 6 — Rate each candidate

For each candidate × axis, decide:

  • — clearly supports / strong on this axis
  • — partial support, average, or a notable caveat
  • — does not support / weak on this axis

Ground every rating in evidence:

  • Start from the dataset's d/d_ja/s/st/lc fields as a first signal.
  • WebFetch each candidate's page (repo README or model card) whenever a rating would otherwise be a guess — required for any claim about license, specific feature support, or benchmark numbers you are not already confident about from well-established knowledge. Cap at 6 WebFetch calls (one per candidate), issued in parallel where possible.
    WebFetch url="https://github.com/<owner>/<repo>" prompt="Extract as JSON: license, key features relevant to <the chosen axes>, install/setup complexity, and any explicit limitations mentioned. If a field is unavailable, set it to null."
    
  • For extremely well-known tools/axes where you have high confidence without fetching (e.g. "MeCab is written in C++ and is fast" is common knowledge), it's fine to skip the fetch — but say so is not required per-cell; just don't invent a rating you aren't reasonably confident in. When genuinely uncertain, rate rather than guessing ○ or ✕.

Step 7 — Format the output

Language detection rule:

  • $ARGUMENTS contains Japanese characters (hiragana / katakana / kanji) → Japanese
  • Otherwise → English (default)
## Comparison: "$ARGUMENTS"

| Resource | <Axis 1> | <Axis 2> | <Axis 3> | <Axis 4> |
|---|---|---|---|---|
| [name](url) | ○ | △ | ○ | ✕ |
| [name](url) | ○ | ○ | △ | ○ |

○ = clearly supports / strong · △ = partial or unverified · ✕ = does not support / weak

**Notes:**
- [name]: one-line justification for any △ or ✕ rating that isn't self-evident.
- [name]: ...

**Recommendation:**
- If <priority A> matters most: [name](url) — why.
- If <priority B> matters most: [name](url) — why.

Sources (if WebFetch/WebSearch used):
- [Title](https://...)

Japanese output template: mirror the structure with ## 比較: "$ARGUMENTS", **注記:**, **おすすめ:**, keeping the ○/△/✕ symbols and legend as-is (they're already language-neutral).

Rules:

  • 3–6 rows, 3–5 columns — this is meant to be scannable at a glance, not exhaustive. If you have more good candidates than fit, keep the most relevant/popular ones and mention in a closing line that others exist (pointing to /awesome-japanese-nlp-resources:search or /awesome-japanese-nlp-resources:discover).
  • Every non-obvious △/✕ needs a one-line reason in Notes — a bare symbol with no justification is not trustworthy.
  • Don't pad the table with an axis just to hit a target column count; 3 solid axes beat 5 where two are filler.
  • If WebFetch was used, Sources: is mandatory.
Info
Name compare
Version v20260916
Size 13.5KB
Updated At 2026-09-17
Language