WebRTC Native APIs[翻译]

WebRTC Native APIs[翻译]
最近一直在研究WebRTC,本篇是WebRTC的本地API文档,Web developer了解一下也是有好处的,了解了API的实现原理使用起来才会更顺手。决定翻译是因为这篇字不多,翻一下加深自己的理解,如果对别人有帮助那就更好了。第一次翻译东西拿出来,如果有错误还望指正,英文好一点的还是移步英文原文吧:

by longrenle

WebRTC Native APIs

版本2.0 (libjingle r115)

2012年2月

WebRTC native APIs文档 是基于  文档撰写的.
实现WebRTC native APIs的代码(包括Stream 和 PeerConnection APIs) 都可以在开源项目上找到. 另外在该项目中我们还提供了.

这篇文档的预期读者是想要用WebRTC Native APIs实现WebRTC javascript APIs或者开发本地RTC应用程序的程序员和工程师们。

内容

新的内容

与 (代码在,开源项目libjingle r115的一部分)相比, 主要不同是新的版本包括了的实现。使用Stream APIs, 视音频媒体会在MediaTrack对象中处理,而不是直接交给PeerConnection处理。并且现在PeerConnection在调用中能够接收和返回MediaStream对象而不是像先前版本中只能处理媒体流标签。

除此之外,在这个版本中信令处理使用的协议改用了,这对APIs的用户应当是透明的。

如果你开发的应用是基于以前的版本,请查看这个来把你的应用迁移到新的APIs来。也可以参考上面提到的。


模块架构图

调用序列

发起通话

接受通话

结束通话


线程模型

WebRTC native APIs 拥有两个全局线程:信令线程(signaling thread)和工作者线程(worker thread)。取决于PeerConnection factory被创建的方式,应用程序可以提供这两个线程或者直接使用内部创建好的线程。

Stream APIs和PeerConnection APIs的调用会被代理到信令线程,这就意味着应用程序可以在任何线程调用这些APIs。

所有的回调函数都在信令线程调用。应用程序应当尽快地跳出回调函数以避免阻塞信令线程。严重消耗资源的过程都应当其他的线程执行。

工作者线程被用来处理资源消耗量大的过程,比如说数据流传输。


Stream APIs ()

Class MediaStreamTrackInterface
这个类声明了一个媒体流传输的抽象接口,用来代表用户代理(UA)的媒体源。
class MediaStreamTrackInterface : public talk_base::RefCountInterface,
                                public NotifierInterface {
public:
enum TrackState {
   kInitializing,
   kLive = 1,
   kEnded = 2,
   kFailed = 3,
};
virtual std::string kind() const = 0;
virtual std::string label() const = 0;
virtual bool enabled() const = 0;
virtual TrackState state() const = 0;
virtual bool set_enabled(bool enable) = 0;
virtual bool set_state(TrackState new_state) = 0;
};
MediaStreamTrackInterface::TrackState
这个枚举类型定义了传输轨道的状态。
语法
enum TrackState {




备注
kInitializing - 传输正在协商.
kLive - 传输轨道可用.
kEnded - 传输轨道关闭.
kFailed - 传输协商失败.
MediaStreamTrackInterface::kind
如果传输音频轨道返回"audio”,如果传输视频轨道则返回"video" ,或者一个用户代理定义的其他字符串。
语法
virtual std::string kind() const = 0;
MediaStreamTrackInterface::label
如果有的话返回轨道的标签,否则返回空串。
语法
virtual std::string label() const = 0;
MediaStreamTrackInterface::enabled
如果轨道可用返回"true”,否则返回"false”.
语法
virtual bool enabled() const = 0;
MediaStreamTrackInterface::state
返回轨道的当前状态。
语法
virtual TrackState state() const = 0;
MediaStreamTrackInterface::set_enabled
开启(true) 或者关闭(false) 媒体管道.
语法
virtual bool set_enabled(bool enable) = 0;
备注
Not implemented.
MediaStreamTrackInterface::set_state
设置媒体管道的状态。
语法
virtual bool set_state(TrackState new_state) = 0;
备注
这个方法应该被PeerConnection内部调用,应用程序不应当直接调用。

Class VideoTrackInterface
类VideoTrackInterface继承自类MediaStreamTrackInterface,增加了两个设置和得到视频渲染器的接口。





};

Class LocalVideoTrackInterface
类LocalVideoTrackInterface继承自类VideoTrackInterface,增加了一个接口得到视频捕获设备。.
class LocalVideoTrackInterface : public VideoTrackInterface {
public:
virtual cricket::VideoCapturer* GetVideoCapture() = 0;
protected:
virtual ~LocalVideoTrackInterface() {}
};

Class AudioTrackInterface
类AudioTrackInterface继承自类MediaStreamTrackInterface,目前没有其他接口。
class AudioTrackInterface : public MediaStreamTrackInterface {
public:
protected:
virtual ~AudioTrackInterface() {}
};

Class LocalAudioTrackInterface
类LocalAudioTrackInterface继承自AudioTrackInterface,增加了一个接口来得到音频设备。
class LocalAudioTrackInterface : public AudioTrackInterface {
public:
virtual AudioDeviceModule* GetAudioDevice() =  0;
protected:
virtual ~LocalAudioTrackInterface() {}
};

Class cricket::VideoRenderer, cricket::VideoCapturer
这些类定义在开源工程

Class webrtc::AudioDeviceModule
类AudioDeviceModule定义在开源工程. 请点击链接参考详细定义。

Class MediaStreamInterface
这个类声明了一个MediaStream的抽象接口,该类典型但不是必须的,表示视音频流。
每一个对象可以包含零到多个音频轨道,尤其视音频轨道。在一个MediaStream对象的所有媒体轨道在渲染的时候必须是同步的。不同的MediaStream对象不必同步。
class MediaStreamInterface : public talk_base::RefCountInterface,
public NotifierInterface {
public:
virtual std::string label() const = 0;
virtual AudioTracks* audio_tracks() = 0;
virtual VideoTracks* video_tracks() = 0;
enum ReadyState {
kInitializing,
kLive = 1,  // Stream alive
kEnded = 2,  // Stream have ended
};
virtual ReadyState ready_state() = 0;
protected:
virtual ~MediaStreamInterface() {}
};
MediaStreamInterface::label
返回这个媒体流的唯一标签,目的是在这些媒体流通过PeerConnection APIs传输后能够被区别清楚。
语法
virtual std::string label() const = 0;
MediaStreamInterface::audio_tracks
返回对象列表的指针,代表与当前MediaStream对象相关的音频流轨道列表。
语法
virtual AudioTracks* audio_tracks() = 0;
MediaStreamInterface::video_tracks
返回对象列表的指针,代表与当前MediaStream对象相关的视频流轨道列表。
语法
virtual VideoTracks* video_tracks() = 0;
MediaStreamInterface::ready_state
返回当前MediaStream的状态是否就绪。
语法
virtual ReadyState ready_state() = 0;

Class LocalMediaStreamInterface
类LocalMediaStreamInterface继承自类MediaStreamInterface,定义了两个方法添加视音频轨道。
class LocalMediaStreamInterface : public MediaStreamInterface {
public:
virtual bool AddTrack(AudioTrackInterface* track) = 0;
virtual bool AddTrack(VideoTrackInterface* track) = 0;
}

;



PeerConnection APIs ()

Class StreamCollectionInterface
这个类定义了一个MediaStream容器接口。
class StreamCollectionInterface : public talk_base::RefCountInterface {
public:
virtual size_t count() = 0;
virtual MediaStreamInterface* at(size_t index) = 0;
virtual MediaStreamInterface* find(const std::string& label) = 0;
protected:
~StreamCollectionInterface() {}
};
StreamCollectionInterface::count
返回MediaStreams集合的数量。
语法
size_t count() = 0;
StreamCollectionInterface::at
返集合中指定位置的MediaStream对象指针。
语法
MediaStreamInterface* at(size_t index) = 0;
参数
index [in] Position of a MediaStream in the collection.
StreamCollectionInterface::find
用标签查询MediaStream对象,如果找到返回对象指针,否者返回NULL。
语法
MediaStreamInterface* find(const std::string& label) = 0;
参数
label [in] The label value to be searched for.

Class PeerConnectionObserver
这个类为用户定义的observer声明了一个抽象接口。它取决于PeerConnection用户实现的子类。当PeerConnection被创建的时候用PeerConnectionFactoryInterface类注册observer对象。
class PeerConnectionObserver {
public:
enum StateType {
   kReadyState,
   kIceState,
   kSdpState,
};
virtual void OnError() = 0;
virtual void OnMessage(const std::string& msg) = 0;
virtual void OnSignalingMessage(const std::string& msg) = 0;
virtual void OnStateChange(StateType state_changed) = 0;
virtual void OnAddStream(MediaStreamInterface* stream) = 0;
virtual void OnRemoveStream(MediaStreamInterface* stream) = 0;
protected:
~PeerConnectionObserver() {}
};
PeerConnectionObserver::StateType
这个枚举定义了状态机状态。
语法
enum StateType {
   kReadyState,
   kIceState,
   kSdpState,
};
PeerConnectionObserver::OnError
当PeerConnection执行中出错时调用此方法。
语法
void OnError() = 0;
备注
尚未实现。
PeerConnectionObserver::OnMessage
当收到对端的一条文本消息是此方法被调用。
语法
void OnMessage(const std::string& msg) = 0;
PeerConnectionObserver::OnSignalingMessage
当收到信令是调用此方法。
语法
void OnSignalingMessage(const std::string& msg) = 0;
参数
msg [in] A format signaling message.
备注
用户应当从回调函数向对端发送信令。
The user should send the signaling message from the callback to the remote peer.
PeerConnectionObserver::OnStateChange
这个方法当状态机状态(ReadyState, SdpState or IceState)改变时被调用。
语法
virtual void OnStateChange(StateType state_changed) = 0;
参数
state_changed [in] Specify which state machine’s state has changed.
备注
IceState尚未实现。
PeerConnectionObserver::OnAddStream
该方法当从对端收到新的媒体流时被调用。
语法
virtual void OnAddStream(MediaStreamInterface* stream) = 0;
参数
stream [in] The handler to the remote media stream.
备注
用户可以用这个事件为收到的媒体流设置渲染器。
PeerConnectionObserver::OnRemoveStream
当对端关闭媒体流时调用此方法。
语法
virtual void OnRemoveStream(MediaStreamInterface* stream) = 0;
参数
stream [in] The handler to the closed remote media stream.

Class PortAllocatorFactoryInterface
这个类声明了一个工厂接口来创建cricket::PortAllocator对象,该对象用来做ICE协商。PeerConnection工厂使用这个接口(如果提供)为自己创建PortAllocator。应用程序也可以提供自己的PortAllocator 实现,只要实现了PortAllocatorFactoryInterface的CreatePortAllocator方法。
class PortAllocatorFactoryInterface : public talk_base::RefCountInterface {
public:
struct StunConfiguration {
   StunConfiguration(const std::string& address, int port)
       : server(address, port) {}
   talk_base::SocketAddress server;
};
struct TurnConfiguration {
   TurnConfiguration(const std::string& address,
                     int port,
                     const std::string& user_name,
                     const std::string& password)
       : server(address, port),
         username(username),
         password(password) {}
   talk_base::SocketAddress server;
   std::string username;
   std::string password;
};
virtual cricket::PortAllocator* CreatePortAllocator(
     const std::vector<StunConfiguration>& stun_servers,
     const std::vector<TurnConfiguration>& turn_configurations) = 0;
protected:
PortAllocatorFactoryInterface() {}
~PortAllocatorFactoryInterface() {}
};
PortAllocatorFactoryInterface::CreatePortAllocator
这个方法返回PortAllocator类的实例.
语法
virtual cricket::PortAllocator* CreatePortAllocator(
     const std::vector<StunConfiguration>& stun_servers,
     const std::vector<TurnConfiguration>& turn_configurations) = 0;
参数
stun_servers [in] A configuration list of the STUN servers.
turn_servers [in] A configuration list of the TURN servers.
备注
TURN 尚未实现。

Class PeerConnectionFactoryInterface
PeerConnectionFactoryInterface是一个工厂接口用来创建PeerConnection对象, 媒体流和媒体轨道。
class PeerConnectionFactoryInterface : public talk_base::RefCountInterface {
public:
virtual talk_base::scoped_refptr<PeerConnectionInterface>
     CreatePeerConnection(const std::string& config,
                          PeerConnectionObserver* observer) = 0;
virtual talk_base::scoped_refptr<LocalMediaStreamInterface>
     CreateLocalMediaStream(const std::string& label) = 0;
virtual talk_base::scoped_refptr<LocalVideoTrackInterface>
     CreateLocalVideoTrack(const std::string& label,
                           cricket::VideoCapturer* video_device) = 0;
virtual talk_base::scoped_refptr<LocalAudioTrackInterface>
     CreateLocalAudioTrack(const std::string& label,
                           AudioDeviceModule* audio_device) = 0;
protected:
PeerConnectionFactoryInterface() {}
~PeerConnectionFactoryInterface() {}
};
PeerConnectionFactoryInterface::CreatePeerConnection
该方法创建PeerConnection类的实例。
语法
virtual talk_base::scoped_refptr<PeerConnectionInterface>
     CreatePeerConnection(const std::string& config,
                        PeerConnectionObserver* observer) = 0;
参数
config [in] STUN或TURN服务器地址用来建立连接的配置字符串。格式定义参考。
observer [in] 继承PeerConnectionObserver类的实例的指针。
备注
TURN 尚未支持。
接受的配置字符串:
"TYPE 203.0.113.2:3478"
表名服务器的IP和端口号。
"TYPE relay.example.net:3478

表明服务器的域名和端口号,用户代理会从DNS查询对应IP。

"TYPE example.net"

表明服务器的域名和端口号,用户代理会从DNS查询对应IP和端口。

类型"TYPE"可以是一下的一种:

STUN

表明一个STUN服务器。

STUNS

表明一个STUN 服务器并用TLS会话连接。

TURN

表明一个TURN服务器。

TURNS

表明一个TURN服务器并用TLS会话连接。

PeerConnectionFactoryInterface::CreateLocalMediaStream
创建本端媒体流的实例。
语法
virtual talk_base::scoped_refptr<LocalMediaStreamInterface>
     CreateLocalMediaStream(const std::string& label) = 0;
参数
label [in] Desired local media stream label.
PeerConnectionFactoryInterface::CreateLocalVideoTrack
创建本端视频轨道的对象。
语法
virtual talk_base::scoped_refptr<LocalVideoTrackInterface>
     CreateLocalVideoTrack(const std::string& label,
                           cricket::VideoCapturer* video_device) = 0;
参数
label [in] Desired local video track label.
video_device [in] Pointer to the video capture device that is going to associate with this track.
PeerConnectionFactoryInterface::CreateLocalAudioTrack
创建本端音频轨道的对象。
语法
virtual talk_base::scoped_refptr<LocalVideoTrackInterface>
     CreateLocalAudioTrack(const std::string& label,
                           AudioDeviceModule* audio_device) = 0;
参数
label [in] Desired local audio track label.
audio_device [in] Pointer to the audio device that is going to associate with this track.

函数 CreatePeerConnectionFactory
创建一个PeerConnectionFactoryInterface对象的实例。
语法
talk_base::scoped_refptr<PeerConnectionFactoryInterface>
CreatePeerConnectionFactory();
备注
这个生成的PeerConnectionFactoryInterface对象会创建需求的内部资源,包括libjingle 线程,socket ,管理网络的network manager factory。

函数 CreatePeerConnectionFactory
用给出的libjingle 线程和portallocator对象工厂创建一个PeerConnectionFactoryInterface对象的实例。
Syntax
talk_base::scoped_refptr<PeerConnectionFactoryInterface>
CreatePeerConnectionFactory(talk_base::Thread* worker_thread,
                           talk_base::Thread* signaling_thread,
                           PortAllocatorFactoryInterface* factory,
                           AudioDeviceModule* default_adm);
备注
当应用程序想要提供自己实现的线程和portallocator对象时调用该方法。
这些参数的所有权不能转移到这个对象上,必须在PeerConnectionFactoryInterface的声明周期范围内。

Class PeerConnectionInterface
class PeerConnectionInterface : public talk_base::RefCountInterface {
public:
enum ReadyState {
   kNew,
   kNegotiating,
   kActive,
   kClosing,
   kClosed,
};
enum SdpState {
   kSdpNew,
   kSdpIdle,
   kSdpWaiting,
};
virtual void ProcessSignalingMessage(const std::string& msg) = 0;
virtual bool Send(const std::string& msg) = 0;
virtual talk_base::scoped_refptr<StreamCollectionInterface>
     local_streams() = 0;
virtual talk_base::scoped_refptr<StreamCollectionInterface>
     remote_streams() = 0;
virtual void AddStream(LocalMediaStreamInterface* stream) = 0;
virtual void RemoveStream(LocalMediaStreamInterface* stream) = 0;
virtual void CommitStreamChanges() = 0;
virtual void Close() = 0;
virtual ReadyState ready_state() = 0;
virtual SdpState sdp_state() = 0;
protected:
~PeerConnectionInterface() {}
};
PeerConnectionInterface::ReadyState
该枚举定义了就绪状态的几种类别状态。
  • kNew - 对象刚被创建并且他的ICE和SDP代理尚未启动。
  • kNegotiating - peerConenction 对象正在尝试得到媒体的传输方式。
  • kActive - 连接建立成功,如果任何媒体流协商成功,相关的媒体就可以被传输了。
  • kClosing - 方法被调用后对象正在被关闭。
  • kClosed - 对象关闭成功。







PeerConnectionInterface::SdpState
该枚举定义了SDP的状态。
  • kSdpNew - 对象刚被创建SDP代理尚未开始。
  • kSdpIdle - 有效的请求回答已经交换,SDP代理正在等地下一个SDP事务。
  • kSdpWaiting - SDP代理发送了一个SDP请求正在等待响应。.
语法
enum SdpState {
kSdpNew,  // TODO(ronghuawu): kSdpNew is not defined in the spec.
kSdpIdle,
kSdpWaiting,
};
PeerConnectionInterface::ProcessSignalingMessage
该方法用来处理对端的信令。
语法
virtual void ProcessSignalingMessage(const std::string& msg) = 0;
参数
msg
[in] A format signaling message.
备注
信令的顺序是很重要的,如果传输的信令与对端产生信令的顺序不同的话会使会话的建立失败或会话连接质量降低。
PeerConnectionInterface::Send
该方法给对端发送一个文本信息。
语法
virtual bool Send(const std::string& msg) = 0;  // TODO(ronghuawu): This is not defined in the spec.
参数
msg
[in] The text message to be sent to the remote peer.
备注
尚未实现。(好奇怪老外为什么会release这么多未实现的interface。)
PeerConnectionInterface::local_streams
返回一个用户代理正在尝试向对端传送的媒体流数组(由方法添加的视频流)。
语法
virtual talk_base::scoped_refptr<StreamCollectionInterface>
local_streams() = 0;
PeerConnectionInterface::remote_streams
返回一个用户代理当前正在从对端接收的媒体流数组。
这个数组当OnAddStream和OnRemoveStream回调函数被调用时被更新。
语法
virtual talk_base::scoped_refptr<StreamCollectionInterface>
remote_streams() = 0;
PeerConnectionInterface::AddStream
添加一个本地媒体流到用户代理正在尝试向对端传送的媒体流数组。这个函数只是添加媒体流并不触法任何状态变化直到CommitStreamChanges方法被调用。
语法
virtual void AddStream(LocalMediaStreamInterface* stream) = 0;
参数
stream
[in] Pointer to the local media stream to be added.
PeerConnectionInterface::RemoveStream
删除一个本地媒体流到用户代理正在尝试向对端传送的媒体流数组。这个函数只是添加媒体流并不触法任何媒体流状态变化直到CommitStreamChanges方法被调用。
语法
virtual void RemoveStream(LocalMediaStreamInterface* stream) = 0;
参数
stream
[in] Pointer to the local media stream to be removed.
PeerConnectionInterface::CommitStreamChanges
提交AddStream和RemoveStream调用后造成的媒体流的变化。新媒体流被添加后开始发送媒体,媒体流被移除后停止发送媒体流。
语法
virtual void CommitStreamChanges() = 0;
PeerConnectionInterface::Close
关闭当前的会话。这会触法发送一个Shutdown消息并且ready_state会切换到kClosing。
语法
virtual void Close() = 0;
PeerConnectionInterface::ready_state
返回对象的, 由枚举类型ReadyState表示。
语法
virtual ReadyState ready_state() = 0;
PeerConnectionInterface::sdp_state
返回 SDP代理的状态, 由枚举类型SdpState表示。
语法
virtual SdpState sdp_state() = 0;

引用

目前HTML5的WebRTC规范说明:

WebRTC Native API 的源码:

客户端和服务器Demo:

Read more

60个“特征工程”计算函数(Python代码)

60个“特征工程”计算函数(Python代码)

转自:coggle数据科学 近期一些朋友询问我关于如何做特征工程的问题,有没有什么适合初学者的有效操作。 特征工程的问题往往需要具体问题具体分析,当然也有一些暴力的策略,可以在竞赛初赛前期可以带来较大提升,而很多竞赛往往依赖这些信息就可以拿到非常好的效果,剩余的则需要结合业务逻辑以及很多其他的技巧,此处我们将平时用得最多的聚合操作罗列在下方。 最近刚好看到一篇文章汇总了非常多的聚合函数,就摘录在下方,供许多初入竞赛的朋友参考。 聚合特征汇总 pandas自带的聚合函数 * 其它重要聚合函数 其它重要聚合函数&分类分别如下。 def median(x):     return np.median(x) def variation_coefficient(x):     mean = np.mean(x)     if mean != 0:         return np.std(x) / mean     else:         return np.nan def variance(x):     return

By Ne0inhk
90w,确实可以封神了!

90w,确实可以封神了!

要说24年一定最热的技术,还得是AIGC! 前段时间阿里旗下的开源项目,登上GitHub热榜! AI大热,如今ChatGPT的优异表现,必然会出现各种细分场景应用的工具软件,和大量岗位项目! 山雨欲来风满楼,强人工智能的出现,所有科技公司已经开始巨量扩招此领域的人才。算法的岗位,近三个月已经增长68%!这件事在HR届也是相当震撼的。 目前各行各业都不景气的市场,人工智能岗位却一直保持常青!甚至同属AI边缘岗都比其他岗薪资高40%! 与此同时,AI算法岗上岸也不简单,竞争激烈,好公司核心岗位不用说,谁都想去。 所以事实就是,想要上岸,门槛也逐渐变高,项目经历、实习经历都很重要,越早明白这个道理就越能提前建立起自己的优势。 但我在b站逛知识区的时候,经常看到有些同学,因为一些客观原因导致无法参加实习,这种情况下,如果你想提升背景,增加项目经历的话,可以试试这个《CV/NLP 算法工程师培养计划》。 目前已经有上千位同学通过该计划拿到offer了,最新一期学员就业薪资最高能拿到78K!年薪94w! 优势就是有BAT大厂讲师带领,手把手带做AI真实企业项目(包含CV、NLP等

By Ne0inhk
再见nohup!试试这个神器,Python Supervisor!

再见nohup!试试这个神器,Python Supervisor!

👇我的小册 45章教程:() ,原价299,限时特价2杯咖啡,满100人涨10元。 作者丨Ais137 https://juejin.cn/post/7354406980784373798 1. 概述 Supervisor 是一个 C/S 架构的进程监控与管理工具,本文主要介绍其基本用法和部分高级特性,用于解决部署持久化进程的稳定性问题。 2. 问题场景 在实际的工作中,往往会有部署持久化进程的需求,比如接口服务进程,又或者是消费者进程等。这类进程通常是作为后台进程持久化运行的。 一般的部署方法是通过 nohup cmd & 命令来部署。但是这种方式有个弊端是在某些情况下无法保证目标进程的稳定性运行,有的时候 nohup 运行的后台任务会因为未知原因中断,从而导致服务或者消费中断,进而影响项目的正常运行。 为了解决上述问题,通过引入 Supervisor 来部署持久化进程,提高系统运行的稳定性。 3. Supervisor 简介 Supervisor is a client/

By Ne0inhk
第一本给程序员看的AI Agent图书上市了!

第一本给程序员看的AI Agent图书上市了!

AI Agent火爆到什么程度? OpenAI创始人奥特曼预测,未来各行各业,每一个人都可以拥有一个AI Agent;比尔·盖茨在2023年层预言:AI Agent将彻底改变人机交互方式,并颠覆整个软件行业;吴恩达教授在AI Ascent 2024演讲中高赞:AI Agent是一个令人兴奋的趋势,所有从事AI开发的人都应该关注。而国内的各科技巨头也纷纷布局AI Agent平台,如:钉钉的AI PaaS、百度智能云千帆大模型平台等等。 Agent 是未来最重要的智能化工具。对于程序员来说,是时候将目光转向大模型的应用开发了,率先抢占AI的下一个风口AI Agent。 小异带来一本新书《大模型应用开发 动手做 AI Agent》,这本书由《GPT图解》的作者黄佳老师创作,从0到1手把手教你做AI Agent。现在下单享受5折特惠! ▼点击下方,即可5折起购书 有这样一本秘籍在手,程序员们这下放心了吧,让我们先来揭开 Agent 的神秘面纱。 AI Agent 面面观

By Ne0inhk