free pascal:fpwebview 组件通过 JSBridge 调用本机TTS

从 https://github.com/PierceNg/fpwebview 下载 fpwebview-master.zip 简单易用。

先请看 \fpwebview-master\README.md

cd \lazarus\projects\fpwebview-master\demo\js_bidir

学习 js_bidir.lpr ,编写 js_bind_speak.lpr 如下,通过 JSBridge 调用本机TTS。

program js_bind_speak;

{$linklib libwebview}
{$mode objfpc}{$H+}

uses
  {$ifdef unix}cthreads,{$endif}
  Classes,Process,SysUtils,StrUtils,
  Variants,ComObj, math,
  webview;

var
  w: PWebView;
  sapi: Variant;
  url: String;
  txt: String;

// seq:sequence; req:request; arg:argument
procedure speak(const seq: PAnsiChar; const req: PAnsiChar; arg: Pointer); cdecl;
var
  s: String;
begin
  if req <> nil then
  begin
    s := strPas(req);
    writeln('speak:'+s);
    try
      sapi.Speak(s);
      Sleep(1000)
    except
      writeln(' OLE Error ')  
    end;
  end
  else
    writeln(' req is nil');
  //webview_return(w, seq, WebView_Return_Ok, '{result: "?"}');
end;

begin
  if Assigned(InitProc) then
    TProcedure(InitProc);

  { Set math masks. libwebview throws at least one of these from somewhere deep inside. }
  SetExceptionMask([exInvalidOp, exDenormalized, exZeroDivide, exOverflow, exUnderflow, exPrecision]);

  try
    sapi := CreateOleObject('SAPI.SpVoice')
  except
    writeln(' OLE Error ')
  end;
  
  url := 'http://localhost/';
  if ParamCount =1 then
  begin
    if Length(ParamStr(1))<6 then
      url := 'http://localhost:' + ParamStr(1)
    else
    begin
      if AnsiStartsStr('http', ParamStr(1)) then url := ParamStr(1)
      else if AnsiStartsStr('192.', ParamStr(1)) then url := 'http://' + ParamStr(1)
      else url := 'https://' + ParamStr(1);
    end;
  end
  else
    url := ParamStr(1);

  writeln(url);
  w := webview_create(WebView_DevTools, nil);
  webview_set_size(w, 1024, 768, WebView_Hint_None);
  webview_set_title(w, PAnsiChar('WebView - Pascal Javascript Bridge'));
//webview_bind(w: PWebView; const name: PAnsiChar; fn: TWebViewBindProc; arg: Pointer);
  webview_bind(w, PAnsiChar('sapi_speak'), @speak, PAnsiChar(txt));
  webview_navigate(w, PAnsiChar(url));
  webview_run(w);
  webview_destroy(w);
end.

注意这一句:webview_bind(w, PAnsiChar('sapi_speak'), @speak, PAnsiChar(txt));

编写 编译批命令:winbuild.bat  如下

@echo off

echo Set up FPC executable path.
set fpcexe=D:\lazarus\fpc\3.2.2\bin\x86_64-win64\fpc.exe
if not exist "%fpcexe%" (
	echo ERROR: Edit this batch file to set up location of fpc.exe
	exit /b 1
)
echo "%fpcexe%"

echo Building...
copy "..\..\dll\x86_64\libwebview.a" .
copy "..\..\dll\x86_64\webview.dll" .
copy "..\..\dll\x86_64\WebView2Loader.dll" .
"%fpcexe%" -Fu..\..\src -Fl. js_bind_speak.lpr

编写 运行批命令:winrun.bat  如下

@echo off
@echo js_bind_speak.exe 
js_bind_speak.exe  %1

前端 js 代码:index6.html  如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">   
    <title>查询英汉词典</title> 
    <script src="jquery-3.2.1.min.js"></script>
<style>
/* portrait 判断为竖屏 */
@media only screen and (orientation: portrait){
     #lab1 {display:none;}
} 
/* landscape 判断为横屏 */ 
@media only screen and (orientation: landscape){
     #lab1 {display: ;} 
}    
</style>
</head>
<body>
  <form name="form" id="form" action="trans" method="POST" target="iframe">
    <label id="lab1">请输入:</label>
    <input type="text" name="txt" id='txt' size="30" placeholder="请输入 a word">
    <input type="submit" name="eng_han" value="英译汉">
    <input type="button" name="btn1" id="btn1" value="前缀查询">
    <input type="button" name="btn2" id="btn2" value="TTS读音" onclick="tts2()">
  </form>
  <p></p>
<div style="float:left; width:100%;">
  <div id="result" style="float:left; width:80%; height:400; border:2px;">
    <iframe name="iframe" id="iframe" width="100%" height="400"> </iframe>
  </div>
  <div id="alist" style="float:right; width:20%; height:400; border:2px;">
  </div>
</div>
  
<script type="text/javascript">
    $(function(){
      $("#btn1").click(function(){
        $.getJSON("/prefix?txt="+$("#txt").val(), function(data){
          $('#alist').empty();
          var items = [];
          $.each(data, function(i, item){
            if (i<=20){
              items[i] = '<a href="/trans?txt=' +item+ '" target="iframe">' +item+ "</a><br>";
            }
          });
          var a = items.join('\n');
          if (a) $('#alist').html(a);
        })
      })
    });
    //定义对象 customHost,方便js函数调用
    //var hostObj = window.chrome.webview.hostObjects.customHost;
    
    // pascal TTS
    function tts() {
        var txt = document.getElementById('txt').value;
        if (txt.length >1) {
          (async ()=>{
              await sapi_speak(txt);
          })();
        }
    }

    // 屏幕双击取词, pascal TTS
    function tts2() {
        // 获取iframe里的选择内容
        var select = window.frames['iframe'].getSelection();
        var txt = select.toString();
        txt = txt.trim();
        if (txt.length >1) { // alert(txt);
          (async ()=>{
              await sapi_speak(txt);
          })();
        } else {
          tts();
        }
    }

  // 页面加载添加:监听iframe网页点击事件
  $(document).ready(function(){
    var listener = window.addEventListener('blur', function(){
      if (document.activeElement === document.getElementById('iframe')){
        $('iframe').contents().find('a.fayin').click(function(event){
          event.preventDefault();
          var a = $(this);
         if (a){
          var addr = a.attr('href');
          if (addr.indexOf('sound://')==0){
            var url = "/data" + addr.substring(7);
            var mp3 = new Audio(url);
            mp3.addEventListener("canplaythrough", (event)=> {
               mp3.play();
            });
          } else {
            alert('href='+addr);
          }
         }
        })
      }        
    });
  });
</script> 
</body>
</html>

web 服务程序请参考:python:mdict + bottle = web 查询英汉词典

记得修改一句:def server_static(filepath="index6.html"):

先运行 web 服务程序:python mdict_bottle.py

再执行编译:winbuild.bat

最后运行:winrun.bat 8086

访问  http://localhost:8086/

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值