Skip to main content

soramimic

空耳(替え歌)歌詞を自動生成する Soramimic エンジンの Python ライブラリです。 本体( soramimic/soramimic の frontend/src/lib )の挙動互換移植で、同じ入力・同じ単語リストから本体と同じ空耳を生成します。

開発中(0.x)。API は変わる可能性があります。

インストール

pip install soramimic          # コア(トークナイザなし)
pip install "soramimic[mecab]" # fugashi + ipadic トークナイザ込み

使い方

from soramimic import create_soramimic, load_default_data
from soramimic.tokenizers.mecab import MeCabTokenizer  # 要 soramimic[mecab]

tok = MeCabTokenizer()
app = create_soramimic(
    **load_default_data(),  # 同梱の辞書データ(漢字読み・英語カナ・音類似度など)
    tokenize_sentenses=tok.tokenize,
    get_yomi=tok.get_yomi,
)

# 単語リスト: tidy CSV (soramimic-wordlists 形式) または1行1語のプレーンテキスト。
# 試しやすいようにサンプル(nations=国名, sekitsui=脊椎動物, stations=駅名)を同梱している
from soramimic import load_sample_wordlist

db = app.word_list.parse_tidy(load_sample_wordlist("nations"), "")  # 第2引数はwhere式

results = app.soramimi_maker.generate(["夜の街を駆け抜ける"], db, {})
for line in results:
    print(" / ".join(w["surface"] for w in line))
# => ヨルダン / マリ / オマーン / ペルー / ペルー

自前の単語リストを使う場合は同形式のCSVテキストを parse_tidy に渡します。 同梱サンプルは権利上の配慮から事実データ(国名・生物名・駅名)のみです。

トークナイザは差し替え可能です( soramimic.tokenizer.Tokenizer プロトコル参照)。 kuromoji.js 互換のトークン dict( surface_form / pronunciation / pos …、未知語は "*" )を返せば何でも使えます。 事前にトークナイズ済みの入力からは generate_from_tokens() で生成できます(固定区間 locks による部分再生成にも対応)。

変換しきれない部分(filler)

単語リストが足りない( DUPLICATE: False で使い切った)・どの単語も合わない区間があると、 その区間は元歌詞のかながそのまま1ユニットずつ残ります(#128)。この仮想語を filler と呼び、 結果の単語 dict は filler: True を持ち、 id を持ちません( surface / pronunciation / kana / originalkana はいずれも元のかな、 original は空文字)。 「候補が無いので行が丸ごと空になる」ことはありません。

for line in results:
    print(" / ".join(("[" + w["surface"] + "]") if w.get("filler") else w["surface"] for w in line))

filler は使用済み(単語重複なし)の判定に入らないので何度でも現れます。コストは soramimic.maker.FILLER_COST (1e6)で、実単語が1つでも置ける区間では必ず負けます (=単語が足りている場合の結果は従来と完全に同一)。

soramimic.com 現行版と同じ設定で生成する

本体フロントエンドは monophone タイブレーク行列(#102)と新パラメータ ( MID_PHRASE_BREAK_PENALTY #98 / VARIATION_COST #105 )を使います。 同じ経路は次のように組みます( r は「音の合わせ方」= vowelRatio、既定 0.8 ):

from soramimic import create_soramimic, load_default_data, scale_similarity

r = 0.8
data = load_default_data(similarity="monotie")
app = create_soramimic(
    **{**data,
       "vowel_similarity": scale_similarity(data["vowel_similarity"], 2 * r),
       "consonant_similarity": scale_similarity(data["consonant_similarity"], 2 * (1 - r))},
    tokenize_sentenses=tok.tokenize,
    get_yomi=tok.get_yomi,
)
# 本体「バランス」プリセット相当のパラメータ
param = {"SAME_PHRASE_BREAK_REWARD": 0, "MID_PHRASE_BREAK_PENALTY": 20,
         "WORD_NUMBER_PENALTY": 20, "VARIATION_COST": 20 * r}

ユニット位置別の重み付けで合わせる音を優先する

generate / generate_from_tokens の省略可能な weights_per_line に、行ごとの 「音節ユニット位置別の重み」(非負float、長さはその行の音節ユニット数)を渡すと、 その位置の音の一致を重く見て単語を選びます。長い音符の音を優先して合わせたい、 といった用途向けです。省略時(None)は従来と完全に同一の動作です。

# 1行目の先頭2ユニット(=長い音符)を重く、残りは軽く
results = app.soramimi_maker.generate_from_tokens(
    tokens_list, db, param, weights_per_line=[[3, 3, 1, 1, 1]]
)

重みは行ごとに平均1へ正規化されます(w_i * n / sum(w))。単語数ペナルティや 文節境界の報酬/ペナルティのような「位置を持たない定数項」との相対スケールを保つ ためで、重みの絶対値ではなく行内の相対的な強弱だけが効きます。長さ不一致や 合計0以下・負値などの不正な重みは warning ログを出してその行を重みなし扱いにします。

現時点で重みが掛かるのは音の一致距離のみで、VARIATION_COST ・ WORD_NUMBER_PENALTY ・文節境界項は無重みのままです。

歌詞にルビ記法で読みを指定する(|表層《よみ》)

歌詞に青空文庫ルビ記法を書くと、その区間の読みを形態素解析の推定より優先できます。 辞書に無い当て字・固有名詞(|邪悪《ダークネス》)で効きます。

results = app.soramimi_maker.generate(["|邪悪《ダークネス》を飼い慣らせ"], db, param)
  • 開始記号は |(U+FF5C)と |(U+007C)の両方、読み括弧は 《》 のみ。
  • \| \| \《 \》 \\ はエスケープ(文字そのもの)。
  • 《よみ》 が続かない |、| を伴わない 《…》、表層や読みが空の記法、 改行をまたぐ記法は、いずれも通常の文字として扱います(暗黙形ルビは未対応)。
  • 記法を含まない入力の出力は従来と完全に同一です。

パーサ単体も公開しています(素テキストと区間注釈への分解のみ)。

from soramimic import parse_ruby

parse_ruby("|邪悪《ダークネス》を飼い慣らせ")
# => {"plain": "邪悪を飼い慣らせ",
#     "annotations": [{"start": 0, "end": 2, "reading": "ダークネス"}]}

start / end は plain 上のコードポイントオフセット(end は排他)です。

大きな単語リストの前処理を速くする(max_units)

単語リストの前処理( parse_tidy / parse_plain )は、各単語の読みからン・ッ・母音連続 の揺れを展開した発音バリエーションを全通り作ります。この数は音節数に対して指数的に 増える(該当する音節1つにつき2〜5通りに分岐する)ため、極端に長い読みが1語混じるだけで 前処理が何分もかかることがあります。format_kana が本体JS由来のバグで「英字を複数語含む 表層」の読みを繰り返してしまうので、英名入りの単語リストでは実際に起こります。

バリエーションはユニット数が完全一致するターゲットとしか照合されない ( maker._ld は長さ不一致を Infinity にする)ので、生成対象の歌詞行の最大ユニット数を 超えるバリエーションは作っても使われません。max_units を渡すとその上限で直積を 枝刈りします。

db = app.word_list.parse_tidy(csv_text, "", max_units=40)

結果は {k: v for k, v in parse_tidy(csv_text, "").items() if k <= max_units} と完全に 同一です(順序・ vcost ・ src 込み)。省略時(None)は従来と完全に同一の動作なので、 上限を歌詞行の最大ユニット数以上にしておけば生成結果は変わりません。

本体JSとの互換性

  • モジュールは本体 frontend/src/lib の各JSファイルと1:1対応です( kanaToSyllable.js → kana_to_syllable.py など)。
  • 互換性はゴールデンテストで担保しています。tools/generate_golden.mjs が本体JSを Node で直接実行して期待出力( tests/golden/*.json )を生成し、pytest で Python 出力との完全一致を検証します。本体更新への追従時は次で再生成してください:
node tools/generate_golden.mjs <soramimicリポジトリのルート> tests/golden
uv run pytest tests/test_golden.py
  • JS実装の癖(オブジェクトのキー列挙順、共有ミューテーション、既知の細かなバグを含む)も出力互換のため忠実に再現しています。詳細は各モジュールのコメント参照。

開発

uv sync --all-extras
uv run pytest
uv run ruff check .

License

MIT。同梱の英語発音データ( english-kana.json )は CMUdict 由来です( src/soramimic/data/english-kana.LICENSE 参照)。

Release files for soramimic 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for soramimic 0.2.0
File Size Uploaded
soramimic-0.2.0.tar.gz 2.0 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for soramimic 0.2.0
File Interpreter ABI Platform
soramimic-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 4.0 MB

Release files / soramimic-0.2.0.tar.gz

Download URL soramimic-0.2.0.tar.gz
Size 2.0 MB
Tags Source
SHA-256 checksum
How to use checksums
4d87662516d2e35d4000b4c0fd6f38b51cdbfee7d4e5be5ef6c9af8a1b667b0d
BLAKE2b-256 checksum
How to use checksums
5023b9b1b388ad6e0b248afa9a2e10e937f8cfd7d1b4b644cec1c2af9b0b36da
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.10

Release files / soramimic-0.2.0-py3-none-any.whl

Download URL soramimic-0.2.0-py3-none-any.whl
Size 2.0 MB
Tags Python 3
SHA-256 checksum
How to use checksums
1791d3557be51c798021f87ea9b9f8b486231234fbb2e757ed21b4ce9d82c047
BLAKE2b-256 checksum
How to use checksums
974003045886068b0d9af1104ef51b3ac410d6a7755640e44dad143bae580430
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.10

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page