最简SSML纯原生Editor编辑器

无框架无难度

懒得找,自己简易撸一个够用的。

容易扩展。

<!DOCTYPE html>
<html lang="zh-CN">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>SSML Editor</title>

  <style>
    .tts-sub {
      position: relative;
      color: pink;
      font-weight: bold;
    }

    .tts-gap {
      position: relative;
      display: inline-block;
      width: 40px;
      height: 20px;
      font-size: 12px;
      color: #999;
    }

    .tts-gap::after {
      content: attr(tts-value);
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 20px;
      display: flex;
      align-items: center;
      justify-content: center;
    }

    .tts-sayas {
      color: blue;
      font-weight: bold;
    }
  </style>
</head>

<body style="display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100vh;">
  <h1>SSML Editor</h1>
  <div id="ssmlEditor" contenteditable="true" style="word-break: break-all; white-space: pre-wrap;">
    112233
    王老石平日里是个温吞的人,这一次对着衙门里的公人,也忍不住说了一番重话:
    “你们也是人,也是人生爹妈养的咧,你们要把村里人都逼死咧。”
  </div>

  <button onclick="onAddSubTag()">添加读音</button>
  <button onclick="onAddGap()">添加间隔</button>
  <button onclick="onChangeNumberMode()">数字模式</button>

  <button onclick="onGenerateSSML()">生成SSML</button>

  <script>
    let selectedText = ''
    document.addEventListener('selectionchange', function (e) {
      // console.log(e.target)
      let selection = document.getSelection()
      let range = selection.getRangeAt(0)
      selectedText = range.toString()
      paranetNode = selection.anchorNode.parentNode
      // console.log(selection, range, selectedText, paranetNode)
      if(paranetNode.id === 'ssmlEditor') {
        console.log('ssmlEditor tag')
      }
    })

    function onAddSubTag() {
      let text = ''
      if(text = prompt('请输入正确读音。')) {
        let subTag = `<span tts-value="${text}" class="tts-sub" title="读:${text}">${selectedText}</span>`
        document.execCommand('insertHTML', false, subTag)
      }
    }

    function onAddGap() {
      let gap = ''
      if(gap = prompt('请输入间隔时长,单位毫秒。')) {
        let subTag = `<span tts-value="${gap}" class="tts-gap" title="间隔:${gap}ms">${selectedText}</span>`
        document.execCommand('insertHTML', false, subTag)
      }
    }

    function onChangeNumberMode() {
      let numberMode = prompt('请输入数字模式,1:数值,2:单个读。')
      let subTag = `<span tts-value="${numberMode === '1' ? 'number' : 'number_digit'}" class="tts-sayas" title="读法:${numberMode === '1' ? '数值' : '单个读'}">${selectedText}</span>`
      document.execCommand('insertHTML', false, subTag)
    }

    function onGenerateSSML() {
      let html = document.getElementById('ssmlEditor').innerHTML
      const ssml = onHtmlToSsml(html)
      alert(`<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" xml:lang="zh-CN"><voice name="zh-CN-YunxiNeural">${ssml}</voice></speak>`)
    }

    function onHtmlToSsml(html) {
      const div = document.createElement('div')
      div.innerHTML = html
      console.log(div.childNodes)
      let ssml = ''
      for(let i = 0; i < div.childNodes.length; i++) {
        const node = div.childNodes[i]
        if(node.nodeType === Node.ELEMENT_NODE) {
          if(node.localName === 'span') {
            if(node.classList.contains('tts-sayas')) { // 数值类型
              ssml += `<say-as interpret-as="${node.getAttribute('tts-value')}">${node.textContent}</say-as>`
            } else if(node.classList.contains('tts-sub')) { // 发音
              ssml += `<sub alias="${node.getAttribute('tts-value')}">${node.textContent}</sub>`
            } else if(node.classList.contains('tts-gap')) { // 间隔
              ssml += `<break time="${node.getAttribute('tts-value')}ms" />`
            } else { // 目前只支持间隔、发音、数值类型
              ssml += node.textContent
            }
          } else { // 目前只支持span标签
            ssml += node.textContent
          }
        } else { // 目前只支持span标签
          ssml += node.textContent
        }
      }
      return ssml
    }
  </script>
</body>

</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值