当前位置: 首页 > article >正文

基于SendBird SDK的iOS即时通讯应用架构与最佳实践详解

1. 项目概述一个iOS即时通讯的“样板间”如果你正在为你的iOS应用寻找一个功能完整、架构清晰的即时通讯IM功能实现参考那么sendbird/sendbird-chat-sample-ios这个GitHub仓库绝对值得你花上半天时间好好研究。它不是一个简单的“Hello World”演示而是一个由SendBird官方维护的、高度工程化的iOS聊天应用示例。你可以把它理解为一个精装修的“样板间”里面不仅展示了如何用SendBird SDK砌墙铺砖实现基础聊天更展示了如何规划空间、布置水电处理消息流、管理频道、优化用户体验等高级功能甚至预埋了未来扩展的接口。对于需要集成IM功能的iOS开发者无论是评估SendBird服务还是学习其SDK的最佳实践这个项目都是一个不可多得的起点。它直接跳过了从零搭建的繁琐让你能快速上手并理解在一个生产级应用中一个健壮的聊天模块应该如何被构建。2. 核心架构与设计思路拆解2.1 为什么选择SendBird SDK作为基础在动手之前理解“为什么是SendBird”至关重要。市面上IM解决方案众多从自研到第三方云服务如SendBird、Agora、腾讯云IM等。这个示例项目选择SendBird SDK作为基石背后有几层考量。首先功能完整性SendBird提供了从一对一聊天、群组聊天、开放频道到消息推送、已读回执、输入状态指示等一整套“开箱即用”的功能避免了开发者从传输协议如WebSocket开始重造轮子。其次平台专注性其iOS SDK是原生开发的对Swift和Objective-C都有良好支持性能优化和内存管理更贴近苹果生态。最后可扩展性SDK设计考虑了大规模应用场景如消息分页加载、频道列表懒加载等这个示例项目正是为了展示如何正确使用这些高级特性。注意选择第三方IM服务时除了功能还需重点评估其网络覆盖质量尤其是国内访问的延迟和稳定性、数据合规性数据存储区域、以及长期的技术支持与版本更新计划。SendBird作为国际服务在国内直接访问可能存在延迟通常需要配合合规的加速方案来优化用户体验但这部分配置不在示例项目的讨论范围内。2.2 示例项目的整体架构设计打开项目你会发现它并非一个简单的单视图应用。它采用了经典的MVCModel-View-Controller模式但通过清晰的文件夹结构进行了强化组织。通常你会看到类似这样的目录Models/: 这里定义了应用的核心数据模型。除了直接使用SendBird SDK提供的SBDUser,SBDGroupChannel等类项目通常会创建一些包装类或扩展以适配自定义UI或业务逻辑。例如一个ChatMessage类它内部封装了SBDUserMessage并添加了用于UI显示的属性如计算出的消息气泡大小、发送状态发送中/发送成功/发送失败等。Views/: 包含所有的自定义UI组件。最关键的是消息列表单元格MessageTableViewCell、输入工具栏MessageInputView以及频道列表单元格。这些视图组件被设计为高度可配置和可复用的它们通过IBOutlet或代码方式与模型数据绑定。ViewControllers/: 这是业务逻辑的核心。主要包含两个重要的控制器ChannelListViewController: 负责获取、展示和管理用户的聊天频道列表。它会处理频道的创建、加入、离开以及列表的排序通常按最后一条消息的时间倒序。ChatViewController: 聊天界面的“大脑”。它负责消息的发送、接收、显示、分页加载、处理已读回执、管理输入状态以及处理各种用户交互如长按消息复制、删除、重发等。Managers/或Utilities/: 这里存放着一些全局的单例或工具类。最重要的莫过于SendBirdManager或ChatManager。这个类封装了所有与SendBird SDK的直接交互如初始化、连接/断开连接、用户认证等。这样做的好处是业务逻辑与SDK调用解耦未来如果更换IM服务商大部分改动可以集中在这个管理类中。Resources/: 存放图片、音效、本地化字符串文件等。这种架构确保了代码的清晰度和可维护性是中型以上IM功能模块的推荐设计。3. 关键模块深度解析与实操要点3.1 用户认证与连接管理这是所有IM功能的起点。示例项目通常会展示两种常见的用户管理方式基于用户ID的简单连接和基于访问令牌Access Token的安全连接。1. 简单连接不推荐用于生产环境// 在AppDelegate或专门的启动管理器中 SBDMain.initWithApplicationId(“YOUR_APP_ID”) // 在用户登录后 SBDMain.connect(withUserId: userId) { user, error in if let error error { // 处理连接失败 return } // 连接成功user对象包含当前用户信息 // 可以更新UI或跳转到频道列表 }这种方式简单但安全性较低因为任何知道用户ID的人都可以模拟该用户连接。2. 基于访问令牌的连接生产环境推荐这种方式需要你的应用服务器参与。流程是你的iOS应用将用户ID发送到你的后端服务器。你的服务器使用SendBird Dashboard上生成的Master API Token调用SendBird的服务器API为该用户ID生成一个唯一的、有时效性的Access Token。服务器将Access Token返回给iOS客户端。客户端使用User ID和Access Token进行连接。SBDMain.connect(withUserId: userId, accessToken: accessToken) { user, error in // 处理连接结果 }示例项目可能会模拟这个过程但真正的服务器端集成需要你自行实现。实操心得务必在AppDelegate的applicationWillResignActive或applicationDidEnterBackground中考虑断开连接并在applicationDidBecomeActive中重连以节省用户设备资源和流量。但要注意重连逻辑避免过于频繁的断线重连导致用户被踢出。3.2 频道列表的高效管理与展示ChannelListViewController是用户进入应用后看到的第一个界面其性能体验至关重要。1. 列表数据获取SendBird SDK 提供了SBDGroupChannelListQuery对象来分页获取频道列表。示例项目会演示如何正确配置这个查询let query SBDGroupChannel.createMyGroupChannelListQuery() query?.limit 20 // 每页加载数量 query?.order .chronological // 或 .latestLastMessage query?.includeEmptyChannel false // 是否包含无消息的频道 query?.includeFrozenChannel true // 是否包含被冻结的频道首次加载时使用query.loadNextPage(completionHandler:)。当用户滚动到底部时再次调用该方法加载下一页。2. 实时更新频道列表需要实时反映新消息的到来。这通过监听SendBird的委托Delegate方法实现// 在ChannelListViewController中遵守SBDChannelDelegate协议 func channel(_ sender: SBDBaseChannel, didReceive message: SBDBaseMessage) { // 当收到新消息时 // 1. 找到本地列表中对应的频道对象 // 2. 更新该频道的lastMessage等属性 // 3. 对列表进行重新排序按最后消息时间 // 4. 刷新TableView的对应行或整个列表 }3. 性能优化技巧避免全表刷新在didReceive message中精确找到发生变化的频道索引使用tableView.reloadRows(at:with:)而非reloadData()。图片异步加载频道封面图通常是其他成员的头像应使用像SDWebImage或Kingfisher这样的库进行异步加载和缓存。Cell重用优化确保在cellForRowAt方法中正确配置和重置cell的状态避免因cell重用导致的内容错乱。3.3 聊天界面的核心实现ChatViewController是整个示例最复杂的部分它需要协调消息流、UI更新和用户输入。1. 消息数据源与分页加载与频道列表类似消息列表也需要分页查询使用SBDPreviousMessageListQuery。var messageQuery: SBDPreviousMessageListQuery? // 初始化查询 messageQuery channel.createPreviousMessageListQuery() messageQuery?.limit 30 // 加载初始消息最新的30条 messageQuery?.loadPreviousMessages(completionHandler: { messages, error in // 将消息逆序后加入数据源因为loadPreviousMessages加载的是更旧的消息 // 刷新TableView }) // 当用户滚动到顶部加载更早的历史消息时 messageQuery?.loadPreviousMessages(completionHandler: { messages, error in // 将新加载的旧消息插入数据源头部 // 使用tableView.insertRows或reloadData并保持滚动位置 })2. 消息的发送与状态管理发送消息不是简单的调用API还需要在UI上给予即时反馈。// 1. 先在本地数据源插入一个“发送中”状态的消息对象 let pendingMessage MyMessage(text: inputText, sender: currentUser, status: .sending) self.messages.append(pendingMessage) self.tableView.reloadData() scrollToBottom() // 2. 调用SDK发送 channel.sendUserMessage(inputText) { userMessage, error in DispatchQueue.main.async { // 3. 找到本地那个“发送中”的消息 // 4. 根据error判断成功则更新其状态为.sent并替换为服务器返回的userMessage包含messageId等失败则更新状态为.failed // 5. 刷新对应的Cell } }这种“乐观更新”能极大提升用户体验的流畅度。3. 实时接收与插入消息通过SBDChannelDelegate的didReceive message方法接收新消息。这里的关键是判断消息是否属于当前打开的频道以及如何插入到列表底部并平滑滚动。func channel(_ sender: SBDBaseChannel, didReceive message: SBDBaseMessage) { guard sender.channelUrl self.currentChannel?.channelUrl else { return } DispatchQueue.main.async { self.messages.append(message) // 仅当用户处于列表底部或附近时才自动滚动到底部 if self.isNearBottom { self.tableView.insertRows(at: [IndexPath(row: self.messages.count-1, section: 0)], with: .none) self.scrollToBottom(animated: true) } else { // 否则只更新数据源可能显示一个“新消息”提示按钮 self.updateUnreadMessageIndicator() } } }4. 高级功能与用户体验打磨4.1 已读回执Read Receipt与输入状态Typing Indicator这两个功能是提升聊天“临场感”的关键。已读回执SendBird SDK会自动跟踪频道内每条消息的已读状态。你需要做的是在ChatViewController的viewWillAppear和每次收到新消息并展示时调用channel.markAsRead()来上报“我已读”。在频道列表和聊天界面通过channel.getUnreadMessageCount()和channel.getReadReceipt(of:)来获取未读计数和特定消息的已读用户列表并更新UI。输入状态// 当用户开始输入时 channel.startTyping() // 当用户停止输入如发送消息或清空输入框时 channel.endTyping() // 监听其他用户的输入状态 func channel(_ sender: SBDGroupChannel, didUpdateTypingStatus status: SBDTypingStatus) { // status.typingMembers 包含正在输入的用户数组 // 更新UI例如在导航栏或输入框上方显示“对方正在输入...” }注意startTyping和endTyping的调用需要有节流Throttle机制例如设置一个最小时间间隔如0.5秒避免用户每按一个键就触发一次网络请求造成不必要的流量消耗和服务器压力。4.2 消息的富媒体支持与本地缓存SendBird支持发送图片、文件等多种消息。示例项目会展示如何使用SBDFileMessage发送图片。let fileData UIImageJPEGRepresentation(image, 0.7) let fileParams SBDFileMessageParams(file: fileData) fileParams?.fileName “image.jpg” fileParams?.mimeType “image/jpeg” fileParams?.fileSize UInt(fileData.count) channel.sendFileMessage(with: fileParams, progressHandler: { bytesSent, totalBytesSent, totalBytesExpectedToSend in // 更新上传进度条 }, completionHandler: { fileMessage, error in // 处理发送完成 })本地缓存策略对于图片和文件强烈建议实现本地缓存。当收到SBDFileMessage后将其url指向的文件下载到本地沙盒并使用messageId或url的哈希值作为文件名存储。下次显示同一条消息时优先检查本地缓存。这不仅能加快加载速度还能在无网络时查看历史图片。4.3 推送通知集成要让应用在后台或关闭时能收到新消息提醒必须集成推送通知。示例项目通常会包含推送设置的代码片段。向APNs注册在AppDelegate中请求用户通知权限并获取设备令牌Device Token。将令牌注册到SendBird在连接SendBird成功后将设备令牌上传。SBDMain.registerDevicePushToken(deviceToken, unique: true) { status, error in // 处理注册结果 }处理推送负载当用户通过推送点击进入应用时AppDelegate的didReceiveRemoteNotification方法会触发。你需要解析推送内容其中应包含channel_url然后导航到对应的ChatViewController。5. 常见问题排查与性能优化实录在实际集成中你几乎一定会遇到下面这些问题。5.1 连接与消息收发失败排查问题现象可能原因排查步骤与解决方案连接失败返回错误1. App ID 错误。2. 网络不通。3. 用户ID/Token无效或过期。1. 检查initWithApplicationId使用的ID是否正确。2. 检查设备网络尝试切换Wi-Fi/4G。3. 检查服务器生成的Token逻辑确保未过期。开启SDK日志(SBDMain.setLogLevel(.debug))查看详细错误码。能连接但收不到消息1. 未正确加入频道。2. 未设置或未正确实现SBDChannelDelegate。3. 消息查询条件有误。1. 确认channelUrl无误并成功调用了join方法对于开放频道或确认用户是该私有频道的成员。2. 在连接成功后设置SBDMain.add(self as SBDChannelDelegate, identifier: “unique_id”)并确保委托对象未被提前释放。3. 检查messageQuery的reverse等参数设置。消息发送缓慢或失败1. 网络质量差。2. 消息内容过大如图片。3. 服务器限流或故障。1. 监听progressHandler优化大文件发送前的压缩如图片尺寸、质量。2. 实现发送队列和失败重试机制示例项目可能未包含需自行补充。3. 查看SendBird服务状态页面。5.2 列表滑动卡顿与内存优化聊天界面消息越来越多时流畅滚动是挑战。Cell高度计算避免在tableView(_:heightForRowAt:)中做复杂的实时计算。应在消息模型对象中缓存计算好的高度。对于动态文本使用boundingRect(with:options:attributes:context:)提前算好并存储。图片加载优化消息中的图片使用缩略图进行预览。SendBird的SBDFileMessage可以生成缩略图URL。在Cell中异步加载缩略图点击后再查看原图。消息数据源清理对于超长聊天记录不要无限制地加载到内存中。可以设定一个阈值如最多保存500条当加载更多历史消息时从尾部移除一些旧消息。同时将移除消息的媒体文件如图片、视频从本地缓存中清理避免沙盒无限膨胀。** Instruments 是朋友**定期使用Xcode的Instruments工具中的Time Profiler和Allocations检测性能瓶颈和内存泄漏。特别注意在Delegate、闭包中形成的循环引用使用[weak self]打破。5.3 后台运行与实时性平衡iOS应用在后台挂起后WebSocket连接可能会被系统断开。为了保持消息的实时性你需要启用后台模式在Xcode项目的Capabilities中开启“Background Modes”下的“Remote notifications”和“Voice over IP”VoIP模式可以维持更稳定的网络连接但需谨慎使用避免被App Store审核拒绝。智能重连策略在applicationDidBecomeActive中执行重连。不要在网络切换或短暂进入后台时就立即重连可以设置一个延迟和指数退避策略避免频繁重连消耗电量。依赖推送作为保底将推送通知作为实时连接失效后的保底方案。确保推送证书配置正确且能正确处理推送点击事件直达对应聊天会话。这个sendbird-chat-sample-ios项目就像一本优秀的“烹饪书”它给了你一道名菜的完整菜谱和关键步骤图解。但真正要做出适合自己餐厅口味应用的菜还需要你根据这份菜谱理解每一步的原理并针对自己的“厨房条件”业务需求、用户体验标准进行调味和改良。从克隆项目、跑通Demo开始然后尝试修改UI、添加一个自定义消息类型比如商品卡片再到实现消息搜索、消息撤回等进阶功能一步步吃透它你就能构建出一个属于自己的、体验流畅的专业级iOS聊天模块。

相关文章:

基于SendBird SDK的iOS即时通讯应用架构与最佳实践详解

1. 项目概述:一个iOS即时通讯的“样板间”如果你正在为你的iOS应用寻找一个功能完整、架构清晰的即时通讯(IM)功能实现参考,那么sendbird/sendbird-chat-sample-ios这个GitHub仓库绝对值得你花上半天时间好好研究。它不是一个简单…...

HTML函数工具在NAS设备上能运行吗_轻服务器适配指南【指南】

在NAS上运行HTML函数工具需依场景选择方案:一、用Web服务托管为静态页,由浏览器执行;二、用Docker运行Node.js容器提供API;三、通过SSHjsdom在终端模拟执行;四、前端留NAS,后端逻辑迁至云函数。如果您希望在…...

基于MCP协议构建智能Telegram助手:连接AI与外部服务的实践指南

1. 项目概述:一个连接AI与Telegram的智能桥梁如果你正在寻找一种方法,让你在Telegram上使用的AI助手(比如ChatGPT、Claude等)能够“活”起来,不仅能聊天,还能帮你查天气、看新闻、管理待办事项,…...

如何免费解锁Cursor Pro功能:开源工具完整使用指南

如何免费解锁Cursor Pro功能:开源工具完整使用指南 【免费下载链接】cursor-free-vip [Support 0.45](Multi Language 多语言)自动注册 Cursor Ai ,自动重置机器ID , 免费升级使用Pro 功能: Youve reached your trial …...

别再只用流水灯了!用Arduino和74HC595驱动数码管/点阵屏的完整教程

从流水灯到智能显示:74HC595驱动数码管与点阵屏的实战指南 在创客社区里,74HC595移位寄存器几乎成了"流水灯"的代名词——无数入门教程用它来演示如何用少量IO口控制多颗LED。但当你真正需要构建一个电子钟、温湿度显示器或简易信息板时&#…...

告别‘玄学’:用Python从零实现一个能纠3个错的BCH码(附完整代码)

告别‘玄学’:用Python从零实现一个能纠3个错的BCH码(附完整代码) 在数字通信系统中,错误控制编码是确保数据可靠传输的核心技术之一。BCH码作为一种强大的循环码,不仅能检测错误,还能纠正多个随机错误&…...

STM32模拟I2C驱动TCS34725实现环境光与颜色识别

1. 环境光与颜色识别的硬件搭档 当我们需要让设备感知周围环境的光线强弱,或者识别物体的具体颜色时,TCS34725这颗传感器绝对是性价比之选。它不仅能测量环境光强度,还能通过RGB三原色的比例来判断颜色,这在智能家居和工业检测中特…...

用Fiddler和Proxifier抓包分析易游网络验证API,手把手教你模拟合法请求

网络验证API抓包与模拟请求实战指南 在当今数字化产品生态中,网络验证机制已成为软件授权管理的核心组件。不同于传统的本地验证方式,网络验证通过远程API交互实现更高安全性的许可控制,这也使得协议层分析成为理解其工作原理的关键切入点。对…...

从零移植Debian到红米2:解锁MSM8916上的主线Linux手机体验

1. 为什么选择红米2作为Linux移植平台 红米2作为2015年发布的入门级智能手机,搭载高通骁龙410(MSM8916)平台,1GB内存8GB存储的配置在今天看来已经相当落伍。但正是这种"过时硬件"反而成为了极客们眼中的宝藏开发板。我选…...

避坑指南:树莓派4B用FFmpeg推USB摄像头流,我踩过的那些编译和权限的坑

树莓派4B USB摄像头推流实战:从编译陷阱到系统服务的深度排雷手册 当你在树莓派4B上尝试用FFmpeg推送USB摄像头流时,是否遇到过这样的场景:按照教程一步步操作,却在编译阶段卡在OMX报错,或是明明设备识别成功却提示权…...

企业级ai应用如何通过taotoken实现稳定低成本的多模型调用

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 企业级AI应用如何通过Taotoken实现稳定低成本的多模型调用 在构建面向生产环境的企业级AI应用时,开发团队常常面临两个…...

mikupad:单文件AI写作前端,兼容多后端与深度创作控制

1. 项目概述:一个单文件全能的AI写作前端如果你和我一样,经常折腾各种本地大语言模型,那你一定对“前端界面”这件事深有体会。Oobabooga的WebUI功能强大但略显臃肿,KoboldCPP的界面简洁但可定制性有限,而各种API调用又…...

基于MCP协议构建地方财政智能体:开源项目实践与开发指南

1. 项目概述:当MCP遇上地方财政,一个开源智能体的诞生最近在开源社区里,一个名为apifyforge/municipal-fiscal-intelligence-mcp的项目引起了我的注意。这个项目名听起来有点“学术”,但拆解开来,其实指向了一个非常具…...

观察Taotoken在多模型并发请求下的稳定性与响应表现

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 观察Taotoken在多模型并发请求下的稳定性与响应表现 在实际业务开发中,我们常常需要同时调用多个不同的大模型来处理不…...

NextPy全栈框架:用Python构建AI智能体Web应用

1. 项目概述:当AI智能体遇上全栈Web开发最近在开源社区里,一个名为dot-agent/nextpy的项目引起了我的注意。作为一名长期在Web开发和AI应用落地之间“反复横跳”的开发者,我深知将AI能力,特别是智能体(Agent&#xff0…...

终极PT资源管理指南:如何用auto_feed_js实现100+站点一键转载

终极PT资源管理指南:如何用auto_feed_js实现100站点一键转载 【免费下载链接】auto_feed_js PT站一键转载脚本 项目地址: https://gitcode.com/gh_mirrors/au/auto_feed_js 在PT(Private Tracker)社区中,资源分享是核心价值…...

从微服务架构设计到团队OKR:聊聊工程师日常中的‘帕累托最优’实践

从微服务架构设计到团队OKR:工程师日常中的‘帕累托最优’实践 在技术团队的实际工作中,我们常常面临各种权衡取舍:微服务拆分时如何平衡模块独立性与系统整体性能?制定OKR时怎样兼顾个人成长与团队目标?这些看似复杂的…...

GitHub加速实战指南:突破国内访问瓶颈的高效方案

GitHub加速实战指南:突破国内访问瓶颈的高效方案 【免费下载链接】Fast-GitHub 国内Github下载很慢,用上了这个插件后,下载速度嗖嗖嗖的~! 项目地址: https://gitcode.com/gh_mirrors/fa/Fast-GitHub 对于国内开发者而言&a…...

技术解析:OBS Source Record - 独立源录制解决方案

技术解析:OBS Source Record - 独立源录制解决方案 【免费下载链接】obs-source-record 项目地址: https://gitcode.com/gh_mirrors/ob/obs-source-record OBS Source Record插件通过创新的滤镜架构,解决了多源独立录制的技术难题,为…...

从零到一:翁恺C语言MOOC实战习题精解与编程思维构建

1. 为什么选择翁恺老师的C语言课程? 作为国内最受欢迎的编程入门课程之一,翁恺老师在MOOC平台上的C语言课程已经帮助超过百万学习者打开了编程世界的大门。我当年自学C语言时,也是从这套课程起步的。与其他课程相比,翁老师的教学有…...

长期使用Token Plan套餐在Taotoken平台带来的月度成本控制体验

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 长期使用Token Plan套餐在Taotoken平台带来的月度成本控制体验 对于个人开发者或小型团队而言,在探索和集成大模型能力…...

AI系统性挑战:从可解释性到思想体系构建的深度剖析

1. 项目概述:从“可解释”到“可理解”的鸿沟最近和几位做AI落地的朋友聊天,大家不约而同地提到了同一个痛点:模型输出看起来头头是道,逻辑清晰,但一旦深究,或者把不同场景下的回答放在一起对比&#xff0c…...

PvZ Toolkit终极指南:5分钟掌握植物大战僵尸PC版最强修改器

PvZ Toolkit终极指南:5分钟掌握植物大战僵尸PC版最强修改器 【免费下载链接】pvztoolkit 植物大战僵尸 PC 版综合修改器 项目地址: https://gitcode.com/gh_mirrors/pv/pvztoolkit 植物大战僵尸PC版玩家们,你是否想过拥有无限阳光、免费种植、自定…...

开发环境准备:Python、Node.js、Docker与Git

从“环境搞了两天”到“半小时开箱即用”,一个老油条的环境配置血泪史前几天团队来了个新同事,应届生,看着简历上写着“熟悉Python、Node.js、Docker、Git”。我心想,挺好,基本功扎实。然后给了他一个新电脑&#xff0…...

Linux内核安全钩子(Hook)深度探秘:以一次文件打开操作为例

Linux内核安全钩子(Hook)深度探秘:以一次文件打开操作为例 当我们在终端输入cat /etc/shadow时,系统背后究竟发生了什么?这个看似简单的操作,实际上触发了一系列精妙的安全检查机制。本文将带您深入Linux内…...

键盘连击问题终极解决方案:免费开源工具KeyboardChatterBlocker完全指南

键盘连击问题终极解决方案:免费开源工具KeyboardChatterBlocker完全指南 【免费下载链接】KeyboardChatterBlocker A handy quick tool for blocking mechanical keyboard chatter. 项目地址: https://gitcode.com/gh_mirrors/ke/KeyboardChatterBlocker 还在…...

初创公司如何用Taotoken统一管理多个AI模型的API密钥

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 初创公司如何用Taotoken统一管理多个AI模型的API密钥 对于初创公司而言,在业务中集成多个大语言模型(如GPT…...

Go语言Beego框架如何用_Go语言Beego框架入门教程【高效】

Beego Controller 靠约定式反射自动注册,需嵌入 beego.Controller、方法名首字母大写且以 HTTP 动词开头、文件置于 controllers/ 目录下;路由参数用 :id 形式绑定到同名 string 参数;模板路径为 views/{小写控制器名}/{小写方法名}.html&…...

3个步骤让AMD显卡也能运行CUDA程序:ZLUDA终极指南

3个步骤让AMD显卡也能运行CUDA程序:ZLUDA终极指南 【免费下载链接】ZLUDA CUDA on non-NVIDIA GPUs 项目地址: https://gitcode.com/GitHub_Trending/zl/ZLUDA 你是否曾经因为手头只有AMD显卡,却想运行那些需要CUDA加速的深度学习框架而感到无奈&…...

JavaScript中字符串与ArrayBuffer缓冲区的转换

...