深入解析iOS视频录制(二):自定义UI的实现

深入解析 iOS 视频录制(一):录制管理核心MWRecordingController 类的设计与实现
深入解析iOS视频录制(二):自定义UI的实现
深入解析 iOS 视频录制(三):完整录制流程的实现与整合
引言
在上一篇博客中,我们深入解析了 iOS 视频录制功能的核心类 MWRecordingController 的实现,涵盖了如何管理视频会话、设置输入输出、控制摄像头以及录制的启动与停止等重要功能。本篇博客将接着上文,探索自定义 UI 的实现,重点讲解如何通过 MWRecordingPreview 预览视图、MWRcordingControlView 控制视图以及精心设置的自定义按钮来提升视频录制的用户体验。
我们将逐步揭开这些自定义 UI 组件背后的设计与实现,了解如何通过灵活的视图布局与动画效果,让录制过程更加直观与流畅。希望通过本篇博客,能够帮助大家更深入地理解如何在 iOS 中定制出高质量的视频录制界面。
UI实现
在视频录制功能中,UI 设计不仅仅是视觉呈现,更是与用户交互的桥梁。一个直观、流畅且具有良好反馈的界面,能够大大提升用户的使用体验。通过自定义 UI,我们能够精细控制各个交互细节,确保用户能够快速而顺畅地完成录制操作。
本篇博客将从三个核心部分入手,详细讲解自定义 UI 的实现:
- 预览视图的实现:如何设计并展示视频录制的预览内容,确保录制时用户能够实时看到画面。
- 控制视图的实现:包括录制、暂停、重新录制以及完成按钮等,通过合理布局和状态管理,使得控制操作清晰易懂。
- 顶部导航栏视图的实现:导航栏中的返回按钮与切换摄像头按钮如何与视频录制功能进行无缝集成。
接下来,我们将逐一展开讲解这些关键视图的设计与实现,带大家了解如何通过代码构建一个高效且美观的视频录制界面。
MWRecordingPreview:预览视图的实现
MWRecordingPreview 类是整个视频录制界面中关键部分之一,它负责显示来自摄像头的实时视频预览。在本次实现中,我们简化了设计,确保预览层与录制会话紧密配合,并通过简单的配置来实现画面显示。
以下是 MWRecordingPreview 类的实现代码:
import UIKit
import AVFoundationclass MWRecordingPreview: UIView {override init(frame: CGRect) {super.init(frame: frame)previewLayer.videoGravity = .resizeAspectFill}required init?(coder: NSCoder) {fatalError("init(coder:) has not been implemented")}override class var layerClass: AnyClass {return AVCaptureVideoPreviewLayer.self}/// 预览图层var previewLayer: AVCaptureVideoPreviewLayer {return layer as! AVCaptureVideoPreviewLayer}/// 设置图层会话var session:AVCaptureSession? {didSet {previewLayer.session = session}}
}
- layerClass:通过重写 layerClass 方法,我们指定了该视图的图层类型为 AVCaptureVideoPreviewLayer,这是一个专门用于显示摄像头预览内容的图层类。
- previewLayer:该属性返回类型为A VCaptureVideoPreviewLayer 的图层,我们可以通过它来访问与摄像头相关的配置。
- session:这个属性用来设置 AVCaptureSession,它是视频录制功能的核心,管理着输入输出设备以及数据流。通过 didSet 方法,当会话对象被设置时,预览层的 session 会自动与之绑定,从而实现实时预览功能。
通过这种简单的实现,我们就能将摄像头的实时图像呈现在自定义视图 MWRecordingPreview 中,并且具备了灵活的图像填充方式,使用 .resizeAspectFill 可以确保预览画面根据视图的大小自适应显示。
MWRecordingControlView:控制视图的实现
MWRecordingControlView 类负责管理视频录制过程汇总的交互空间,包括录制按钮、录制时间显示、重新录制按钮以及完成按钮。通过合理布局与状态管理,确保用户能够清晰地了解录制进度,并灵活地控制录制行为。
以下是 MWRecordingControlView 类的实现代码:
import UIKitenum MWRecordingControlState {/// 正常case normal/// 录制中case recording/// 录制完成case finish
}class MWRecordingControlView: UIView {/// 录制按钮private let recordButton = MWRecordingButton()/// 录制时间private let recordTimeLabel = UILabel()/// 重新录制按钮private let reRecordButton = MWRecordingItemButton()/// 完成按钮private let finishButton = MWRecordingItemButton()/// 录制按钮点击事件回调var recordButtonClickBlock: (() -> Void)?/// 重新录制点击回调var reRecordButtonClickBlock: (() -> Void)?/// 完成点击回调var finishButtonClickBlock: (() -> Void)?override init(frame: CGRect) {super.init(frame: frame)setupView()setLayout()setEvent()setRecordingState(state: .normal)}required init?(coder: NSCoder) {fatalError("init(coder:) has not been implemented")}private func setupView() {// 录制按钮addSubview(recordButton)// 录制时间addSubview(recordTimeLabel)recordTimeLabel.textColor = .whiterecordTimeLabel.font = MWFontHelper.font(name: .nunito, size: 14, weight: .bold)// 重新录制按钮addSubview(reRecordButton)reRecordButton.setImage(UIImage(named: "recording_retake"), for: .normal)reRecordButton.setTitle(MWLocaleStringHelper.getString("Retake"), for: .normal)reRecordButton.setTitleColor(.white, for: .normal)reRecordButton.titleLabel?.font = MWFontHelper.font(name: .nunito, size: 14, weight: .bold)reRecordButton.titleLabel?.textAlignment = .center// 完成按钮addSubview(finishButton)finishButton.setImage(UIImage(named: "recording_complete"), for: .normal)finishButton.setTitle(MWLocaleStringHelper.getString("Complete"), for: .normal)finishButton.setTitleColor(.white, for: .normal)finishButton.titleLabel?.font = MWFontHelper.font(name: .nunito, size: 14, weight: .bold)finishButton.titleLabel?.textAlignment = .center}private func setLayout() {// 录制按钮recordButton.snp.makeConstraints { make inmake.centerX.equalToSuperview()make.top.equalToSuperview()make.width.height.equalTo(72.0)}// 录制时间recordTimeLabel.snp.makeConstraints { make inmake.centerX.equalToSuperview()make.top.equalTo(recordButton.snp.bottom).offset(12.0)make.height.equalTo(19.0)}// 重新录制按钮reRecordButton.snp.makeConstraints { make inmake.trailing.equalTo(recordButton.snp.leading).offset(-44.0)make.width.equalTo(64.0)make.height.equalTo(63.0)make.centerY.equalTo(recordButton)}// 完成按钮finishButton.snp.makeConstraints { make inmake.leading.equalTo(recordButton.snp.trailing).offset(44.0)make.width.equalTo(64.0)make.height.equalTo(63.0)make.centerY.equalTo(recordButton)}}private func setEvent() {// 录制按钮recordButton.addTarget(self, action: #selector(recordButtonClick), for: .touchUpInside)// 重新录制按钮reRecordButton.addTarget(self, action: #selector(reRecordButtonClick), for: .touchUpInside)// 完成按钮finishButton.addTarget(self, action: #selector(finishButtonClick), for: .touchUpInside)}/// 录制事件@objc private func recordButtonClick() {recordButtonClickBlock?()}/// 重新录制事件@objc private func reRecordButtonClick() {reRecordButtonClickBlock?()}/// 完成事件@objc private func finishButtonClick() {finishButtonClickBlock?()}/// 设置录制状态/// - Parameter state: 状态func setRecordingState(state: MWRecordingControlState) {switch state {case .normal:recordButton.isSelected = truerecordTimeLabel.isHidden = truereRecordButton.isHidden = truefinishButton.isHidden = truecase .recording:recordButton.isSelected = falserecordTimeLabel.isHidden = falsereRecordButton.isHidden = truefinishButton.isHidden = truecase .finish:recordButton.isSelected = truerecordTimeLabel.isHidden = falsereRecordButton.isHidden = falsefinishButton.isHidden = false}}/// 更新时间/// - Parameter time: 时间func updateTime(time: TimeInterval) {recordTimeLabel.text = time.formattedMS}
}
MWRecordingControlView 提供了以下几个核心功能:
- 录制按钮(recordButton):用于控制录制的开始和暂停。根据状态变化,按钮的样式会自动调整。
- 录制时间(recordTimeLabel):显示当前录制的时长,动态更新。
- 重新录制按钮(reRecordButton):在录制完成后,允许用户重新开始录制。
- 完成按钮(finishButton):会在点击完成时,将录制好的音频文件传递到需要的地方。
通过设置不同的录制状态(normal、recording和finish),控制视图中的各个按钮和标签的显示与隐藏,确保用户能够清晰地看到当前操作的状态。
MWRecordingButton:录制按钮
MWRecordingButton 是自定义的录制按钮,通过多层图层效果展现录制状态,并使用CALayer和CAGradientLayer创建了独特的视觉效果。其设计目标是提供一个既美观又符合录制功能需求的按钮,用户可以通过点击它来启动或停止视频录制。
以下是 MWRecordingButton 类的实现代码:
import UIKitclass MWRecordingButton: UIButton {/// 大圆图层private let bigCircleLayer = CALayer()/// 小圆图层private let smallCircleLayer = CALayer()/// 方形图层private let squareLayer = CAGradientLayer()override init(frame: CGRect) {super.init(frame: frame)setupLayer()}required init?(coder: NSCoder) {fatalError("init(coder:) has not been implemented")}private func setupLayer() {// 大圆bigCircleLayer.backgroundColor = UIColor.white.withAlphaComponent(0.6).cgColorbigCircleLayer.cornerRadius = 36.0layer.addSublayer(bigCircleLayer)// 小圆smallCircleLayer.backgroundColor = UIColor.white.withAlphaComponent(1.0).cgColorsmallCircleLayer.cornerRadius = 30layer.addSublayer(smallCircleLayer)// 方形squareLayer.colors = [UIColor.wm_hex("FF3498").cgColor, UIColor.wm_hex("FF4545").cgColor]squareLayer.cornerRadius = 6.0layer.addSublayer(squareLayer)}override var isSelected: Bool {didSet {squareLayer.isHidden = isSelected}}override func layoutSubviews() {super.layoutSubviews()let width = bounds.widthlet height = bounds.height// 大圆bigCircleLayer.frame = CGRect(x: 0, y: 0, width: width, height: height)// 小圆let smallWidth = 60.0smallCircleLayer.frame = CGRect(x: (width - smallWidth) / 2, y: (height - smallWidth) / 2, width: smallWidth, height: smallWidth)// 方形let squareWidth = 25.0squareLayer.frame = CGRect(x: (width - squareWidth) / 2, y: (height - squareWidth) / 2, width: squareWidth, height: squareWidth)}
}
- 大圆图层(bigCircleLayer):这个圆形图层充当按钮的背景,使用 CALayer 创建,设置了半透明白色背景,使其看起来既简洁又具有层次感。
- 小圆图层 (smallCircleLayer):这个圆形图层在大圆内部显示,颜色为纯白,模拟了录制按钮中的核心圆形。
- 方形图层(squareLayer):这个图层使用 CAGradientLayer 绘制了一个渐变色的矩形,位于小圆的中心。它的显示与按钮的选择状(isSelected)态相关,状态为selected时,方形会被隐藏。
通过这种设计,MWRecordingButton在录制和暂停状态之间切换时,能够清晰地反馈状态,用户一眼就能判断当前按钮的作用,同时通过动态的图层切换,使得界面更加生动。
MWRecordingNavigationView:导航栏
MWRecordingNavigationView 是自定义的视频录制界面顶部导航栏视图,它包含了三个主要组件:返回按钮、切换摄像头按钮和一个可定制的中间文案标签。这个视图旨在为用户提供流畅的操作体验,在录制过程中可以方便地进行控制和反馈。
以下是 MWRecordingNavigationView 类的实现代码:
import UIKitclass MWRecordingNavgationView: UIView {/// 返回按钮private let backButton = UIButton()/// 切换摄像头按钮private let switchCameraButton = UIButton()/// 返回按钮点击事件var backButtonClickBlock: (() -> Void)?/// 切换摄像头按钮点击事件var switchCameraButtonClickBlock: (() -> Void)?/// 隐藏显示切换按钮var isHiddenSwitchCameraButton: Bool = false {didSet {switchCameraButton.isHidden = isHiddenSwitchCameraButton}}override init(frame: CGRect) {super.init(frame: frame)setupView()setLayout()setEvent()}required init?(coder: NSCoder) {fatalError("init(coder:) has not been implemented")}private func setupView() {// 返回按钮addSubview(backButton)backButton.setImage(UIImage(named: "navigation_back_white"), for: .normal)// 切换摄像头按钮addSubview(switchCameraButton)switchCameraButton.setImage(UIImage(named: "navigation_switch_camera"), for: .normal)}private func setLayout() {// 设置返回按钮的布局backButton.snp.makeConstraints { make inmake.leading.equalToSuperview().offset(16.0)make.centerY.equalToSuperview()make.width.height.equalTo(32.0)}// 设置切换摄像头按钮的布局switchCameraButton.snp.makeConstraints { make inmake.trailing.equalToSuperview().offset(-16.0)make.centerY.equalToSuperview()make.width.height.equalTo(32.0)}}private func setEvent() {// 返回按钮点击事件backButton.addTarget(self, action: #selector(backButtonClick), for: .touchUpInside)// 切换摄像头按钮点击事件switchCameraButton.addTarget(self, action: #selector(switchCameraButtonClick), for: .touchUpInside)}@objc private func backButtonClick() {backButtonClickBlock?()}@objc private func switchCameraButtonClick() {switchCameraButtonClickBlock?()}
}
- 返回按钮(backButton):通过UIButton实现,提供一个简单的返回操作,用户可以随时退出当前的录制界面。图标为白色箭头,易于辨识。
- 切换摄像头(switchCameraButton):也是一个UIButton,用于切换前后摄像头。在某些应用场景下,用户可能需要切换摄像头,这个按钮就提供了这个功能。
结语
在本文中,我们详细探讨了 iOS 视频录制功能中的自定义 UI 实现,包括预览视图、控制视图和导航栏的设计与实现。这些自定义组件不仅提升了用户体验,还确保了操作的流畅性和可控性。通过自定义 MWRecordingPreview 视图,我们为录制过程提供了实时的视频预览;通过设计 MWRecordingControlView 和 MWRecordingButton,我们实现了清晰直观的录制控制;而 MWRecordingNavigationView 则为用户提供了便捷的导航和摄像头切换功能。
这些 UI 组件的灵活性和可定制性,使得在开发过程中可以根据需求对界面进行调整与扩展。在未来的版本中,您可以继续根据产品需求对这些视图进行优化和改进,带给用户更加丰富和优质的录制体验。
通过对这些自定义 UI 组件的解析,我们希望能够帮助开发者们更好地理解和实现 iOS 视频录制功能,并为其应用增添更多个性化的设计。感谢您的阅读,期待您的探索和创新!
相关文章:
深入解析iOS视频录制(二):自定义UI的实现
深入解析 iOS 视频录制(一):录制管理核心MWRecordingController 类的设计与实现 深入解析iOS视频录制(二):自定义UI的实现 深入解析 iOS 视频录制(三):完…...
跳表的C语言实现
跳表(Skip List)是一种基于链表的动态数据结构,用于实现高效的查找、插入和删除操作。它通过引入多级索引来加速查找过程,类似于多级索引的有序链表。跳表的平均时间复杂度为 O(logn),在某些场景下可以替代平衡树。 以…...
Java Web开发实战与项目——Spring Security与权限管理实现
Web应用中,权限管理是系统安全的核心部分,确保用户只能访问他们被授权的资源。Spring Security是Spring框架中的一个安全框架,它提供了强大的认证和授权功能,用于实现用户认证和权限控制。本章节将详细讲解如何使用Spring Securit…...
单元测试方法的使用
import java.util.Date; import org.junit.Test; /** java中的JUnit单元测试* * 步骤:* 1.选中当前项目工程 --》 右键:build path --》 add libraries --》 JUnit 4 --》 下一步* 2.创建一个Java类进行单元测试。* 此时的Java类要求:①此类是公共的 ②此类提供一个公共的无参…...
VScode内接入deepseek包过程(本地部署版包会)
目录 1. 首先得有vscode软件 2. 在我们的电脑本地已经部署了ollama,我将以qwen作为实验例子 3. 在vscode上的扩展商店下载continue 4. 下载完成后,依次点击添加模型 5. 在这里可以添加,各种各样的模型,选择我们的ollama 6. 选…...
flink写入hdfs数据如何保证幂等的?
在 Flink 中使用 HDFS Connector 将数据写入 HDFS 时,保证幂等性是一个重要的需求,尤其是在数据可靠性要求较高的场景下。以下是详细介绍如何通过 Flink 和 HDFS 的特性以及一些设计上的优化来实现幂等性。 一、Flink 的 Checkpoint 机制 Flink 的 Chec…...
newgrp docker需要每次刷新问题
每次都需要运行 newgrp docker 的原因: 当用户被添加到 docker 组后,当前会话并不会立即更新组信息,因此需要通过 newgrp docker 切换到新的用户组以使权限生效 如果不想每次都手动运行 newgrp docker,可以在终端中配置一个自动刷新的脚本。…...
LM_Funny-2-01 递推算法:从数学基础到跨学科应用
目录 第一章 递推算法的数学本质 1.1 形式化定义与公理化体系 定理1.1 (完备性条件) 1.2 高阶递推的特征分析 案例:Gauss同余递推4 第二章 工程实现优化技术 2.1 内存压缩的革新方法 滚动窗口策略 分块存储技术 2.2 异构计算加速方案 GPU并行递推 量子计…...
WDM_OTN_基础知识_波分站点与组网类型
为了便于理解,我们用高铁来打个比方,这是郑州与武汉的高铁,中间经过了许昌孝感等很多个站点,郑州武汉作为始发站和终点站,所有人员都是上车或下车,而许昌等中间站点,既有人员上下车,…...
机器视觉--索贝尔滤波
引言 在图像处理领域,边缘检测是一项至关重要的任务,它能够帮助我们识别图像中不同区域的边界,为后续的目标识别、图像分割等操作奠定基础。索贝尔滤波(Sobel Filter)作为一种经典的边缘检测算法,因其简单…...
网络分析仪E5071C的回波损耗测量
回波损耗(Return Loss)是评估射频/微波元件(如滤波器、天线、电缆等)信号反射特性的关键参数,反映端口阻抗匹配性能。E5071C矢量网络分析仪(VNA)通过以下步骤实现高精度回波损耗测量:…...
力扣-二叉树-98 验证二叉搜索树
思路 第一个特性,二叉搜索树的中序遍历是有序的,第二个特性,利用两个指针判断大小关系 代码 class Solution { public:TreeNode* pre NULL;bool isValidBST(TreeNode* root) {if(root NULL) return true;bool left isValidBST(root->…...
【动态规划】详解 0-1背包问题
文章目录 1. 问题引入2. 从 dfs 到动态规划3. 动态规划过程分析4. 二维 dp 的遍历顺序5. 从二维数组到一维数组6. 一维数组的遍历次序7. 背包的遍历顺序8. 代码总结9. 总结 1. 问题引入 0-1 背包是比较经典的动态规划问题,这里以代码随想录里面的例子来介绍下。总的…...
【Java线程池与线程状态】线程池分类与最佳实践
解析Java线程池与线程状态变化,结合运行机制与业务场景对照,帮助形成系统性知识。 一、线程池核心要素(五维模型) 采用「参数配置→处理流程→工作模式」三层递进结构 核心参数(线程池DNA) corePoolSiz…...
【小白学AI系列】NLP 核心知识点(八)多头自注意力机制
文章目录 **多头自注意力机制(Multi-Head Self-Attention)****核心概念** **1. 自注意力机制(Self-Attention)****2. 多头机制(Multi-Head Attention)****3. 为什么要用多头注意力机制?****4. 公…...
学习笔记——word中图目录、表目录 标题引用
目标1: 建立——图1-1 引用——图1-1 1在word文档中的引用——>插入题注 新建标签,然后命名为“图1-“。 点击确认,即可插入如图所示 图1- 1 春天 需要把图1-和后面那个1中间的空格删除,即 图1-1 春天 2怎么去引用这个“…...
3.3 Hugging Face Transformers核心功能模块深度解析
Hugging Face Transformers核心功能模块深度解析 一、模块化架构总览 #mermaid-svg-wxTV5vrEo7Y57IlW {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-wxTV5vrEo7Y57IlW .error-icon{fill:#552222;}#mermaid-svg-wxT…...
linux中设置脚本定时执行ntp命令同步时间
目录 一、背景二、过程1.到系统目录2.安装ntp3.创建文件夹4.创建脚本文件5.提升脚本文件权限6.设置执行时间:7.检查是否设置了执行器(执行后输出的内容为执行器中的定时执行内容)8.执行脚本文件9.查看日志文件,是否执行成功 三、总…...
map的使用(c++)
在了解map之前,我们先看看两个场景,通过这两个场景的对比,让我们知道为什么要存在存储双关键字的容器 场景一:判断一堆字符串中,某一个字符串是否出现过 在没学set容器之前,我们只能想到把这一堆字符串存到…...
毕业设计—基于Spring Boot的社区居民健康管理平台的设计与实现
🎓 毕业设计大揭秘!想要源码和文章?快来私信我吧! Hey小伙伴们~ 👋 毕业季又来啦!是不是都在为毕业设计忙得团团转呢?🤔 别担心,我这里有个小小的福利要分享给你们哦&…...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...
工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...
dedecms 织梦自定义表单留言增加ajax验证码功能
增加ajax功能模块,用户不点击提交按钮,只要输入框失去焦点,就会提前提示验证码是否正确。 一,模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...
Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...
uniapp微信小程序视频实时流+pc端预览方案
方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度WebSocket图片帧定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐RTMP推流TRTC/即构SDK推流❌ 付费方案 (部分有免费额度&#x…...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...
华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...
