工作流端點

修拗音、押韻收束、逐字標註

01工作流端點是什麼

檢索端點回答「有什麼字符合條件」;工作流端點回答 「我這一句有沒有問題,該怎麼改」—— 把粵語填詞的判斷邏輯本身封裝起來, 呼叫方毋須自行實作聲調比對與音高層推算。

這是本服務最難自建的部分
聲調層映射、變調處理、詞邊界切分、音域頂底的可救性判斷 —— 這些規則若自行實作,誤判率極高。詞庫可以買,判斷邏輯才是難處。

02逐字標註

POST/api/lexicon/annotate

把一段文字逐字標上粵拼、協音碼、聲調與韻母。多音字會附全部候選讀音。

cURL
curl -X POST "https://api.writer.hk/api/lexicon/annotate" \
  -H "Authorization: Bearer $WRITERHK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text":"夜色靜靜落在窗前"}'
lines[0] → 夜 je6 碼2 · 色 sik1 碼3 · 靜 zing6 碼2 …
回應(節錄)
{
  "lines": [[
    {
      "char": "夜", "g": 0,
      "jyutping": "je6", "code": "2", "tones": [6], "rhyme": "e",
      "polyphones": [
        { "jyutping": "je6", "code": "2", "tones": [6], "rhyme": "e" },
        { "jyutping": "je2", "code": "3", "tones": [2], "rhyme": "e" }
      ]
    },
    { "char": "色", "g": 0, "jyutping": "sik1", "code": "3", "tones": [1], "rhyme": "ik" }
  ]],
  "scheme": "0243"
}
  • g詞群編號:同一個詞的字共用同一個 g。 「夜色」是 g: 0、「靜靜」是 g: 1。詞邊界會影響讀音判斷, 所以必須整句送出,不要逐字呼叫。
  • polyphones 只在多音字出現。jyutping 是依上下文選定的讀音,polyphones 是全部候選 —— 需要讓使用者手動改音時用它。
  • 換行會切成 lines 的多個元素,可直接送整段歌詞。

03偵測並修正拗音

POST/api/lexicon/workflow/fix-contour

給一句歌詞與旋律走向,回報哪些位置的字音逆著旋律走 (即「拗音」——唱出來會變成另一個字),並給出可換的詞與字。

參數型別預設說明
line必填string單行歌詞,上限 200 字。
movesstring相鄰字的旋律走向:+ 升 / - 降 / = 平,長度為字數減一。
melodynumber[]每字一個 MIDI 音高;null 表示該處不限。與 moves 擇一。
max_candidatesinteger8每處最多回幾個建議(1–20)。
「風吹過山崗」配上 = - + - 的走向
cURL
curl -X POST "https://api.writer.hk/api/lexicon/workflow/fix-contour" \
  -H "Authorization: Bearer $WRITERHK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"line":"風吹過山崗","moves":"=-+-","max_candidates":4}'
risk_count 1 · position 4「崗」旋律降但字音平 → 可換
issues[0](節錄)
{
  "position": 4,
  "char": "崗",
  "word": "山崗",
  "melody_move": "-",
  "lyric_move": "=",
  "prev_char": "山",
  "fixable": true,
  "char_fixable": true,
  "word_fixable": true,
  "reason": null,
  "word_swaps": [
    { "word": "山脊", "jyutping": "saan1 zek3", "reg": "雅", "definition": "山峰頂部連綿的高線" },
    { "word": "高地", "jyutping": "gou1 dei6", "reg": "通", "definition": "地勢較高的地方" }
  ],
  "char_swaps": [
    { "char": "槓", "jyutping": "gong3", "same_final": true, "same_initial": true, "closeness": "同韻" }
  ]
}
  • melody_movelyric_move —— 兩者不一致就是拗音。
  • word_swaps整個詞(保住語義),char_swaps單字(保住音)。前者通常較可用,後者用於已經想好要什麼音的情況。
  • fixable: false 表示這一處換字救不到,reason 會說明原因 (常見是夾在音域頂/底),此時要改的是旋律或鄰字。 這是誠實的回答,不是失敗。
  • chars 陣列回報每個字的 pitch(音高層 0/2/4/6)與兩個 move, 可直接畫成對照圖。

04押韻收束

GET/api/lexicon/workflow/rhyme-close

收句的難處在於:韻定了之後,尾字的聲調還必須夾得上旋律的最後一個音。 此端點把候選按尾字聲調分組,讓你直接挑「音層夾得到」的那一組。

押「心」韻、悲傷、兩字
cURL
curl -H "Authorization: Bearer $WRITERHK_API_KEY" \
  "https://api.writer.hk/api/lexicon/workflow/rhyme-close?rhyme_char=心&emotion=悲傷&length=2&limit=10"
total 49 · 6 組(依尾字聲調)
end_tonepitch_levelcount
40(最低)10下沉 / 低吟
16(最高)10
26(最高)10
629
349
541

pitch_level 越大越高音(6 最高、0 最低)。若旋律的收尾音在高處, 就取 pitch_level: 6 那兩組。loose=true 可放寬到通韻組,rhymes_used 會回報實際採用了哪些韻母。

可再疊加 emotionthemevalenceregposlength 收窄語義範圍。

05成本與速率

工作流端點每次計 5 個 credit
這兩個端點內部要做多次交集與候選評分,成本明顯高於單純檢索, 因此在計量上以 5 credit 計(檢索端點為 1)。 速率上限也較低:匿名 10 / 分鐘。
  • 不要在每次鍵盤輸入時呼叫 fix-contour —— 在使用者停止輸入後再送出。
  • /annotate 屬一般計量(1 credit),做即時標註用它就夠; 只有真的要「找出問題並給建議」時才用 fix-contour
  • 候選數量用 max_candidates 控制,不要一律取滿 20。

用量與 credit 的實際消耗可在主控台的用量頁逐日核對。