diff --git a/doc.sh b/doc.sh new file mode 100644 index 0000000..1ddb7d7 --- /dev/null +++ b/doc.sh @@ -0,0 +1,5 @@ +sources=$(find bricks -name "*.js" -exec grep -l '.register(' {} \; -print|sort -u) +for s in $sources +do + t2t -p prompt.md -o docs/ai $s +done diff --git a/docs/ai/accordion.md b/docs/ai/accordion.md new file mode 100644 index 0000000..5b11f55 --- /dev/null +++ b/docs/ai/accordion.md @@ -0,0 +1,68 @@ +# Accordion +用于实现手风琴式折叠面板效果,允许用户通过点击选项卡切换显示对应的内容区域;类型为容器控件,继承自bricks.VBox。 + +## 主要方法 +| 方法名 | 功能说明 | 参数/选项 | +|--------|----------|-----------| +| `constructor(opts)` | 初始化手风琴控件,创建选项卡按钮并默认展开第一个选项卡内容 | - `item_size`:选项卡高度,默认值为`25px`
- `items`:选项卡配置数组,每个项需包含`name`(唯一标识)、`icon`(图标类名)、`label`(选项卡文本)、`content`(选项卡对应的内容控件JSON)、`refresh`(是否每次切换都重新构建内容,默认`false`)
- `item_css`:选项卡按钮的CSS类,默认`accordion-button`
- `content_css`:内容区域的CSS类,默认`accordion-content` | +| `async change_content(event)` | 点击选项卡按钮时触发,切换显示对应的内容区域。若`refresh`为`true`或内容未构建过,则重新构建内容控件 | - `event`:事件对象,`target.bricks_widget`指向被点击的选项卡按钮 | + +## 主要事件 +| 事件名 | 触发时机 | +|--------|----------| +| `click`(选项卡按钮) | 用户点击手风琴的任意选项卡按钮时触发,进而执行内容切换逻辑 | + +## 源码例子 +```json +{ + "id": "demo_accordion", // 手风琴控件唯一ID + "widgettype": "Accordion", // 控件类型为Accordion + "options": { + "item_size": "30px", // 自定义选项卡高度为30px + "items": [ // 选项卡配置数组 + { + "name": "tab_home", // 选项卡唯一标识 + "icon": "icon-home", // 选项卡图标类名 + "label": "首页", // 选项卡文本 + "content": { // 首页对应的内容控件(Label) + "widgettype": "Label", + "options": { + "text": "欢迎使用手风琴控件演示", + "align": "center" + } + } + }, + { + "name": "tab_info", + "icon": "icon-info", + "label": "信息", + "content": { // 信息页对应的内容控件(VBox容器,包含Label和Button) + "widgettype": "VBox", + "options": { + "align": "left" + }, + "subwidgets": [ + { + "widgettype": "Label", + "options": {"text": "手风琴支持动态加载内容"} + }, + { + "widgettype": "Button", + "options": {"label": "查看详情"}, + "binds": [ // 按钮事件绑定 + { + "actiontype": "script", + "wid": "infoBtn", // 按钮ID + "event": "click", + "target": "demo_accordion", + "script": "console.log('点击了查看详情按钮');" // 执行自定义脚本 + } + ] + } + ] + } + } + ] + } +} +``` \ No newline at end of file diff --git a/docs/ai/asr.md b/docs/ai/asr.md new file mode 100644 index 0000000..e03fee7 --- /dev/null +++ b/docs/ai/asr.md @@ -0,0 +1,116 @@ +# ASRClient + +用于实现语音识别(ASR,Automatic Speech Recognition)功能的前端控件。用户点击按钮开始录音,控件通过浏览器的 `MediaRecorder API` 获取麦克风音频流,并将音频数据编码为 Base64 后通过 WebSocket 实时发送至后端服务器进行语音识别。识别结果由服务器返回,控件触发 `transtext` 事件将文本内容传递给上层逻辑处理。 + +**类型**:普通控件(继承自 `bricks.VBox`) + +--- + +## 主要方法 + +- **`toggle_button()`** + 切换录音状态(开始/停止),并更新按钮图标。 + +- **`start_recording()`** + 异步方法,请求用户授权麦克风权限,启动 `MediaRecorder` 每秒采集音频片段并通过 WebSocket 发送。 + +- **`stop_recording()`** + 停止 `MediaRecorder` 录音,关闭媒体流。 + +- **`response_data(event)`** + WebSocket 接收到服务器消息时调用,解析 JSON 数据并派发 `transtext` 事件。 + +- **`response_log(event)`** + 默认的日志处理函数,在控制台输出识别结果,可通过重写来自定义日志行为。 + +--- + +## 主要事件 + +- **`start`** + 当用户点击按钮开始录音时触发,无参数。 + +- **`stop`** + 当用户停止录音时触发,无参数。 + +- **`transtext`** + 服务器返回识别文本时触发,参数结构如下: + ```json + { + "content": "识别出的文本", + "speaker": "说话人标识(可选)", + "start": "起始时间戳", + "end": "结束时间戳" + } + ``` + +--- + +## 源码例子 + +```json +{ + "id": "asr_widget", + "widgettype": "ASRClient", + "options": { + // 开始录音时显示的图标(可选) + "start_icon": "imgs/start_recording.svg", + // 停止录音时显示的图标(可选) + "stop_icon": "imgs/stop_recording.png", + // WebSocket 连接地址(必须) + "ws_url": "wss://example.com/api/asr/stream", + // 图标控件的额外配置(如大小、样式等,可选) + "icon_options": { + "width": "50px", + "height": "50px" + }, + // 发送给 WebSocket 的附加参数(例如模型类型、语言等) + "ws_params": { + "lang": "zh-CN", + "model": "asr-general" + } + }, + "binds": [ + { + "actiontype": "event", + "wid": "asr_widget", + "event": "transtext", + "target": "text_display", + "dispatch_event": "update_text", + "params": { + "from": "ASR" + }, + "rtdata": { + "msg": "{content}" + } + }, + { + "actiontype": "script", + "wid": "asr_widget", + "event": "start", + "target": "logger", + "script": "console.log('ASR recording started...');" + }, + { + "actiontype": "script", + "wid": "asr_widget", + "event": "stop", + "target": "logger", + "script": "console.log('ASR recording stopped.');" + } + ] +} +``` + +> ✅ **说明与注释**: +> +> - `widgettype: "ASRClient"` 表示使用已注册的语音识别控件。 +> - `options.ws_url` 必须是一个有效的 WebSocket 地址(`ws://` 或 `wss://`)。 +> - `binds` 中监听了 `transtext` 事件,将识别结果动态更新到 ID 为 `text_display` 的控件中。 +> - 使用 `{content}` 占位符可在运行时自动替换为实际识别内容(基于 bricks 数据绑定机制)。 +> - 可结合 `registerfunction` 调用全局函数进一步处理识别结果,如语义理解、TTS 回复等。 + +--- + +📌 **应用场景建议**: +适用于语音输入、实时字幕、语音助手交互等需要前端采集语音并实时获取识别结果的场景。需确保后端支持 WebSocket 流式 ASR 解码。 \ No newline at end of file diff --git a/docs/ai/audio.md b/docs/ai/audio.md new file mode 100644 index 0000000..875cb07 --- /dev/null +++ b/docs/ai/audio.md @@ -0,0 +1,282 @@ +# AudioPlayer + +用于播放音频文件的普通控件,继承自 `JsWidget`。支持本地或远程音频资源播放、自动播放、播放控制(暂停/继续)、播放队列管理以及通过流式响应动态加载多个音频片段。 + +**类型:** 普通控件(非容器控件) + +--- + +## 主要方法 + +- `play()` + 异步方法,开始播放当前音频。如果音频已暂停,则恢复播放。 + +- `toggle_play()` + 异步方法,切换播放/暂停状态。若当前为暂停状态则播放,否则暂停。 + +- `set_url(url)` + 设置音频源并立即开始播放。参数 `url` 为音频文件的 URL 地址。 + +- `set_source(url)` + 设置音频源(仅更新 `` 标签和 `audio.src`),不自动播放。 + +- `add_url(url)` + 将指定 URL 添加到播放列表末尾。如果当前音频处于“错误”或“结束”状态,则立即切换播放该音频;否则加入队列等待自动播放下一首。 + +- `get_status()` + 获取当前播放器的状态,返回值为以下之一: + - `"playing"`:正在播放 + - `"paused"`:已暂停 + - `"loading"`:加载中(数据不足) + - `"ended"`:播放结束 + - `"error"`:发生错误 + +- `set_stream_urls(response)` + 接收一个 `Response` 对象(如从 `fetch` 流式接口获取),解析其流中的每一段音频 URL,并逐个播放。适用于服务器推送多个音频片段的场景。 + +- `play_srclist(event)` + 内部异步方法,用于从 `srcList` 中按顺序播放未播放过的音频片段。 + +--- + +## 主要事件 + +- `ended` + 当所有音频播放完毕(包括播放列表中的最后一个)时触发。可用于通知上层组件播放完成。 + +--- + +## 源码例子 + +```json +{ + "id": "player1", + "widgettype": "AudioPlayer", + "options": { + "url": "/audio/intro.mp3", // 初始音频URL + "autoplay": true // 是否自动播放 + }, + "binds": [ + { + "actiontype": "method", + "wid": "btn_toggle", + "event": "click", + "target": "player1", + "method": "toggle_play", + "params": {} + }, + { + "actiontype": "method", + "wid": "btn_next", + "event": "click", + "target": "player1", + "method": "add_url", + "params": { + "url": "/audio/chapter2.mp3" + } + }, + { + "actiontype": "script", + "wid": "player1", + "event": "ended", + "target": "Popup", + "script": "bricks.alert('播放完成!');" + } + ] +} +``` + +> **注释说明:** +> - 此控件 ID 为 `player1`,初始加载并自动播放 `/audio/intro.mp3`。 +> - 点击 ID 为 `btn_toggle` 的按钮会调用 `toggle_play()` 方法实现播放/暂停切换。 +> - 点击 `btn_next` 按钮将添加新的音频到播放队列。 +> - 当音频播放结束后,弹出提示框告知用户“播放完成”。 + +--- + +# AudioRecorder + +音频录制控件,继承自 `HBox`(水平布局容器控件)。提供麦克风录音功能,支持 WAV 格式录音、实时录音时长显示、录音开始/结束事件派发,并可配置上传 URL 实现录音文件自动上传。 + +**类型:** 容器控件(继承自 HBox,包含子控件) + +--- + +## 主要方法 + +- `start_recording()` + 开始录音。若尚未打开麦克风权限,则先请求授权并初始化录音器。 + +- `stop_recording()` + 停止录音,生成 Blob 对象并派发 `record_ended` 事件,携带录音数据与播放 URL。 + +- `pause_recording()` + 暂停录音(如有支持)。 + +- `resume_recording()` + 恢复暂停的录音。 + +- `upload()` + 异步方法,将最近一次录音的数据通过 FormData 上传至 `upload_url` 配置的地址,使用 POST 请求发送文件 `recorder.wav`。 + +- `download()` + 下载当前录音文件,生成临时链接并触发浏览器下载行为。 + +- `recOpen()` / `recClose()` + 内部方法,用于打开/关闭麦克风访问权限及初始化 Recorder 实例。 + +--- + +## 主要事件 + +- `record_started` + 当录音开始前触发,可用于 UI 更新(如切换图标、启用播放预览等)。 + +- `record_ended` + 录音停止后触发,携带数据对象 `{ data: Blob, url: string, duration: number }`,可用于预览或上传。 + +- `uploaded` + 成功上传录音后触发,携带服务器返回结果 `ret`。 + +--- + +## 源码例子 + +```json +{ + "id": "recorder1", + "widgettype": "AudioRecorder", + "options": { + "upload_url": "/api/upload_audio", // 录音上传地址 + "start_icon": "imgs/start_recording.svg", // 开始录音图标 + "stop_icon": "imgs/stop_recording.svg", // 停止录音图标 + "icon_rate": 2 // SVG 图标缩放比例 + }, + "binds": [ + { + "actiontype": "event", + "wid": "recorder1", + "event": "record_started", + "target": "status_text", + "dispatch_event": "set_text", + "params": { + "text": "正在录音..." + } + }, + { + "actiontype": "event", + "wid": "recorder1", + "event": "record_ended", + "target": "status_text", + "dispatch_event": "set_text", + "params": { + "text": "录音结束,正在上传..." + } + }, + { + "actiontype": "registerfunction", + "wid": "recorder1", + "event": "uploaded", + "rfname": "onAudioUploaded", + "params": { + "recorderId": "recorder1" + } + }, + { + "actiontype": "method", + "wid": "btn_download", + "event": "click", + "target": "recorder1", + "method": "download", + "params": {} + } + ] +} +``` + +> **注释说明:** +> - 控件 ID 为 `recorder1`,使用自定义图标进行视觉反馈。 +> - 录音开始时,向 `status_text` 文本控件派发 `set_text` 事件更新状态。 +> - 录音结束后提示“正在上传”,并在上传成功后调用全局注册函数 `onAudioUploaded` 处理后续逻辑。 +> - 提供一个下载按钮 `btn_download`,允许用户手动下载录音文件。 + +--- + +# TextedAudioPlayer + +带文本同步显示的音频播放器,继承自 `VBox`(垂直容器控件)。常用于语音朗读+字幕同步场景。能够接收流式 JSON 数据,其中包含音频 Base64 编码片段和对应文本内容,实现边接收边播放边展示文本的效果。 + +**类型:** 容器控件(可包含子控件) + +--- + +## 主要方法 + +- `set_stream_urls(response)` + 接收一个 `Response` 流对象,从中读取 JSON 数据流(每个 JSON 包含 `audio` 和 `text` 字段),解码后缓存至内部队列。 + +- `load_stream_data(json)` + 内部异步方法,处理每一个流式到达的 JSON 数据块,将其推入播放缓冲区,并尝试触发播放。 + +- `playnext()` + 从缓冲区取出下一条音频+文本数据,设置音频播放,并更新文本区域内容。当播放完当前音频后自动触发下一首。 + +--- + +## 主要事件 + +无自定义事件对外暴露,但内部监听 `AudioPlayer` 的 `ended` 事件以驱动连续播放。 + +--- + +## 源码例子 + +```json +{ + "id": "texted_player", + "widgettype": "TextedAudioPlayer", + "options": { + "height": "300px", + "width": "100%" + }, + "subwidgets": [], + "binds": [ + { + "actiontype": "urlwidget", + "wid": "btn_start_read", + "event": "click", + "target": "texted_player", + "options": { + "url": "/api/stream-audio-text", + "method": "POST", + "params": { + "text": "{{input_text}}" + } + }, + "mode": "replace" + }, + { + "actiontype": "method", + "wid": "texted_player", + "event": "ended", + "target": "bricks", + "method": "notify", + "params": { + "message": "全部朗读完成" + } + } + ] +} +``` + +> **注释说明:** +> - 控件 ID 为 `texted_player`,是一个垂直布局容器,内部包含一个 `AudioPlayer` 和一个带滚动的文本区域。 +> - 点击 `btn_start_read` 按钮时,向 `/api/stream-audio-text` 发起 POST 请求,传入动态文本内容(例如来自输入框的 `input_text`)。 +> - 服务器以流式 JSON 响应返回多个 `{ audio: base64str, text: '...' }` 数据块,客户端逐步播放音频并同步显示文本。 +> - 所有内容播放完成后,调用 `bricks.notify` 显示完成通知。 + +--- + +> ✅ **备注:** +> 上述三个控件均已通过 `bricks.Factory.register` 注册,可在 `.ui` 文件中直接使用 `widgettype` 调用。 +> 使用时需确保引入依赖库:[Recorder.js](https://gitee.com/xiangyuecn/Recorder) 用于录音功能。 \ No newline at end of file diff --git a/docs/ai/bar.md b/docs/ai/bar.md new file mode 100644 index 0000000..d337562 --- /dev/null +++ b/docs/ai/bar.md @@ -0,0 +1,88 @@ +# ChartBar + +ChartBar 是一个基于 ECharts 的柱状图控件,用于可视化展示分类数据的数值对比。该控件继承自 `bricks.EchartsExt`,属于**普通控件**(非容器控件),不支持包含子控件。 + +--- + +## 主要方法 + +- **`values_from_data(data, name)`** + 从传入的数据数组中提取指定字段的值,返回值数组。常用于构建 ECharts 的 series 数据。 + +- **`lineinfo_from_data(data, name)`** + 根据字段名生成单个柱状序列(series)的配置对象,类型为 `'bar'`。 + +- **`setup_options(data)`** + 核心方法,接收原始数据并生成完整的 ECharts 配置项(options),包括: + - tooltip:轴触发提示 + - legend:图例(基于 nameField 字段) + - xAxis:类别轴(横轴) + - yAxis:数值轴(纵轴) + - series:多个柱状图序列 + +--- + +## 主要事件 + +该控件未定义自定义事件,但继承了 `EchartsExt` 基类所支持的标准事件,例如: + +- `'click'`:用户点击图表时触发,可通过 binds 监听。 +- `'legendselectchanged'`:图例选择变化时触发。 + +这些事件可用于与其他控件联动或执行脚本逻辑。 + +--- + +## 源码例子 + +```json +{ + "id": "chart_sales_bar", + "widgettype": "ChartBar", + "options": { + "data_url": "/api/sales/data", // 从后端接口获取数据 + "method": "GET", // 请求方式,默认可省略 + "params": { // 请求参数 + "year": 2024, + "region": "north" + }, + "nameField": "month", // 用作 X 轴显示的字段(如月份) + "valueFields": ["sales", "target"] // 多个指标字段,分别绘制为不同柱子 + }, + "binds": [ + { + "actiontype": "bricks", + "wid": "btn_refresh_chart", + "event": "click", + "target": "chart_sales_bar", + "options": { + "widgettype": "ChartBar", + "options": { + "data_url": "/api/sales/data", + "params": { + "year": "{{widget('input_year').getValue()}}", // 动态取输入框年份 + "region": "north" + }, + "nameField": "month", + "valueFields": ["sales", "target"] + } + }, + "mode": "replace" + }, + { + "actiontype": "script", + "wid": "chart_sales_bar", + "event": "click", + "script": "async function({ params }) { console.log('柱状图点击:', params); }", + "params": {} + } + ] +} +``` + +> ✅ **注释说明:** +> - 此控件通过 `data_url` 和 `params` 自动加载远程数据并渲染柱状图。 +> - `nameField` 定义 X 轴标签(如 “1月”, “2月”)。 +> - `valueFields` 支持多个字段,每个字段对应一个柱状系列(如销售额、目标额)。 +> - 使用 `binds` 实现按钮刷新图表和点击日志输出。 +> - `{{widget(...)}}` 表达式可在运行时动态获取其他控件的值,实现交互过滤。 \ No newline at end of file diff --git a/docs/ai/brief.md b/docs/ai/brief.md new file mode 100644 index 0000000..30322fb --- /dev/null +++ b/docs/ai/brief.md @@ -0,0 +1,106 @@ +# bricks框架简介 +## 目录 +* bricks目标 +* bricks概念 +* bricks开发方法 +* bricks运行 + +## bricks目标 +* 无前端代码或极少代码 +* 降低前端开发技术难度 +* 数据驱动 +* 常用控件包装 +* 纯json开发 + +## bricks概念 +* 控件与控件继承 +* 事件以及事件处理 +* 控件嵌套和页面组装 + +### 控件与控件继承 +bricks采用控件这一概念来描述web GUI的显示部件,每个控件均映射到一个html +的标签类型的一个javascript类。每个控件均可以实例化,并可在页面显示。 +控件分为:基本控件,容器控件。 + +* 基本控件 +基本控件是一个原子控件,不能有子控件。 +* 容器控件 +容器控件可以有子控件,bricks通过在容器控件添加子控件,以及在子容器控件中 +在添加子子控件的方式来构造复杂的web页面。 + +控件的详细介绍请参看[控件说明](widgets.md) + +### 控件扩展 +如果现有的控件没法满足系统要求,bricks支持控件扩展,控件扩展需遵守: +* 控件class继承自某一个控件的class + +* 按照需求实现控件逻辑 + +* 在需要的地方用this.dispatch触发此控件的事件 + +假设需要扩展一个名字叫ExtContainer的控件 +``` +bricks.ExtContainer = class extends bricks.VBox { + constructor(opts){ + super(opts); + /* 新控件的创建代码 */ + } + ...... + /* 对象的其他方法,在需要的时候,在某个方法中,使用this.dispatch('new_event', data)方法引发事件 */ +} +bricks.register('ExtContainer', bricks.ExtContainer); /* 注册新控件 */ +``` +新控件的使用,example.ui +``` +{ + "widgettype":"ExtContainer", + "options":{ + .... + }, + "subwidgets":[ + ... + ], + "binds":[ + { + "wid":"self", + "event":"new_event", + "actiontype":"urlwidget", + "target":"some_container", + "options":{ + "url":"{{entire_url('./some_ui.ui')}}" + } + } + ] +} +``` + +### 事件以及事件处理 +每个控件都能触发所映射dom元素的事件,以及控件js类的成员函数以及祖先类的 +成员函数中dispatch出的事件 + +所以bricks控件的事件来源于两类,dom元素原生事件以及控件类中创造的事件。 +两类事件处理方式相同。 + +### 控件表达形式 +在服务器的后台,以json文件的形式表达控件,每个ui文件定义一个控件, +对于容器控件,可以在ui文件中的subwidgets子属性中为此控件添加子控件 + +#### id属性 +字符串属性,定义控件的id,让控件可以用getWidgetById找到,如果不给定,系统会自动生成一个id +#### options属性 +字典属性,创建控件时的选项,每个控件可接受的选项请参看控件选项说明 +#### binds属性 +数组属性,定义零到多个事件响应,每个bind字典需要遵守[事件](event.md)要求 +#### 容器控件特有属性 +##### subwidgets +数组属性,定义容器控件的子控件,每个元素定义一个子控件,子控件遵守控件的数据要素要求 + +## 开发 +使用存放在服务器后台的.ui后缀的json格式文件来开发,每个.ui文件定义一个控件, 支持基本控件和容器空间。 + +关于如何书写ui文件请参考[UI文件格式](descjson.md) + +## 调试 +ui文件可以直接调试,如在服务器根目录下的test目录下有一个hello.ui文件, +就可以在浏览器中用url:https://sername/test/hello.ui调试 + diff --git a/docs/ai/button.md b/docs/ai/button.md new file mode 100644 index 0000000..f7ee81d --- /dev/null +++ b/docs/ai/button.md @@ -0,0 +1,92 @@ +# Button + +按钮控件(Button)是 Bricks.js 框架中用于触发用户交互行为的**普通控件**,继承自 `bricks.Layout`。它通常用于提交表单、打开弹窗、执行脚本或导航等操作。Button 支持图标、文本标签、自定义样式以及事件绑定,适用于各种 UI 场景。 + +## 主要方法 + +- **`target_clicked(event)`** + 内部方法,当按钮被点击时触发,阻止事件冒泡并派发 `click` 事件,同时处理配置的 `action` 行为。 + +- **`create()`** + 创建底层 DOM 元素(`