鸿蒙(API 12 Beta3版)【媒体会话提供方】本地媒体会话

news2024/9/20 6:08:39

音视频应用在实现音视频功能的同时,需要作为媒体会话提供方接入媒体会话,在媒体会话控制方(例如播控中心)中展示媒体相关信息,及响应媒体会话控制方下发的播控命令。

基本概念

  • 媒体会话元数据(AVMetadata): 用于描述媒体数据相关属性,包含标识当前媒体的ID(assetId),上一首媒体的ID(previousAssetId),下一首媒体的ID(nextAssetId),标题(title),专辑作者(author),专辑名称(album),词作者(writer),媒体时长(duration)等属性。
  • 媒体播放状态(AVPlaybackState):用于描述媒体播放状态的相关属性,包含当前媒体的播放状态(state)、播放位置(position)、播放倍速(speed)、缓冲时间(bufferedTime)、循环模式(loopMode)、是否收藏(isFavorite)、正在播放的媒体Id(activeItemId)、自定义媒体数据(extras)等属性。

接口说明

媒体会话提供方使用的关键接口如下表所示。接口返回值有两种返回形式:callback和promise,下表中为callback形式接口,promise和callback只是返回值方式不一样,功能相同。

接口名说明
createAVSession(context: Context, tag: string, type: AVSessionType, callback: AsyncCallback): void10+创建媒体会话。一个UIAbility只能存在一个媒体会话,重复创建会失败。
setAVMetadata(data: AVMetadata, callback: AsyncCallback): void10+设置媒体会话元数据。
setAVPlaybackState(state: AVPlaybackState, callback: AsyncCallback): void10+设置媒体会话播放状态。
setLaunchAbility(ability: WantAgent, callback: AsyncCallback): void10+设置启动UIAbility。
getController(callback: AsyncCallback): void10+获取当前会话自身控制器。
getOutputDevice(callback: AsyncCallback): void10+获取播放设备相关信息。
activate(callback: AsyncCallback): void10+激活媒体会话。
deactivate(callback: AsyncCallback): void10+禁用当前会话。
destroy(callback: AsyncCallback): void10+销毁媒体会话。
setAVQueueItems(items: Array, callback: AsyncCallback): void 10+设置媒体播放列表。
setAVQueueTitle(title: string, callback: AsyncCallback): void10+设置媒体播放列表名称。
dispatchSessionEvent(event: string, args: {[key: string]: Object}, callback: AsyncCallback): void10+设置会话内自定义事件。
setExtras(extras: {[key: string]: Object}, callback: AsyncCallback): void10+设置键值对形式的自定义媒体数据包。
getOutputDeviceSync(): OutputDeviceInfo10+使用同步方法获取当前输出设备信息。

开发步骤

音视频应用作为媒体会话提供方接入媒体会话的基本步骤如下所示:

  1. 通过AVSessionManager的方法创建并激活媒体会话。
import { avSession as AVSessionManager } from '@kit.AVSessionKit';

// 开始创建并激活媒体会话
// 创建session
let context: Context = getContext(this);
async function createSession() {
  let type: AVSessionManager.AVSessionType = 'audio';
  let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
  await session.activate();
  console.info(`session create done : sessionId : ${session.sessionId}`);
}
  1. 跟随媒体信息的变化,及时设置媒体会话信息。需要设置的媒体会话信息主要包括:

    • 媒体会话元数据AVMetadata。
    • 媒体播放状态AVPlaybackState。

    音视频应用设置的媒体会话信息,会被媒体会话控制方通过AVSessionController相关方法获取后进行显示或处理。

import { avSession as AVSessionManager } from '@kit.AVSessionKit';
import { BusinessError } from '@kit.BasicServicesKit';

let context: Context = getContext(this);
async function setSessionInfo() {
  // 假设已经创建了一个session,如何创建session可以参考之前的案例
  let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', 'audio');
  // 播放器逻辑··· 引发媒体信息与播放状态的变更
  // 设置必要的媒体信息
  let metadata: AVSessionManager.AVMetadata = {
    assetId: '0', // 由应用指定,用于标识应用媒体库里的媒体
    title: 'TITLE',
    mediaImage: 'IMAGE',
    artist: 'ARTIST'
  };
  session.setAVMetadata(metadata).then(() => {
    console.info(`SetAVMetadata successfully`);
  }).catch((err: BusinessError) => {
    console.error(`Failed to set AVMetadata. Code: ${err.code}, message: ${err.message}`);
  });
  // 简单设置一个播放状态 - 暂停 未收藏
  let playbackState: AVSessionManager.AVPlaybackState = {
    state:AVSessionManager.PlaybackState.PLAYBACK_STATE_PAUSE,
    isFavorite:false
  };
  session.setAVPlaybackState(playbackState, (err) => {
    if (err) {
      console.error(`Failed to set AVPlaybackState. Code: ${err.code}, message: ${err.message}`);
    } else {
      console.info(`SetAVPlaybackState successfully`);
    }
  });
  // 设置一个播放列表
  let queueItemDescription_1: AVSessionManager.AVMediaDescription = {
    assetId: '001',
    title: 'music_name',
    subtitle: 'music_sub_name',
    description: 'music_description',
    mediaImage: "PIXELMAP_OBJECT",
    extras: {'extras':'any'}
  };
  let queueItem_1: AVSessionManager.AVQueueItem = {
    itemId: 1,
    description: queueItemDescription_1
  };
  let queueItemDescription_2: AVSessionManager.AVMediaDescription = {
    assetId: '002',
    title: 'music_name',
    subtitle: 'music_sub_name',
    description: 'music_description',
    mediaImage: "PIXELMAP_OBJECT",
    extras: {'extras':'any'}
  };
  let queueItem_2: AVSessionManager.AVQueueItem = {
    itemId: 2,
    description: queueItemDescription_2
  };
  let queueItemsArray = [queueItem_1, queueItem_2];
  session.setAVQueueItems(queueItemsArray).then(() => {
    console.info(`SetAVQueueItems successfully`);
  }).catch((err: BusinessError) => {
    console.error(`Failed to set AVQueueItem, error code: ${err.code}, error message: ${err.message}`);
  });
  // 设置媒体播放列表名称
  let queueTitle = 'QUEUE_TITLE';
  session.setAVQueueTitle(queueTitle).then(() => {
    console.info(`SetAVQueueTitle successfully`);
  }).catch((err: BusinessError) => {
    console.info(`Failed to set AVQueueTitle, error code: ${err.code}, error message: ${err.message}`);
  });
}
  1. 设置用于被媒体会话控制方拉起的UIAbility。当用户操作媒体会话控制方的界面时,例如点击播控中心的卡片,可以拉起此处配置的UIAbility。

设置UIAbility时通过WantAgent接口实现

import { wantAgent } from '@kit.AbilityKit';
import { avSession as AVSessionManager } from '@kit.AVSessionKit';
import { wantAgent } from '@kit.AbilityKit';

let context: Context = getContext(this);
async function getWantAgent() {
  let type: AVSessionManager.AVSessionType = 'audio';
  // 假设已经创建了一个session,如何创建session可以参考之前的案例
  let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
  let wantAgentInfo: wantAgent.WantAgentInfo = {
    wants: [
      {
        bundleName: 'com.example.musicdemo',
        abilityName: 'MainAbility'
      }
    ],
    operationType: wantAgent.OperationType.START_ABILITIES,
    requestCode: 0,
    wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
  }
  wantAgent.getWantAgent(wantAgentInfo).then((agent) => {
    session.setLaunchAbility(agent);
  })
}
  1. 设置一个即时的自定义会话事件,以供媒体控制方接收到事件后进行相应的操作。

说明

通过dispatchSessionEvent方法设置的数据不会保存在会话对象或AVSession服务中。

import { avSession as AVSessionManager } from '@kit.AVSessionKit';
import { BusinessError } from '@kit.BasicServicesKit';

let context: Context = getContext(this);
async function dispatchSessionEvent() {
  // 假设已经创建了一个session,如何创建session可以参考之前的案例
  let type: AVSessionManager.AVSessionType = 'audio';
  let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
  let eventName = 'dynamic_lyric';
  await session.dispatchSessionEvent(eventName, {lyric : 'This is my lyric'}).then(() => {
    console.info(`Dispatch session event successfully`);
  }).catch((err: BusinessError) => {
    console.error(`Failed to dispatch session event. Code: ${err.code}, message: ${err.message}`);
  })
}
  1. 设置与当前会话相关的自定义媒体数据包,以供媒体控制方接收到事件后进行相应的操作。

说明

通过setExtras方法设置的数据包会被存储在AVSession服务中,数据的生命周期与会话一致;会话对应的Controller可以使用getExtras来获取该数据。

import { avSession as AVSessionManager } from '@kit.AVSessionKit';
import { BusinessError } from '@kit.BasicServicesKit';

let context: Context = getContext(this);
async function setExtras() {
  // 假设已经创建了一个session,如何创建session可以参考之前的案例
  let type: AVSessionManager.AVSessionType = 'audio';
  let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
  await session.setExtras({extra : 'This is my custom meida packet'}).then(() => {
    console.info(`Set extras successfully`);
  }).catch((err: BusinessError) => {
    console.error(`Failed to set extras. Code: ${err.code}, message: ${err.message}`);
  })
}
  1. 注册播控命令事件监听,便于响应用户通过媒体会话控制方,例如播控中心,下发的播控命令。

    在Session侧注册的监听分为固定播控命令和高级播控事件两种。

6.1 固定控制命令的监听

说明

媒体会话提供方在注册相关固定播控命令事件监听时,监听的事件会在媒体会话控制方的getValidCommands()方法中体现,即媒体会话控制方会认为对应的方法有效,进而根据需要触发相应暂不使用时的事件。为了保证媒体会话控制方下发的播控命令可以被正常执行,媒体会话提供方请勿进行无逻辑的空实现监听。

Session侧的固定播控命令主要包括播放、暂停、上一首、下一首等基础操作命令。
import { avSession as AVSessionManager } from '@kit.AVSessionKit';

let context: Context = getContext(this);
async function setListenerForMesFromController() {
  // 假设已经创建了一个session,如何创建session可以参考之前的案例
  let type: AVSessionManager.AVSessionType = 'audio';
  let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
  // 一般在监听器中会对播放器做相应逻辑处理
  // 不要忘记处理完后需要通过set接口同步播放相关信息,参考上面的用例
  session.on('play', () => {
    console.info(`on play , do play task`);
    // 如暂不支持该指令,请勿注册;或在注册后但暂不使用时,通过session.off('play')取消监听
    // 处理完毕后,请使用SetAVPlayState上报播放状态
  });
  session.on('pause', () => {
    console.info(`on pause , do pause task`);
     // 如暂不支持该指令,请勿注册;或在注册后但暂不使用时,通过session.off('pause')取消监听
     // 处理完毕后,请使用SetAVPlayState上报播放状态
  });
  session.on('stop', () => {
    console.info(`on stop , do stop task`);
     // 如暂不支持该指令,请勿注册;或在注册后但暂不使用时,通过session.off('stop')取消监听
     // 处理完毕后,请使用SetAVPlayState上报播放状态
  });
  session.on('playNext', () => {
    console.info(`on playNext , do playNext task`);
     // 如暂不支持该指令,请勿注册;或在注册后但暂不使用时,通过session.off('playNext')取消监听
     // 处理完毕后,请使用SetAVPlayState上报播放状态,使用SetAVMetadata上报媒体信息
  });
  session.on('playPrevious', () => {
    console.info(`on playPrevious , do playPrevious task`);
     // 如暂不支持该指令,请勿注册;或在注册后但暂不使用时,通过session.off('playPrevious')取消监听
     // 处理完毕后,请使用SetAVPlayState上报播放状态,使用SetAVMetadata上报媒体信息
  });
  session.on('fastForward', () => {
    console.info(`on fastForward , do fastForward task`);
     // 如暂不支持该指令,请勿注册;或在注册后但暂不使用时,通过session.off('fastForward')取消监听
     // 处理完毕后,请使用SetAVPlayState上报播放状态和播放position
  });
  session.on('rewind', () => {
    console.info(`on rewind , do rewind task`);
     // 如暂不支持该指令,请勿注册;或在注册后但暂不使用时,通过session.off('rewind')取消监听
     // 处理完毕后,请使用SetAVPlayState上报播放状态和播放position
  });

  session.on('seek', (time) => {
    console.info(`on seek , the seek time is ${time}`);
     // 如暂不支持该指令,请勿注册;或在注册后但暂不使用时,通过session.off('seek')取消监听
     // 处理完毕后,请使用SetAVPlayState上报播放状态和播放position
  });
  session.on('setSpeed', (speed) => {
    console.info(`on setSpeed , the speed is ${speed}`);
    // do some tasks ···
  });
  session.on('setLoopMode', (mode) => {
    console.info(`on setLoopMode , the loop mode is ${mode}`);
     // 如暂不支持该指令,请勿注册;或在注册后但暂不使用时,通过session.off('setLoopMode')取消监听
     // 应用自定下一个模式,处理完毕后,请使用SetAVPlayState上报切换后的LoopMode
  });
  session.on('toggleFavorite', (assetId) => {
    console.info(`on toggleFavorite , the target asset Id is ${assetId}`);
     // 如暂不支持该指令,请勿注册;或在注册后但暂不使用时,通过session.off('toggleFavorite')取消监听
     // 处理完毕后,请使用SetAVPlayState上报收藏结果isFavorite
  });
}

6.2 高级播控事件的监听

Session侧的可以注册的高级播控事件主要包括:

  • skipToQueueItem: 播放列表其中某项被选中的事件。
  • handleKeyEvent: 按键事件。
  • outputDeviceChange: 播放设备变化的事件。
  • commonCommand: 自定义控制命令变化的事件。
import { avSession as AVSessionManager } from '@kit.AVSessionKit';

let context: Context = getContext(this);
async function setListenerForMesFromController() {
  // 假设已经创建了一个session,如何创建session可以参考之前的案例
  let type: AVSessionManager.AVSessionType = 'audio';
  let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
  // 一般在监听器中会对播放器做相应逻辑处理
  // 不要忘记处理完后需要通过set接口同步播放相关信息,参考上面的用例
  session.on('skipToQueueItem', (itemId) => {
    console.info(`on skipToQueueItem , do skip task`);
    // do some tasks ···
  });
  session.on('handleKeyEvent', (event) => {
    console.info(`on handleKeyEvent , the event is ${JSON.stringify(event)}`);
    // do some tasks ···
  });
  session.on('outputDeviceChange', (device) => {
    console.info(`on outputDeviceChange , the device info is ${JSON.stringify(device)}`);
    // do some tasks ···
  });
  session.on('commonCommand', (commandString, args) => {
    console.info(`on commonCommand , command is ${commandString}, args are ${JSON.stringify(args)}`);
    // do some tasks ···
  });
}
  1. 获取当前媒体会话自身的控制器,与媒体会话对应进行通信交互。
import { avSession as AVSessionManager } from '@kit.AVSessionKit';

let context: Context = getContext(this);
async function createControllerFromSession() {
  // 假设已经创建了一个session,如何创建session可以参考之前的案例
  let type: AVSessionManager.AVSessionType = 'audio';
  let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);

  // 通过已有session获取一个controller对象
  let controller = await session.getController();

  // controller可以与原session对象进行基本的通信交互,比如下发播放命令
  let avCommand: AVSessionManager.AVControlCommand = {command:'play'};
  controller.sendControlCommand(avCommand);

  // 或者做状态变更监听
  controller.on('playbackStateChange', 'all', (state) => {

    // do some things
  });

  // controller可以做的操作还有很多,具体可以参考媒体会话控制方相关的说明
}
  1. 音视频应用在退出,并且不需要继续播放时,及时取消监听以及销毁媒体会话释放资源。

    取消播控命令监听的示例代码如下所示 :

import { avSession as AVSessionManager } from '@kit.AVSessionKit';

let context: Context = getContext(this);
async function unregisterSessionListener() {
  // 假设已经创建了一个session,如何创建session可以参考之前的案例
  let type: AVSessionManager.AVSessionType = 'audio';
  let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);

  // 取消指定session下的相关监听
  session.off('play');
  session.off('pause');
  session.off('stop');
  session.off('playNext');
  session.off('playPrevious');
  session.off('skipToQueueItem');
  session.off('handleKeyEvent');
  session.off('outputDeviceChange');
  session.off('commonCommand');
}

销毁媒体会话示例代码如下所示:

import { avSession as AVSessionManager } from '@kit.AVSessionKit';

let context: Context = getContext(this);
async function destroySession() {
  // 假设已经创建了一个session,如何创建session可以参考之前的案例
  let type: AVSessionManager.AVSessionType = 'audio';
  let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
  // 主动销毁已创建的session
  session.destroy((err) => {
    if (err) {
      console.error(`Failed to destroy session. Code: ${err.code}, message: ${err.message}`);
    } else {
      console.info(`Destroy : SUCCESS `);
    }
  });
}

最后呢

很多开发朋友不知道需要学习那些鸿蒙技术?鸿蒙开发岗位需要掌握那些核心技术点?为此鸿蒙的开发学习必须要系统性的进行。

而网上有关鸿蒙的开发资料非常的少,假如你想学好鸿蒙的应用开发与系统底层开发。你可以参考这份资料,少走很多弯路,节省没必要的麻烦。由两位前阿里高级研发工程师联合打造的《鸿蒙NEXT星河版OpenHarmony开发文档》里面内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(Harmony NEXT)技术知识点

如果你是一名Android、Java、前端等等开发人员,想要转入鸿蒙方向发展。可以直接领取这份资料辅助你的学习。下面是鸿蒙开发的学习路线图。

在这里插入图片描述

针对鸿蒙成长路线打造的鸿蒙学习文档。话不多说,我们直接看详细鸿蒙(OpenHarmony )手册(共计1236页)与鸿蒙(OpenHarmony )开发入门视频,帮助大家在技术的道路上更进一步。

  • 《鸿蒙 (OpenHarmony)开发学习视频》
  • 《鸿蒙生态应用开发V2.0白皮书》
  • 《鸿蒙 (OpenHarmony)开发基础到实战手册》
  • OpenHarmony北向、南向开发环境搭建
  • 《鸿蒙开发基础》
  • 《鸿蒙开发进阶》
  • 《鸿蒙开发实战》

在这里插入图片描述

总结

鸿蒙—作为国家主力推送的国产操作系统。部分的高校已经取消了安卓课程,从而开设鸿蒙课程;企业纷纷跟进启动了鸿蒙研发。

并且鸿蒙是完全具备无与伦比的机遇和潜力的;预计到年底将有 5,000 款的应用完成原生鸿蒙开发,未来将会支持 50 万款的应用。那么这么多的应用需要开发,也就意味着需要有更多的鸿蒙人才。鸿蒙开发工程师也将会迎来爆发式的增长,学习鸿蒙势在必行! 自↓↓↓拿

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

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

相关文章

WordPress原创插件:Download-block-plugin下载按钮图标美化

WordPress原创插件:Download-block-plugin下载按钮图标美化 https://download.csdn.net/download/huayula/89632743

Mapreduce_csv_averageCSV文件计算平均值

csv文件求某个平均数据 查询每个部门的平均工资,最后输出 数据处理过程 employee_noheader.csv(没做关于首行的处理,运行时请自行删除) EmployeeID,EmployeeName,DepartmentID,Salary 1,ZhangSan,101,5000 2,LiSi,102,6000…

疫情下图书馆管理系统

TOC springboot126疫情下图书馆管理系统 系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及,互联网成为人们查找信息的重要场所,二十一世纪是信息的时代,所以信息的管理显得特别重要。因此,使用计算机来管…

mock.js的简单使用~

1、什么是mock? mock.js:是一款模拟数据生成器,可以生成随机数据,拦截 Ajax 请求. 2、mock的作用。 可以通过mock来模拟后端接口,可随机生成所需数据,模拟对数据的增删改查。并且截Ajax请求不需要修改既有代码就可以拦截&…

RCE-eval长度限制突破技巧

目录 一、长度17的限制绕过 1、最简单的绕过 (一)绕过 (二)编写一句话木马 2、文件包含的利用 (一)远程文件包含的利用 (二)本地文件包含的利用 3、usort绕过 &#xff08…

BGP路由优选(五)

当到达同一个目的网段存在多条路由时,BGP通过如下的次序进行路由优选: 丢弃下一跳不可达的路由。 优选Preferred-Value属性值最大的路由。优选Local_Preference属性值最大的路由。本地始发的BGP路由优于从其他对等体学习到的路由,本地始发的路…

使用腾讯云存储桶COS来实现上传和下载图片功能

有个需求,需要上传和下载图片,我决定使用腾讯云存储桶来做服务器存储目录,供程序上传和下载使用。 1、首先打开对应网站:云产品免费体验馆_云产品免费试用_个人云产品试用-腾讯云,点击左边的"存储"项&#x…

proxy负载均衡

endpoint : 终点、终端 看service服务器的ip kubectl get ep backend -> real server :真正提供web服务的服务器 负载均衡器 load balancer --》LB USER -->LB --->BACKEND(real server) nginx SERVICE --->很多的endpoint--》po…

报名表EXCEL图片批量下载源码-CyberWinApp-SAAS 本地化及未来之窗行业应用跨平台架构

每次报名表都会包含大量照片,一张一张下载很慢 可以通过未来之窗开源平台架构 开开excel批量下载 实现代码也很简单 function 未来之窗下载(){ let 未来之窗地址 document.getElementById("batchurl").value; let 保存路径 document.getElementById(…

GD32 MCU如何使用双ADC内核提高ADC采样率?

如下图所示,GD32F303系列MCU在不同的ADC位宽情况下均具有对应的最高采样率,那这个最高采样率还可以提高吗? 答案是可以的。GD32F30X系列MCU可以支持双ADC内核,分别为ADC0和ADC1,且双ADC可以支持同步模式,同…

力扣热题100_链表_206_反转链表

文章目录 题目链接解题思路解题代码 题目链接 206. 反转链表 给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。 示例 1: 输入:head [1,2,3,4,5] 输出:[5,4,3,2,1] 示例 2: 输入&#xf…

Leetcode面试经典150题-146.LRU缓存

解法都在代码里,不懂就留言或者私信,这个题大概率不会让你直接写代码,而是说以下思路,如果写代码这个题写出来基本就过了 class LRUCache {/**首先我们得有缓存,get和put都是O(1)时间复杂度,我们常用的数…

公用事业公司与数据中心的电力协议推动未来增长

随着人工智能技术的迅猛发展,美国公用事业公司正在积极与数据中心运营商签订电力供应协议。这一趋势预计将显著提升这些公司的销售额和利润,并对未来几年的能源市场产生深远影响。 数据中心电力需求激增 根据高盛的报告,到2030年&#xff0c…

WMS助力企业数字化转型(六)

在当今数字化时代,仓库管理系统(WMS)作为推动企业数字化转型的重要工具,通过实时数据监控、自动化操作和智能分析,大幅提升了仓储管理的效率与精准度,为企业在供应链优化、库存控制和客户满意度方面带来了显…

Datawhale X 魔搭 AI夏令营 第四期魔搭-AIGC文生图方向Task2笔记

了解一下 AI生图技术 的能力&局限 对所有人来说,定期关注AI生图的最新能力情况都十分重要: 对于普通人来说,可以避免被常见的AI生图场景欺骗,偶尔也可以通过相关工具绘图 对于创作者来说,通过AI生图的工具可以快速…

GUI Agent with SFT 学习

grounding指的是基础训练,定位之类的意思,sft指的是监督微调,也就是用带有标签的数据集对与训练完毕的模型进行微调(因为是带标签的,所以叫监督) ui理解能力分为两个部分:Static UI understandi…

离线安装部署springboot+vue系统到服务器

注意:首先服务器会有多个网卡,这些服务器的网卡连接所需要的文件可能不是我们默认的ifcfg-eth0/ifcfgens33,可以试着切换一下服务器网线插入的接口,要保证服务器网线插入的接口和网卡对应的文件一致 说明,在一些政府(保…

lvs的相关应用2

lvs 安装lvs 配置规则,查看所有的规则,如果已经配置好规则,重启之后就没了 [rootds01 ~]# ipvsadm -Ln IP Virtual Server version 1.2.1 (size4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forwa…

react的setState中为什么不能用++?

背景: 在使用react的过程中产生了一些困惑,handleClick函数的功能是记录点击次数,handleClick函数被绑定到按钮中,每点击一次将通过this.state.counter将累计的点击次数显示在页面上 困惑: 为什么不能直接写prevStat…

为什么要学习AI大模型?

AI大模型正在以惊人的速度改变着各行各业。正如移动互联网时代造就了无数成功的开发者,今天的大模型技术也为我们带来了前所未有的机遇。学习和掌握这项技术,不仅能让你站在行业前沿,还能为你的职业生涯带来巨大的回报。 01 企业为什么需要…