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

news2024/11/27 2:32:38

从 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;

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, 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/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1448840.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java入门高频考查基础知识9(银盛15问万字参考答案)

JAVA刷题专栏&#xff1a;http://t.csdnimg.cn/9qscL 目录 一、Springcloud的工作原理 三、注册中心心跳是几秒 四、消费者是如何发现服务提供者的 五、多个消费者调⽤用同⼀接口&#xff0c;eruka默认的分配⽅式是什么 六、springboot常用注解&#xff0c;及其实现 七、…

pytorch常用激活函数笔记

1. relu函数&#xff1a; 公式&#xff1a; 深层网络内部激活函数常用这个 import matplotlib.pyplot as pltdef relu_fun(x):if x>0:return xelse:return 0x np.random.randn(10) y np.arange(10)plt.plot(y,x)for i ,t in enumerate(x):x[i] relu_fun(t) plt.p…

移动机器人激光SLAM导航(五):Cartographer SLAM 篇

参考 Cartographer 官方文档Cartographer 从入门到精通 1. Cartographer 安装 1.1 前置条件 推荐在刚装好的 Ubuntu 16.04 或 Ubuntu 18.04 上进行编译ROS 安装&#xff1a;ROS学习1&#xff1a;ROS概述与环境搭建 1.2 依赖库安装 资源下载完解压并执行以下指令 https://pa…

Python 读取pdf文件

Python 实现读取pdf文件简单示例。 安装命令 需要安装操作pdf的三方类库&#xff0c;命令如下&#xff1a; pip install pdfminer3K 安装过程如下&#xff1a; 引入类库 需要引入很多的类库。 示例如下&#xff1a; import sys import importlib importlib.reload(sys)fr…

鸿蒙开发系列教程(十八)--页面内动画(1)

页面内的动画 显示动画 语法&#xff1a;animateTo(value: AnimateParam, event: () > void): void 第一个参数指定动画参数 第二个参数为动画的闭包函数。 如&#xff1a;animateTo({ duration: 1000, curve: Curve.EaseInOut }, () > {动画代码}&#xff09; dura…

Golang快速入门到实践学习笔记

Go学习笔记 1.基础 Go程序设计的一些规则 Go之所以会那么简洁&#xff0c;是因为它有一些默认的行为&#xff1a; 大写字母开头的变量是可导出的&#xff0c;也就是其它包可以读取 的&#xff0c;是公用变量&#xff1b;小写字母开头的就是不可导出的&#xff0c;是私有变量…

cool-node.js 框架 创建数据表的步骤

1.文件目录 business 这个模块的数据库对应的就是 entity文件夹 这一个文件.ts 就是代表了一个表 2.user.ts 表的介绍 这个 相当于 时 固定格式的数据表 &#xff0c;只需要按照这个 格式和创建表的方式来创建就可以 BusinessUserEntity 相当于时这个数据表类的名字 Entity(b…

FPGA_简单工程_拨码开关

一 框图 二 波形图 三 代码 3.1 工程代码 module bomakiaguan (input [15:0] switch, // 输入16路拨码开关output reg [15:0] led // 输出16个LED灯 );always (switch) beginled < switch; // 将拨码开关的值直接赋给LED灯 end // 将拨码开关的值直接赋给LED灯 endmodu…

五.实战软件部署 4-5MYSQL 5.7版本在ubuntu(WSL环境)安装MYSQL 8.0版本在ubuntu(WSL环境)安装

目录 五.实战软件部署 4-MYSQL 5.7版本在ubuntu(WSL环境)安装 安装 1-下载apt仓库文件 2-配置apt仓库 3-更新apt仓库的信息 4-检查是否成功配置mysql5.7的仓库 5-安装mysql5.7 6-启动mysql 7-对mysql进行初始化 1-输入密码 2-是否开启密码验证插件&#xff0c;如果需…

二叉树的顺序结构及堆的实现

创作不易&#xff0c;兄弟们给个三连&#xff01;&#xff01; 一、二叉树的顺序存储 顺序结构指的是利用数组来存储&#xff0c;一般只适用于表示完全二叉树&#xff0c;原因如上图&#xff0c;存储不完全二叉树会造成空间上的浪费&#xff0c;有的人又会问&#xff0c;为什么…

ELAdmin 部署

后端部署 按需修改 application-prod.yml 例如验证码方式、登录状态到期时间等等。 修改完成后打好 Jar 包 执行完成后会生成最终可执行的 jar。JPA版本是 2.6&#xff0c;MyBatis 版本是 1.1。 启动命令 nohup java -jar eladmin-system-2.6.jar --spring.profiles.active…

探索微信小程序的奇妙世界:从入门到进阶

文章目录 一、什么是微信小程序1.1 简要介绍微信小程序的定义和特点1.2 解释小程序与传统应用程序的区别 二、小程序的基础知识2.1 微信小程序的架构2.2 微信小程序生命周期的理解2.3 探索小程序的目录结构和文件类型 三、小程序框架和组件3.1 深入了解小程序框架的核心概念和原…

【JavaEE】_JavaScript(Web API)

目录 1. DOM 1.1 DOM基本概念 1.2 DOM树 2. 选中页面元素 2.1 querySelector 2.2 querySelectorAll 3. 事件 3.1 基本概念 3.2 事件的三要素 3.3 示例 4.操作元素 4.1 获取/修改元素内容 4.2 获取/修改元素属性 4.3 获取/修改表单元素属性 4.3.1 value&#xf…

nba2k24 灌篮高手樱木花道面补

nba2k24 灌篮高手樱木花道面补 nba2k23-nba2k24通用 灌篮高手樱木花道面补 下载地址&#xff1a; https://www.changyouzuhao.cn/9539.html

linux系统配置zabbix监控agent端

目录 客户端配置 启动服务 浏览器工具设置 创建主机群组 创建主机 创建监控项 ​编辑 ​编辑 创建触发器 查看监控 客户端配置 rpm -Uvh https://repo.zabbix.com/zabbix/5.0/rhel/7/x86_64/zabbix-release-5.0-1.el7.noarch.rpm # yum clean allyum install -y zab…

【Python】Python代码的单元测试

Python代码的单元测试 单元测试的概念 定义&#xff1a;是指对软件中的最小可测试单元进行检查和验证。 作用&#xff1a;可以确保程序模块是否否和我们规范的输出&#xff0c;保证该模块经过修改后仍然是满足我们的需求。 单元测试的策略 如果要创建单元测试&#xff0c;…

2024最新APP下载单页源码 带管理后台 首发

2024最新APP下载单页源码 带管理后台 首发 新版带后台管理app应用下载页,自动识别安卓苹果下载页&#xff0c;带管理后台&#xff0c;内置带3套App下载模板带中文模板/英文模板随时切换。 下载地址2023最新APP下载单页源码 带管理后台 .zip官方版下载丨最新版下载丨绿色版下载…

重复导航到当前位置引起的。Vue Router 提供了一种机制,阻止重复导航到相同的路由路径。

代码&#xff1a; <!-- 侧边栏 --><el-col :span"12" :style"{ width: 200px }"><el-menu default-active"first" class"el-menu-vertical-demo" select"handleMenuSelect"><el-menu-item index"…

深度学习-吴恩达L1W2作业

作业1&#xff1a;吴恩达《深度学习》L1W2作业1 - Heywhale.com 作业2&#xff1a;吴恩达《深度学习》L1W2作业2 - Heywhale.com 作业1 你需要记住的内容&#xff1a; -np.exp&#xff08;x&#xff09;适用于任何np.array x并将指数函数应用于每个坐标 -sigmoid函数及其梯度…

【教学类-16-02】20240214《数字卡片1-9(正方形)华光彩云_CNKI》

背景需求&#xff1a; 前期坐过长方形A4纸的数字卡片 【教学类-16-01】20221121《数字卡片9*2》&#xff08;中班)_数字卡片pdf-CSDN博客文章浏览阅读897次。【教学类-16-01】20221121《数字卡片9*2》&#xff08;中班)_数字卡片pdfhttps://blog.csdn.net/reasonsummer/artic…