#端云一体化开发# #HarmonyOS Next#《说书人》鸿蒙原生基于角色的对话式文本编辑开发方案

1、写在前面

过去的一百年里,在“编程”的这个行业诞生之初,人们采用面向过程的方式进行开发,但是,伴随着程序规模的日益增大,程序的复杂度也随之增加,使用结构化编程方法来管理复杂的程序逻辑变得越来越困难。因此,开发者们引入了“面向对象”的概念,采用将数据和操作封装在“对象”中的方式,令程序设计更加条理。

而现如今,市场上的文本类软件越来越多,创作者的门槛越来越低,无数文字作品争相涌现,长篇小说的字数也不断突破记录,可是,对于一个经验不够丰富的创作者而言,常常会发生文章内容跑偏,角色性格无法把握的问题,特别是在小说文字长度越来越长时,这样的问题便愈发严重。而在这样的情况下,我决定仿照“面向对象”的方式,开发一款基于“角色”定义,进行剧本编写的软件,帮助文字创作者们能够基于“角色”来编写文章,提高创作的效率与质量。

在选择开发平台时,我们注意到鸿蒙平台上还没有基于对话式的文本类APP,这使得我在实现基本功能的同时,还可以在这方面填充市场的空缺。此外,我也希望能够参与鸿蒙生态建设,助力国产科技企业发展,成为openHarmony漫天星光中的一员。

综上,我们决定开发一个鸿蒙原生的,基于角色定义的对话式文本编写软件,以达到解决市场空缺,解决用户需求的目的。

本文就是分享《说书人》的一部分鸿蒙技术实践过程,欢迎各位阅读

cke_13418.png

2、路由展示

2.1、页面展示

《说书人》的界面十分简洁,主要的界面包括:角色/剧本列表,用户空间,动态空间,以及阅读界面等,如下图所示

2.2、路由展示

(1)Tabs组件简介

Tabs组件的页面组成包含两个部分,分别是TabContent和TabBar。TabContent是内容页,TabBar是导航页签栏,页面结构如下图所示,根据不同的导航类型,布局会有区别,可以分为底部导航、顶部导航、侧边导航,其导航栏分别位于底部、顶部和侧边。

Tabs组件的实践

《说书人》的角色/书本列表,动态空间,个人页面,主要分为UserSpacePage,scriptInterface和DynamicPage三个组件,结合Tabs组件,进行页面布局,如下列代码所示:

import { frame, frameDataSet, ThisPagefontColor } from '../Data/frameData'
import { userOwnData, userOwn, userTheyData, userTheyTemplate } from '../Data/userData'import UserSpacePage from './mainPage/userSpacePage'
import scriptInterface from './mainPage/scriptPage'
import DynamicPage from './mainPage/dynamicPage'
import router from '@ohos.router'@Entry
@Component
struct UserSpace {aboutToAppear(): void {let params = router.getParams() as Record<string, number>this.pageIndex = params['goPageIndex']}@StorageProp('frame') frameData: frame = frameDataSet@StorageProp('fontColor') ThisColor: ResourceColor = ThisPagefontColor@StorageProp('userOwnData') userOwn: userOwnData = userOwn@StorageProp('userTheyData') userTheyData: userTheyTemplate = userTheyData@State pageIndex: number = 0build() {Flex(){Tabs({index: this.pageIndex == undefined ? 0 : this.pageIndex,}){TabContent(){scriptInterface()}.tabBar('推荐')TabContent(){DynamicPage()}.tabBar('动态')TabContent(){UserSpacePage()}.tabBar('空间')}.barPosition(BarPosition.End)}.backgroundColor(this.frameData.backGround)}
}复制

3、端云一体化的实践应用

在本项目中,接入了华为云提供的认证服务与数据库服务,将AGC的serverless云和HarmonyOS的端进行结合开发,以下是开发示例

1、登录AppGallery Connect

2、在全部服务中,选择“认证服务”,启动手机号码认证

3、我的项目中,添加项目,再选择添加应用,随后根据实际情况填写即可

4、在“项目设置”中,下载SDK配置,并放在自己项目的如图所示的目录中

5、修改oh-package.json5文件,添加以下内容

"dependencies": { "@hw-agconnect/hmcore": "^1.0.1", "@hw-agconnect/cloud": "^1.0.1" }复制复制复制

6、修改EntryAbility.ets文件,在onCreate中添加以下内容

async onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {let input = await this.context.resourceManager.getRawFileContent('agconnect-services.json')let jsonString  = util.TextDecoder.create('utf-8', {ignoreBOM: true}).decodeWithStream(input, {stream: false});initialize(this.context, JSON.parse(jsonString));
}复制复制复制

7、打开需要使用验证码的界面,导入代码

// 导入
import cloud from '@hw-agconnect/cloud';
import { Auth, VerifyCodeAction } from '@hw-agconnect/cloud';
import { promptAction } from '@kit.ArkUI';// 申请验证码
function requestVerifyCode(phoneNumber: string){cloud.auth().requestVerifyCode({action: VerifyCodeAction.REGISTER_LOGIN,lang: 'zh_CN',sendInterval: 60,verifyCodeType: {phoneNumber: phoneNumber,countryCode: '86',kind: "phone"}}).then(verifyCodeResult => {//验证码申请成功promptAction.showToast({message: '申请成功'})}).catch(() => {//验证码申请失败promptAction.showToast({message: "申请失败 "})});
}// 注册用户
function createUser(phoneNumber: string, phoneCode: string){cloud.auth().createUser({kind: 'phone',countryCode: '86',phoneNumber: phoneNumber,password: '123456789',//可以给用户设置初始密码,后续可以用密码来登录verifyCode: phoneCode}).then(result => {// 创建用户成功promptAction.showToast({message: '创建成功'})}).catch(() => {// 创建用户失败promptAction.showToast({message: '创建失败'})})
}复制

 以上是手机号部分的开发流程,数据库部分也与其相似,可以在AGC官网查看文档进行开发

4、角色/剧本创建部分

对于角色/剧本的创建,总是会遇见需要“多维数组”等云数据库默认无法实现的情况,这种情况下,就采用分隔符来对数据进行处理,以字符串类型存储在云端,再在本地读取时进行反处理

角色创建部分如下:

import { frame, frameDataSet,ThisPagefontColor, frameData } from '../../Data/frameData'
import { userOwnData, userOwn } from '../../Data/userData'
import { roleDataTemplate, roleData, roleCustom } from '../../Data/roleData'
import router from '@ohos.router';import EntryPage from '../popUp/EntryPage'
import CarePage from '../popUp/CarePage'
import DelCarePage from '../popUp/DelCarePage'
import closePage from '../popUp/closePage'import promptAction from '@ohos.promptAction';@Extend(Text) function textCare(size: number){.fontColor('#3c3f41').backgroundColor('#e0dcda').fontSize(size).fontWeight(300).padding({left: 8,right: 8,top: 5,bottom: 5}).borderRadius(12).opacity(.8)
}@Entry
@Component
struct UserCreate {entryPageOpen: CustomDialogController = new CustomDialogController({builder: EntryPage({onCancel: (Name: string, Value: string) => {this.roleCustom.push({name: Name,value: Value})}})})carePageOpen: CustomDialogController = new CustomDialogController({builder: CarePage({onCancel: (Value: string) => {this.roleLabel.push(Value)}})})delcarePageOpen: CustomDialogController = new CustomDialogController({builder: DelCarePage({onCancel: (Value: boolean) => {if (Value) {this.roleLabel.splice(this.delRoleIndex, 1)}},})})closeOpen: CustomDialogController = new CustomDialogController({builder: closePage({onCancel: () => {this.roleData = roleDatathis.newRoleData = this.roleDatathis.roleData.createUserID = this.userOwn.userIDthis.roleData.createUserName = this.userOwn.userNamerouter.pushUrl({"url": "pages/Main/userSpace","params": {"goPageIndex" : 0}})},})})@StorageProp('frame') frameData: frame = frameDataSet@StorageProp('fontColor') ThisColor: ResourceColor = ThisPagefontColor@StorageProp('userOwnData') userOwn: userOwnData = userOwn@StorageLink('roleData') roleData: roleDataTemplate = roleData@State newRoleData: roleDataTemplate = this.roleData@State openText: boolean = false@State roleCustom: roleCustom[] = []@State roleLabel: string[] = this.newRoleData.roleLabel@State delRoleIndex: number = 0loadRoleData(){this.roleData = this.newRoleDatathis.roleData.roleLabel = this.roleLabelthis.roleData.createUserID = this.userOwn.userIDthis.roleData.createUserName = this.userOwn.userNamefor (let index = 0; index < this.roleCustom.length; index++) {this.roleData.roleCustomName.push(this.roleCustom[index].name)this.roleData.roleCustomValue.push(this.roleCustom[index].value)}router.pushUrl({"url": "pages/dynamicSystem/previewPage/userPreviewPage"})}build() {Flex({wrap: FlexWrap.Wrap}){Column({ space: 24 }){// 标题Row(){frameData().width(50)Text('角色').fontSize(this.frameData.typefaceSize + 8).fontColor(this.ThisColor)Text('').width(50)}.width('100%').justifyContent(FlexAlign.SpaceBetween)Scroll(){Column({ space: 24 }){// 封面标题作者标签IDRow({space: 16}){Text(String(this.newRoleData.roleName == '' ? '角色名称' : this.newRoleData.roleName).slice(String(this.newRoleData.roleName == '' ? '角色名称' : this.newRoleData.roleName).length - 2, String(this.newRoleData.roleName == '' ? '角色名称' : this.newRoleData.roleName).length)).fontSize(18).width(120).height(120).borderRadius(60).backgroundColor(this.frameData.backGround).border({width: 1}).textOverflow({overflow: TextOverflow.Ellipsis}).padding(2).textAlign(TextAlign.Center).letterSpacing(3)Column({ space: 9 }){// 角色昵称Row(){Text(this.newRoleData.roleName == '' ? '角色名称' : this.newRoleData.roleName).fontSize(this.frameData.typefaceSize + 6).fontColor(this.ThisColor).fontWeight(600)}// IDRow(){Text(this.newRoleData.roleAge.toString()).fontSize(this.frameData.typefaceSize - 4).fontColor(Color.Gray).fontWeight(400)}// 作者Row({ space: 6 }){Text(String(this.userOwn.userName).slice(String(this.userOwn.userName).length - 2, String(this.userOwn.userName).length)).fontSize(8).width(28).height(28).borderRadius(14).backgroundColor(this.frameData.backGround).border({width: 1}).textOverflow({overflow: TextOverflow.Ellipsis}).padding(2).textAlign(TextAlign.Center)Text(this.userOwn.userName).fontSize(this.frameData.typefaceSize - 2).fontColor(Color.Gray)}// 标签Flex({wrap: FlexWrap.Wrap,justifyContent: FlexAlign.Start}){ForEach(this.roleLabel, (item: string) => {Text(item).textCare(this.frameData.typefaceSize - 3).margin({right: 2,bottom: 2})})}}.width('100%').alignItems(HorizontalAlign.Start).height(120)}// 简介Column({ space: 12 }){Text('简介').fontSize(this.frameData.typefaceSize + 4).fontColor(this.ThisColor).fontWeight(600)Row(){Text(`${this.newRoleData.roleBrief}`).maxLines(this.openText ? 999 : 4).textOverflow({overflow: this.openText ? TextOverflow.None : TextOverflow.Ellipsis }).fontSize(this.frameData.typefaceSize).fontColor(this.ThisColor)}.width('100%')Row(){Text(this.openText ? '收起' : '展开').fontSize(this.frameData.typefaceSize - 2).fontColor(this.ThisColor).fontWeight(300).onClick(() => {this.openText = !this.openText})}.width('100%')}.width('100%').alignItems(HorizontalAlign.Start)// 详细档案Column(){Row(){Text('详细档案').fontSize(this.frameData.typefaceSize + 4).fontColor(this.ThisColor).fontWeight(600)}.width('100%').justifyContent(FlexAlign.SpaceBetween).border({width: {bottom: 2}}).padding({bottom: 6})// 详细档案中的档案Column(){// 词条Column(){// 姓名Row(){Text('姓名:').fontSize(this.frameData.typefaceSize + 2).fontColor(this.ThisColor).fontWeight(500)TextInput({ placeholder: this.newRoleData.roleName == '' ? '请输入角色姓名' : this.newRoleData.roleName }).width('100%').backgroundColor(this.frameData.backGround).borderRadius(0).border({width:{bottom: 1},color: this.ThisColor}).fontColor(this.ThisColor).placeholderColor(this.ThisColor).fontSize(this.frameData.typefaceSize + 2).maxLength(16).onChange(value => {this.newRoleData.roleName = value})}.width('100%').justifyContent(FlexAlign.SpaceBetween).padding({left: 12,right: 12,top: 12,bottom: 12})// 年龄Row(){Text('年龄:').fontSize(this.frameData.typefaceSize + 2).fontColor(this.ThisColor).fontWeight(500)TextInput({ placeholder: this.newRoleData.roleAge == '0' ? '请输入角色年龄' : this.newRoleData.roleAge.toString()}).width('100%').backgroundColor(this.frameData.backGround).borderRadius(0).border({width:{bottom: 1},color: this.ThisColor}).fontColor(this.ThisColor).placeholderColor(this.ThisColor).fontSize(this.frameData.typefaceSize + 2).maxLength(8).type(InputType.Number).onChange(value => {this.newRoleData.roleAge = value})}.width('100%').justifyContent(FlexAlign.SpaceBetween).padding({left: 12,right: 12,top: 12,bottom: 12})// 性别Row(){Text('性别:').fontSize(this.frameData.typefaceSize + 2).fontColor(this.ThisColor).fontWeight(500)TextInput({ placeholder: this.newRoleData.roleGender == '' ? '请输入角色性别' : this.newRoleData.roleGender }).width('100%').backgroundColor(this.frameData.backGround).borderRadius(0).border({width:{bottom: 1},color: this.ThisColor}).fontColor(this.ThisColor).placeholderColor(this.ThisColor).fontSize(this.frameData.typefaceSize + 2).maxLength(6).onChange(value => {this.newRoleData.roleGender = value})}.width('100%').justifyContent(FlexAlign.SpaceBetween).padding({left: 12,right: 12,top: 12,bottom: 12})ForEach(this.roleCustom, (item: roleCustom, index: number) => {// 姓名Row(){Text(item.name + ':').fontSize(this.frameData.typefaceSize + 2).fontColor(this.ThisColor).fontWeight(500).textAlign(TextAlign.End).width('17%')Row(){TextInput({ placeholder: '请输入角色姓名', text: item.value }).width('71%').backgroundColor(this.frameData.backGround).borderRadius(0).border({width:{bottom: 1},color: this.ThisColor}).fontColor(this.ThisColor).placeholderColor(this.ThisColor).fontSize(this.frameData.typefaceSize + 2).maxLength(16)Text('删除').onClick(() => {this.roleCustom.splice(index, 1)}).textAlign(TextAlign.End).width(50)}}.width('100%').justifyContent(FlexAlign.SpaceBetween).padding({left: 12,right: 12,top: 12,bottom: 12})})Row(){Button('添加自定义词条').border({width: 1}).backgroundColor(this.frameData.backGround).fontColor(this.ThisColor).width('100%').onClick(() => {this.entryPageOpen.open()})}.width('100%').padding({left: 12,right: 12,top: 12,bottom: 12})}// 标签Flex({wrap: FlexWrap.Wrap,justifyContent: FlexAlign.SpaceAround}){ForEach(this.roleLabel, (item: string, index) => {Row(){Button(item).border({width: 1}).backgroundColor(this.frameData.backGround).fontColor(this.ThisColor).width('45%').onClick(() => {this.delRoleIndex = indexthis.delcarePageOpen.open()})}.padding({left: 12,right: 12,top: 12,bottom: 12})})Row(){Button('添加角色标签').border({width: 1}).backgroundColor(this.frameData.backGround).fontColor(this.ThisColor).width('45%').onClick(() => {this.carePageOpen.open()})}.padding({left: 12,right: 12,top: 12,bottom: 12})}.width('100%')// 剧本Column({ space: 6 }){Row(){Text('角色简介:').fontSize(this.frameData.typefaceSize + 4).fontColor(this.ThisColor).fontWeight(600)}.width('100%').padding({bottom: 6})// 简介Row(){TextArea({ placeholder: '请输入角色简介'}).width('100%').height(120).padding(16).fontSize(this.frameData.typefaceSize + 2).fontColor(this.ThisColor).fontWeight(500).onChange(value => {this.newRoleData.roleBrief = value}).maxLength(200)}.width('100%')}}}.width('100%').alignItems(HorizontalAlign.Center)}.alignItems(HorizontalAlign.Start)}.edgeEffect(EdgeEffect.Spring).scrollBar(BarState.Off).height('85%')Row(){Button('预览').fontSize(this.frameData.typefaceSize + 2).fontColor(this.ThisColor).backgroundColor(this.frameData.backGround).width('50%').padding({top: 16,bottom: 16}).onClick(() => {this.loadRoleData()})Button('取消').fontSize(this.frameData.typefaceSize + 2).fontColor(this.ThisColor).backgroundColor(this.frameData.backGround).width('50%').padding({top: 16,bottom: 16}).onClick(() => {this.closeOpen.open()})}.width('100%').justifyContent(FlexAlign.SpaceAround).alignItems(VerticalAlign.Center).border({width: {top: 2}})}.padding({top: 16,left: 24,right: 24,bottom: 16}).height('100%')}}
}复制

5、总结

说书人APP是一款基于鸿蒙平台开发的原生应用,旨在通过角色定义的方式提高文字创作的效率与质量。

不仅填补了市场上对话式文本类APP的空缺,而且通过华为端云一体化开发,接入了短信认证服务和云数据库,确保了应用的高兼容性、稳定性、低功耗和高性能。

项目背景与目标:随着市场上文本创作软件的增多,创作者面临的挑战也随之增加,尤其是对于经验不足的创作者而言,如何有效管理角色和剧情成为一大难题。说书人APP应运而生,目的是帮助这些创作者通过“面向对象”的方式编写剧本,从而提高创作效率和作品质量。

技术实现:应用采用了华为的端云一体化开发模式,利用DevEco Studio进行编译运行,并支持API version 9版本SDK,确保了应用的技术先进性和安全性。

功能特色:包括注册登录系统、文章创建与编辑、章节管理、角色创建与自定义、以及用户个性化设置等,全面满足文字创作者的需求。特别是其基于角色的对话式编写功能,为创作者提供了全新的创作体验。

优势方面

技术创新:作为鸿蒙平台上的原生应用,说书人APP在技术上具有天然的优势,包括更好的系统兼容性和性能优化。 用户体验:通过角色定义的创作方式,简化了复杂的剧情管理,使得创作者可以更加专注于内容的创作。

生态贡献:参与鸿蒙生态建设,不仅丰富了应用市场的多样性,也为国产科技企业的发展贡献了一份力量。

需要改进的地方

用户引导:对于新用户来说,应用的功能可能较为复杂,需要更加直观的用户引导和教程来帮助用户快速上手。

社交互动:虽然应用提供了丰富的创作工具,但在社交互动方面似乎有所欠缺。增加创作者之间的交流和合作功能,可能会进一步提升用户的活跃度和粘性。

持续优化:任何应用都需要根据用户反馈进行持续优化。说书人APP也不例外,需要不断收集用户意见,对功能、界面和性能进行迭代升级。

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

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

相关文章

xadmin后台首页增加一个导入数据按钮

xadmin后台首页增加一个导入数据按钮 效果 流程 1、在添加小组件中添加一个html页面 2、写入html代码 3、在urls.py添加导入数据路由 4、在views.py中添加响应函数html代码 <!DOCTYPE html> <html lang

【AimRT】现代机器人通信中间件 AimRT

目录 一、什么是AimRT二、AimRT与ROS22.1 定位与设计2.2 组成与通信方式对比 三、AimRT基本概念3.1 Node、Pkg 和 Module3.2 Protocol、Channel、Rpc 和 Filter3.3 App模式 和 Pkg模式3.4 Executor3.5 Plugin 一、什么是AimRT AimRT 是智元机器人公司自主研发的一款机器人通信…

mysql系列7—Innodb的redolog

背景 本文涉及的内容较为底层&#xff0c;做了解即可&#xff0c;是以前学习《高性能Mysql》和《mysql是怎样运行的》的笔记整理所得。 redolog(后续使用redo日志表示)的核心作用是保证数据库的持久性。 在mysql系列5—Innodb的缓存中介绍过&#xff1a;数据和索引保存在磁盘上…

C++【内存管理】

C/C中程序的内存划分&#xff1a; 栈&#xff1a;又称堆栈&#xff0c;存放非静态的局部变量、函数参数、返回值等等&#xff0c;栈是向下增长的。内存映射段&#xff1a;是高效的&#xff29;&#xff0f;&#xff2f;映射方式&#xff0c;用于装载一个共享的动态内存库。用户…

手机租赁平台开发助力智能设备租赁新模式

内容概要 手机租赁平台开发&#xff0c;简单说就是让你用得起高大上的智能设备&#xff0c;不管是最新款的手机、平板&#xff0c;还是那些炫酷的智能耳机&#xff0c;这个平台应有尽有。想要体验但又不希望花大钱&#xff1f;那你就找对地方了&#xff01;通过灵活的租赁方案…

【开源免费】基于SpringBoot+Vue.JS校园社团信息管理系统(JAVA毕业设计)

本文项目编号 T 107 &#xff0c;文末自助获取源码 \color{red}{T107&#xff0c;文末自助获取源码} T107&#xff0c;文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…

【鸿蒙NEXT】鸿蒙里面类似iOS的Keychain——关键资产(@ohos.security.asset)实现设备唯一标识

前言 在iOS开发中Keychain 是一个非常安全的存储系统&#xff0c;用于保存敏感信息&#xff0c;如密码、证书、密钥等。与 NSUserDefaults 或文件系统不同&#xff0c;Keychain 提供了更高的安全性&#xff0c;因为它对数据进行了加密&#xff0c;并且只有经过授权的应用程序才…

使用npm包的工程如何引入mapboxgl-enhance/maplibre-gl-enhance扩展包

作者&#xff1a;刘大 前言 在使用iClient for MapboxGL/MapLibreGL项目开发中&#xff0c;往往会对接非EPSG:3857坐标系的地图&#xff0c;由于默认不支持&#xff0c;因此需引入mapboxgl-enhance/maplibre-gl-enhance扩展包。 在使用Vue等其他框架&#xff0c;通过npm包下载…

应急指挥系统总体架构方案

引言 应急指挥系统总体架构方案旨在构建一个高效、智能的应急管理体系&#xff0c;以应对自然灾害、事故灾难等突发事件&#xff0c;保障人民生命财产安全。 背景与挑战 近年来&#xff0c;安全生产形势严峻&#xff0c;自然灾害事故频发&#xff0c;对应急指挥系统的要求越…

如何用CSS3创建圆角矩形并居中显示?

在网页设计中&#xff0c;圆角矩形因其美观和现代感而被广泛使用&#xff0c;居中显示元素也是一个常见的需求。今天&#xff0c;我们将学习如何使用CSS3的border-radius属性来创建圆角矩形&#xff0c;并将其居中显示在页面上。 如果你正在学习CSS&#xff0c;那么这个实例将非…

UE5通过蓝图节点控制材质参数

通过蓝图节点控制材质的参数 蓝图节点 在材质上设置标量值 和 在材质上设置向量参数值 Set Scalar Parameter Value on Materials Set Vector Parameter Value on Materials 这两个蓝图节点都可以在蓝图中&#xff0c;控制材质的参数值和向量值

canvas+fabric实现时间刻度尺(二)

前言 我们前面实现了时间刻度尺&#xff0c;鼠标移动显示时间&#xff0c;接下来我们实现鼠标点击某个时间进行弹框。 效果 实现 1.监听鼠标按下事件 2.编写弹框页面 3.时间转换 <template><div><canvas id"rulerCanvas" width"1200"…

手机实时提取SIM卡打电话的信令声音-双卡手机来电如何获取哪一个卡的来电

手机实时提取SIM卡打电话的信令声音 --双卡手机来电如何获取哪一个卡的来电 一、前言 前面的篇章《手机实时提取SIM卡打电话的信令声音-智能拨号器的双SIM卡切换方案》中&#xff0c;我们论述了局域网SIP坐席通过手机外呼出去时&#xff0c;手机中主副卡的呼叫调度策略。 但…

离线语音识别+青云客语音机器人(幼儿园级别教程)

1、使用步骤 确保已安装以下库&#xff1a; pip install vosk sounddevice requests pyttsx3 2、下载 Vosk 模型&#xff1a; 下载适合的中文模型&#xff0c;如 vosk-model-small-cn-0.22。 下载地址&#xff1a; https://alphacephei.com/vosk/models 将模型解压后放置在…

Streaming Dense Video Captioning

原文出处 CVPR 原文链接 [2404.01297] Streaming Dense Video Captioninghttps://arxiv.org/abs/2404.01297 原文笔记 What 1、提出了一种基于聚类传入token的新记忆模块&#xff0c;该模块可以处理任意长的视频&#xff0c;并且可以在不访问视频所有帧的情况下处理视频(…

TCP 连接:三次握手与四次挥手

TCP 协议&#xff0c;全称为“传输控制协议”。 1. TCP 协议段格式 给出几个定义 &#xff1a; 16位源端口号 &#xff1a;用于标识发送端的应用程序。 16位目的端口号 &#xff1a;用于标识接收端的目标应用程序。 32位序号 &#xff1a;用于标识发送的每一个字节流中的第一…

IDEA+Docker一键部署项目SpringBoot项目

文章目录 1. 部署项目的传统方式2. 前置工作3. SSH配置4. 连接Docker守护进程5. 创建简单的SpringBoot应用程序6. 编写Dockerfile文件7. 配置远程部署 7.1 创建配置7.2 绑定端口7.3 添加执行前要运行的任务 8. 部署项目9. 开放防火墙的 11020 端口10. 访问项目11. 可能遇到的问…

redis开发与运维-redis0401-补充-redis流水线与Jedis执行流水线

文章目录 【README】【1】redis流水线Pipeline【1.1】redis流水线概念【1.2】redis流水线性能测试【1.2.1】使用流水线与未使用流水线的性能对比【1.2.2】使用流水线与redis原生批量命令的性能对比【1.2.3】流水线缺点 【1.3】Jedis客户端执行流水线【1.3.1】Jedis客户端执行流…

Uncaught ReferenceError: __VUE_HMR_RUNTIME__ is not defined

Syntax Error: Error: vitejs/plugin-vue requires vue (>3.2.13) or vue/compiler-sfc to be present in the dependency tree. 第一步 npm install vue/compiler-sfc npm run dev 运行成功&#xff0c;本地打开页面是空白&#xff0c;控制台报错 重新下载了vue-loa…

【微服务】【Sentinel】认识Sentinel

文章目录 1. 雪崩问题2. 解决方案3. 服务保护技术对比4. 安装 Sentinel4.1 启动控制台4.2 客户端接入控制台 参考资料: 1. 雪崩问题 微服务调用链路中的某个服务故障&#xff0c;引起整个链路中的所有微服务都不可用&#xff0c;这就是雪崩。动图演示&#xff1a; 在微服务系统…