AI 讲房集成指南
本文档面向接入众趣 zqsdk 的开发者,说明如何在自己的项目中实现「AI 讲房」功能。按步骤完成能力判断、事件监听、方法调用与 UI 搭建即可完成集成。
一、功能简介与前置条件
1.1 什么是 AI 讲房
AI 讲房是众趣 SDK 的「新版讲房」能力:按预设段落(小区内部、周边配套、户型解析、房源信息)自动播放讲解,并同步当前段落与进度。你的项目需要:
- 在合适的时机判断当前模型是否支持讲房;
- 监听 SDK 事件以更新进度与播放状态;
- 调用 SDK 方法实现开始、暂停、切换段落;
- 提供讲房入口、控制条、进度展示等 UI(样式可完全自定义)。
1.2 展示示例

1.3 前置条件
- 已接入众趣 zqsdk,并在
zqsdk.init的complete回调中拿到window.housePlay(或等价实例)。 - 模型存在讲房数据;支持讲房的模型会在初始化时提供
vr_speak_data。 AI讲房接口对接流程见: AI讲房业务对接文档 - 本项目采用的baidu地图进行的示例组件开发, 如果需要正常使用,需要您设置环境变量
VITE_APP_BAIDU_MAP_AK到.env中
1.4 申请百度ak
百度地图ak, 用于本demo项目中地图相关信息的展示。百度地图应用申请地址:https://lbsyun.baidu.com/)
创建应用,应用类型请选择【浏览器端】

ak在此处复制

二、集成步骤概览
| 步骤 | 内容 |
|---|---|
| 1 | 在 init_UI 中根据 vr_speak_data 判断是否支持讲房,并初始化你的「讲房可用」状态与段落列表 |
| 2 | 在 housePlay 上注册讲房相关事件,将进度、段落索引、暂停/结束同步到你的状态 |
| 3 | 在用户操作时调用 startLecture / pauseLecture / goToLectureByName |
| 4 | 实现讲房入口、控制条、进度条、讲房时的遮罩等 UI |
| 5 | 监听 connect_ui_operation,在讲房过程中显隐地图、小区图、周边配套等 |
以下按步骤展开。
三、第一步:判断模型是否支持讲房
时机:在 housePlay.on('init_UI', ...) 回调中执行。
做法:从 housePlay.model.settings.vr_speak_data 判断是否存在且为非空对象。若是,则当前模型支持讲房。
housePlay.on('init_UI', function(model) {
// model 即 housePlay.model,可从 model.settings 读取配置
let settings = model.settings || {};
let vrSpeakData = settings.vr_speak_data;
let hasLecture = vrSpeakData && typeof vrSpeakData === 'object' && Object.keys(vrSpeakData).length > 0;
if (hasLecture) {
// 在你的应用里:显示「AI 讲房」入口,并初始化讲房段落列表(见下)
yourApp.setLectureAvailable(true);
yourApp.initLectureSegmentList(vrSpeakData); // 可选:用 vrSpeakData 解析自定义段落,或使用固定 4 段
}
});
段落列表建议:SDK 按「场景名」切换,固定为以下 4 段(顺序可自定),你只需维护「展示名 + 传给 SDK 的名称」的映射:
| 展示名(可自定义) | 传给 SDK 的名称(必须一致) |
|---|---|
| 小区内部 | uptown_inside |
| 周边配套 | uptown_outside |
| 户型解析 | house_parse |
| 房源信息 | house_info |
列表末尾可加一项「退出讲房」,仅用于关闭面板并暂停,不传 SDK。
四、第二步:准备讲房状态与段落数据
建议在你自己项目中维护至少以下状态(名称可自定):
| 状态 | 含义 | 建议更新方式 |
|---|---|---|
| 讲房是否可用 | 当前模型是否有讲房数据 | 仅在 init_UI 中根据 vr_speak_data 设置 |
| 讲房面板是否显示 | 是否打开讲房控制条/浮层 | 用户点击入口时设为 true,点击退出时设为 false |
| 是否正在播放 | 与 SDK 实际播放状态一致 | 仅由 SDK 事件回调更新,避免与 SDK 不同步 |
| 当前段落索引 | 0~3 对应四段,或你的列表 index | 由 lectureUpdate 第一参数或用户点击段落时更新 |
| 当前段落进度 | 0–100,用于进度条 | 由 lectureUpdate 第二参数更新 |
段落数据结构示例(便于你渲染列表并调用 goToLectureByName):
const defaultSegments = [
{ name: '小区内部', lectureName: 'uptown_inside' },
{ name: '周边配套', lectureName: 'uptown_outside' },
{ name: '户型解析', lectureName: 'house_parse' },
{ name: '房源信息', lectureName: 'house_info' }
];
// 可再 push 一项 { name: '退出讲房', lectureName: null } 用于关闭面板
五、第三步:注册 SDK 事件并同步到你的状态
在 housePlay 可用后(例如在 zqsdk.init 的 complete 里 housePlay.start() 之后),注册以下讲房事件,并仅在这些回调中更新「是否正在播放」「当前段落索引」「当前段落进度」。
// 讲房进度更新:第一参数为当前段落 index 或 playStyle,第二参数为当前段落内进度百分比
housePlay.on('lectureUpdate', function(playStyleOrIndex, percent) {
yourApp.setLectureProgress(typeof percent === 'number' ? percent : 0);
if (typeof playStyleOrIndex === 'number' && playStyleOrIndex >= 0) {
yourApp.setCurrentSegmentIndex(playStyleOrIndex);
}
});
// 讲房场景切换:playStyle 为新段落名称(如 'uptown_outside')
housePlay.on('lectureNextPlayStyle', function(playStyle) {
yourApp.setCurrentSegmentByPlayStyle(playStyle);
yourApp.setLectureProgress(0); // 切换段落时重置进度
});
// 讲房暂停
housePlay.on('lecturePause', function() {
yourApp.setLecturePlaying(false);
});
// 讲房结束
housePlay.on('lectureEnd', function() {
yourApp.setLecturePlaying(false);
yourApp.hideLecturePanel(); // 可选:自动关闭面板
});
注意:不要在用户点击「播放」时仅本地把「是否正在播放」设为 true 而不调 SDK;应先调 SDK,再由上述事件回写状态,以保证与 SDK 一致。
六、第四步:在用户操作时调用 SDK 方法
SDK 提供三个与讲房相关的方法(均在 housePlay 上调用):
| 方法 | 说明 | 调用时机建议 |
|---|---|---|
housePlay.startLecture() |
开始或继续讲房 | 用户点击「开始讲房」或控制条上的「播放」 |
housePlay.pauseLecture() |
暂停讲房 | 用户点击「暂停」或「退出讲房」 |
housePlay.goToLectureByName(name) |
跳转到指定段落 | 在开始/继续播放前先跳段,再调用 startLecture() |
推荐交互逻辑:
- 用户点击「AI 讲房」入口:显示讲房面板 → 将本地「当前选中段」设为 0(或保持上次)→ 调用
housePlay.startLecture()(若希望从第一段开始,可先goToLectureByName('uptown_inside')再startLecture())。 - 用户点击控制条「播放」:若当前有选中段落且非「退出」,先
goToLectureByName(当前段的 lectureName),再startLecture();否则仅startLecture()。 - 用户点击「暂停」:仅调用
pauseLecture();播放状态由事件lecturePause/lectureEnd回写。 - 用户点击某一段落:
- 若当前为暂停:只更新你本地的「当前选中段」和进度条置 0,不调 SDK。
- 若当前为播放:先
goToLectureByName(该段 lectureName),再startLecture()。 - 用户点击「退出讲房」:调用
pauseLecture(),并关闭讲房面板、重置本地展示状态。
这样可避免「暂停时误触 SDK」导致状态错乱。
七、第五步:实现讲房 UI
UI 完全由你自定义,只需满足功能对应关系即可。
7.1 建议具备的 UI 元素
- 讲房入口
- 显示条件:SDK 已就绪且当前模型
vr_speak_data存在(即「讲房可用」为 true),且讲房面板未打开。 -
点击:打开讲房面板,并调用
startLecture()(必要时先goToLectureByName再startLecture)。 -
讲房控制条/浮层
- 显示条件:讲房面板已打开。
-
内容建议:
- 播放/暂停按钮 → 对应
startLecture/pauseLecture,且播放时若需从当前段开始则先goToLectureByName; - 段落列表(4 段 + 可选「退出讲房」)→ 点击段落时按「第四步」逻辑处理;
- 当前段进度条 → 绑定「当前段落进度」状态(0–100)。
- 播放/暂停按钮 → 对应
-
讲房播放时的画布遮罩(推荐)
-
当「讲房面板已打开且正在播放」时,在 3D/全景画布上盖一层透明遮罩(
pointer-events: auto),避免用户误触旋转/漫游;讲房控制条置于遮罩之上并可点击。这样体验更稳定。 -
讲房模式下的其他 UI
- 可根据需要隐藏底部栏、右侧面板、导览入口等,仅保留讲房相关控件,避免与讲房控制条重叠。
7.2 可选:顶部房源标题
若你有房源名称,可在讲房面板打开时在顶部居中展示,提升识别度;数据来源由你业务决定(如从 vr_speak_data.settings 或房源接口获取)。
八、第六步:讲房过程中显示地图、小区图、周边配套
讲房播放到某些段落时,SDK 会通过事件 connect_ui_operation 下发「要显示/隐藏的 UI」,用于在讲房过程中自动弹出或关闭地图、小区图、房源详情等。
8.1 监听方式
housePlay.on('connect_ui_operation', function(action) {
if (!action || action.type !== 'UI_OPERATION' || !action.data) return;
if (action.data.type !== 'UI') return;
let target = action.data.target; // 要控制的 UI 目标
let show = action.data.action; // true 显示,false 隐藏(或其他数据)
switch (target) {
case 'houseInfo': // 房源详情(可包含地图、小区图、房源信息等)
yourApp.toggleHouseInfoPanel(show);
break;
case 'bigMap': // 大地图
yourApp.toggleBigMap(show);
break;
case 'imgSwiper': // 小区图片轮播
yourApp.toggleCommunityImageSwiper(show);
break;
case 'bigHangpai': // 大航拍
yourApp.toggleBigHangpaiPanel(show);
break;
case 'mapSearchItemIndex': // 周边配套 POI 数据
yourApp.setMapSearchData(show);
break;
// 其他 target 按需处理
}
});
8.2 数据来源
讲房所需的地图、小区图等数据通常来自模型配置。可在 init_UI 或房源数据加载时,将 housePlay.model.settings.vr_speak_data.settings 中与 UI 相关的字段(如 communityImages、address、panoramaLink 等)合并到你自己的房源/详情数据中,再在收到 connect_ui_operation 时根据 target 显示对应组件。
8.3 周边配套 POI 数据(mapSearchItemIndex)
当讲房进入「周边配套」段落时,SDK 会通过 connect_ui_operation 下发 mapSearchItemIndex 数据,包含当前分类的 POI(兴趣点)列表,用于在地图上展示周边学校、地铁、公交、购物中心、医院、公园、菜市场等配套设施。
8.3.1 数据结构
// action.data 结构
{
type: 'UI',
target: 'mapSearchItemIndex',
action: {
name: '学校', // 分类名称:学校 | 地铁 | 公交 | 购物中心 | 医院 | 公园 | 菜市场
poi: [
{
name: 'XX小学', // POI 名称
title: 'XX小学', // POI 标题(可能与 name 相同)
lng: 116.404, // 经度
lat: 39.915, // 纬度
location: { lng, lat }, // 坐标(部分版本使用此字段)
distance: 500, // 距离房源的距离(米)
address: 'XX路XX号' // 地址(可选)
},
// ... 更多 POI
]
}
}
注意:SDK 下发的分类名称可能是具体类型(如 "初中"、"小学"),需要映射到标准分类(如 "学校")。
8.3.2 分类名称映射
SDK 可能下发的分类名称与标准分类的映射关系:
| SDK 下发名称 | 标准分类 |
|---|---|
| 幼儿园、小学、初中、高中、大学 | 学校 |
| 地铁、地铁站 | 地铁 |
| 公交、公交站 | 公交 |
| 购物、商场、超市 | 购物中心 |
| 医院、诊所、卫生院 | 医院 |
| 公园、绿地、广场 | 公园 |
| 菜市场、菜场、农贸市场、生鲜 | 菜市场 |
// 分类名称映射函数示例
function normalizeMapSearchCategory(name) {
const schoolTypes = ['幼儿园', '小学', '初中', '高中', '大学', '学校'];
if (schoolTypes.includes(name)) return '学校';
if (name.includes('地铁')) return '地铁';
if (name.includes('公交')) return '公交';
if (name.includes('购物') || name.includes('商场') || name.includes('超市')) return '购物中心';
if (name.includes('医院') || name.includes('诊所')) return '医院';
if (name.includes('公园') || name.includes('绿地')) return '公园';
if (name.includes('菜市场') || name.includes('农贸')) return '菜市场';
return name; // 已是标准分类则直接返回
}
8.3.3 监听与处理
housePlay.on('connect_ui_operation', function(action) {
if (!action || action.type !== 'UI_OPERATION' || !action.data) return;
if (action.data.type !== 'UI') return;
let target = action.data.target;
let data = action.data.action;
switch (target) {
// ... 其他 target 处理
case 'mapSearchItemIndex':
// 周边配套 POI 数据
if (data && typeof data === 'object' && data.name && data.poi) {
let rawCategoryName = data.name;
let normalizedCategory = normalizeMapSearchCategory(rawCategoryName);
yourApp.setMapSearchData({
rawName: rawCategoryName, // 原始名称(用于显示)
normalizedName: normalizedCategory, // 标准分类(用于索引)
poi: data.poi.map(function(item) {
return {
name: item.name || item.title,
lng: item.lng || (item.location && item.location.lng),
lat: item.lat || (item.location && item.location.lat),
distance: item.distance || 0,
address: item.address || ''
};
}).sort(function(a, b) {
return (a.distance || 0) - (b.distance || 0); // 按距离排序
})
});
}
break;
}
});
8.3.4 状态管理建议
建议在你的应用中维护以下周边配套相关状态:
| 状态 | 含义 | 说明 |
|---|---|---|
mapSearchCurrentIndex |
当前分类索引 | 0-6 对应:学校、地铁、公交、购物中心、医院、公园、菜市场 |
mapSearchCurrentName |
当前分类名称 | 如 "学校"、"地铁" 等 |
mapSearchCurrentPoi |
当前分类的 POI 列表 | 数组,包含 name、lng、lat、distance 等 |
mapSearchCategoriesData |
所有分类的 POI 缓存 | 对象,key 为标准分类名,value 为 POI 数组 |
// 分类常量
const MAP_SEARCH_CATEGORIES = ['学校', '地铁', '公交', '购物中心', '医院', '公园', '菜市场'];
// 设置 POI 数据
function setMapSearchData(data) {
let rawCategoryName = data.rawName;
let normalizedCategory = data.normalizedName;
let poiList = data.poi;
// 使用标准分类名缓存数据
mapSearchCategoriesData[normalizedCategory] = poiList;
// 更新当前分类(显示原始名称便于用户理解)
mapSearchCurrentName = rawCategoryName;
mapSearchCurrentPoi = poiList;
mapSearchCurrentIndex = MAP_SEARCH_CATEGORIES.indexOf(normalizedCategory);
}
// 切换分类(用户手动切换时)
function switchMapSearchCategory(index) {
let categoryName = MAP_SEARCH_CATEGORIES[index];
let cachedData = mapSearchCategoriesData[categoryName];
mapSearchCurrentIndex = index;
mapSearchCurrentName = categoryName;
mapSearchCurrentPoi = cachedData || [];
}
8.3.5 地图 UI 实现建议
周边配套地图建议包含以下 UI 元素:
- 地图主体
- 显示房源位置(中心标记点)
- 显示当前分类的 POI 标记
-
POI 数据更新时自动显示第一个 POI 的步行路径
-
分类切换栏(底部或顶部)
- 7 个分类按钮:学校、地铁、公交、购物中心、医院、公园、菜市场
- 高亮当前分类
-
点击切换分类,更新地图上的 POI 标记
-
POI 列表侧边栏(可选)
- 显示当前分类的 POI 列表
- 每项显示名称和距离
-
点击可定位到该 POI 并显示步行路径
-
步行路径
- POI 数据更新时,自动显示第一个 POI 的步行路线
- 点击 POI 时,切换显示该 POI 的步行路线
- 使用百度地图
WalkingRouteAPI 实现
// 百度地图步行路径示例
let walkingRoute = new BMap.WalkingRoute(map, {
renderOptions: { map: map, autoViewport: false }
});
// 显示步行路径
function showWalkingRoute(poi) {
walkingRoute.clearResults();
let start = new BMap.Point(houseLng, houseLat); // 房源坐标
let end = new BMap.Point(poi.lng, poi.lat); // POI 坐标
walkingRoute.search(start, end);
}
// POI 数据更新时自动显示第一个 POI 的路径
function renderPoiMarkers(poiList) {
// ... 渲染 POI 标记 ...
// 自动显示第一个 POI 的步行路径
if (poiList.length > 0) {
showWalkingRoute(poiList[0]);
}
}
九、API 速查表
9.1 方法(housePlay)
| 方法 | 说明 |
|---|---|
housePlay.startLecture() |
开始/继续讲房 |
housePlay.pauseLecture() |
暂停讲房 |
housePlay.goToLectureByName(name) |
跳转到指定段落;name 取值:uptown_inside | uptown_outside | house_parse | house_info |
9.2 事件(housePlay.on)
| 事件 | 回调参数 | 说明 |
|---|---|---|
lectureUpdate |
(playStyleOrIndex, percent) |
进度更新;第一参数为段落 index 或 playStyle 字符串,第二参数为 0–100 百分比 |
lectureNextPlayStyle |
(playStyle) |
场景切换;playStyle 为新段落名称(如 uptown_outside) |
lecturePause |
无 | 讲房暂停 |
lectureEnd |
无 | 讲房结束 |
lecture |
(state) |
旧版;state === 'stop' 表示停止 |
connect_ui_operation |
(action) |
讲房过程中显隐 UI;action.data.target 与 action.data.action 见下表 |
9.3 connect_ui_operation target 速查
| target | action 类型 | 说明 |
|---|---|---|
houseInfo |
boolean |
房源详情面板显隐 |
bigMap |
boolean |
大地图显隐 |
imgSwiper |
boolean |
小区图片轮播显隐 |
bigHangpai |
boolean |
大航拍面板显隐 |
houseInfoSwiper |
boolean |
房源信息轮播自动播放 |
initHouseInfoSwiper |
number |
房源信息轮播初始索引 |
mapSearchItemIndex |
{ name, poi[] } |
周边配套 POI 数据(见 8.3 节) |
9.4 判断讲房是否可用
- 在
init_UI中读取:housePlay.model.settings.vr_speak_data,存在且为非空对象即表示支持讲房。
十、常见问题与注意事项
-
务必在事件回调中更新「是否正在播放」
不要只在点击播放时本地设为 true;否则 SDK 暂停或出错时,你的 UI 会与真实状态不一致。应以lecturePause、lectureEnd为准。 -
暂停时切换段落不要调 SDK
用户暂停后点击其他段落,只更新你本地的「当前选中段」和进度条;等用户再次点击「播放」时再goToLectureByName+startLecture,避免多余调用。 -
先 goToLectureByName 再 startLecture
若希望「从指定段开始播放」,请先调用goToLectureByName(lectureName),再调用startLecture()。 -
方法是否存在
部分环境或旧版 SDK 可能未暴露startLecture/pauseLecture/goToLectureByName,调用前可用housePlay.startLecture != null等方式做兼容。 -
与导览的关系
讲房与导览相互独立;同一模型可同时有导览和讲房,分别用heroLocations和vr_speak_data判断即可。 -
周边配套分类名称映射
SDK 下发的分类名称可能是具体类型(如 "初中"),需要映射到标准分类(如 "学校")后再进行索引和缓存,确保分类切换栏正确高亮。 -
周边配套路径自动显示
当 POI 数据更新时,建议自动显示第一个 POI 的步行路径,提升用户体验。
十一、本仓库实现参考
若需参考本仓库的完整实现(Vue 3 + Pinia + TypeScript),可参阅:
11.1 核心文件
| 文件 | 说明 |
|---|---|
src/stores/introduce.ts |
讲房状态管理(段落、进度、POI、面板显隐等) |
src/stores/vr.ts |
SDK 事件监听与分发(lectureUpdate、connect_ui_operation 等) |
src/types/lecture.ts |
讲房相关类型定义(MapSearchPoiItem、MapSearchData、normalizeMapSearchCategory 等) |
11.2 UI 组件
| 文件 | 说明 |
|---|---|
src/modules/pc/introduce/NestIntroduceBtn.vue |
讲房入口按钮 |
src/modules/pc/introduce/NestIntroducePanel.vue |
讲房控制面板(段落列表、进度条、播放/暂停) |
src/modules/pc/introduce/NestIntroduceOverlay.vue |
讲房播放遮罩 |
src/modules/pc/introduce/NestIntroduceActionPanel.vue |
讲房弹出 UI 容器 |
11.3 讲房弹出面板
| 文件 | 说明 |
|---|---|
src/modules/pc/introduce/NestLectureBigMap.vue |
讲房大地图(含周边配套 POI) |
src/modules/pc/introduce/NestLectureImgSwiper.vue |
讲房图片轮播 |
src/modules/pc/introduce/NestLectureBigHangpai.vue |
讲房航拍面板 |
src/modules/pc/introduce/NestLectureHouseInfo.vue |
讲房房源信息 |
11.4 公共组件
| 文件 | 说明 |
|---|---|
src/components/common/pc/NestModalMap.vue |
通用地图组件(支持 POI 标记、分类切换、步行路径) |
src/components/common/pc/NestModalImgSwiper.vue |
通用图片轮播组件 |
src/components/common/pc/NestHouseInfo.vue |
通用房源信息组件 |
11.5 布局入口
| 文件 | 说明 |
|---|---|
src/layouts/pc/PcHouseLayout.vue |
PC 端布局(讲房组件挂载点) |
十二、 离线数据包目录位置与资源替换
众趣推送的离线数据包中,会存在AI讲房相关资源内容,如讲房音频等资源。资源目录放置在 {{model_id}}/audio/目录下。
替换目录:
模型版本目录
- settings.txt (单个文件)
- settings_local.txt (单个文件)
模型id目录
- audio (整个目录)
截图示意
{{模型id}}/audio目录

{{模型版本}}/setting.txt 和 setting_local.txt
