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

Coze源码分析-资源库-编辑插件-后端源码-IDL/API/应用服务层

前言

本文将深入分析Coze Studio项目中用户编辑插件功能的后端实现。当用户登录Coze平台后,点击"资源库" → 接着在表格中点击要编辑的插件行,触发的是一个完整的插件资源编辑流程。插件作为AI应用开发的核心组件,其编辑操作涉及权限验证、编辑锁定、数据更新和多个后端服务层的协同工作。通过源码解读,我们将深入理解插件编辑功能在整个Coze Studio后端架构中的设计思路和技术实现细节。

项目架构概览

插件编辑功能架构设计

Coze Studio的插件编辑功能采用了经典的分层架构模式,专门针对插件资源的安全编辑进行了优化设计。整个架构围绕插件的权限验证、编辑锁定、数据更新和版本管理展开:

┌─────────────────────────────────────────────────────────────┐
│                    IDL接口定义层                             │
│  ┌─────────────┐  ┌─────────────┐    ┌─────────────┐        │
│  │ base.thrift │  │plugin_      │    │ api.thrift  │        │
│  │             │  │develop.     │    │             │        │
│  │             │  │thrift       │    │             │        │
│  └─────────────┘  └─────────────┘    └─────────────┘        │
└─────────────────────────────────────────────────────────────┘↓
┌─────────────────────────────────────────────────────────────┐
│                    API网关层                                 │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐          │
│  │   Handler   │  │   Router    │  │ Middleware  │          │
│  │   处理器     │  │   路由      │  │   中间件     │          │
│  └─────────────┘  └─────────────┘  └─────────────┘          │
└─────────────────────────────────────────────────────────────┘↓
┌─────────────────────────────────────────────────────────────┐
│                   应用服务层                                 │
│  ┌─────────────────────────────────────────────────────┐    │
│  │           PluginApplicationService                  │    │
│  │     CheckAndLockPluginEdit UpdatePluginMeta         │    │
│  └─────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────┘↓
┌─────────────────────────────────────────────────────────────┐
│                   领域服务层                                 │
│  ┌─────────────────────────────────────────────────────┐    │
│  │              pluginServiceImpl                      │    │
│  │                ┌─────────────────┐                  │    │
│  │                │UpdatePlugin     │                  │    │
│  │                │Meta             │                  │    │
│  │                └─────────────────┘                  │    │
│  └─────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────┘↓
┌─────────────────────────────────────────────────────────────┐
│                   数据访问层                                 │
│  ┌─────────────────────────────────────────────────────┐    │
│  │              PluginRepository                       │    │
│  │  ┌──── ─────── ──── ──┐  ┌─────────────────────────┐│    │
│  │  │PluginDAO           │  │plugin.gen.go            ││    │
│  │  │UpdatePlugin        │  │tool.gen.go              ││    │
│  │  │ToolDAO             │  │GORM Generated Code      ││    │
│  │  └──── ─────── ─── ───┘  └─────────────────────────┘│    │
│  └─────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────┘↓
┌─────────────────────────────────────────────────────────────┐
│                   基础设施层                                 │
│              ┌─ ─ ─── ─ ── ── ─ ─ ─┐                        │
│              │       gorm.DB       │                        │
│              │ es.Client redisImpl │                        │
│              └── ─ ── ── ─ ── ── ─ ┘                        │
└─────────────────────────────────────────────────────────────┘↓
┌─────────────────────────────────────────────────────────────┐
│                   存储服务层                                 │
│  ┌─────────────────────────────────────────────────────┐    │
│  │       MySQL数据库       Redis数据库                  │    │
│  │            ElasticSearch数据库                      │    │
│  └─────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────┘

插件编辑流程核心组件

API路由映射:

  • POST /api/plugin_api/check_and_lock_plugin_edit - 检查并锁定插件以进行编辑
  • POST /api/plugin_api/update_plugin_meta - 更新插件元数据
  • POST /api/plugin_api/unlock_plugin_edit - 解锁插件编辑

核心数据模型:

// 文件位置:backend/api/model/crossdomain/plugin/plugin.go
type PluginInfo struct {ID           int64PluginType   api.PluginTypeSpaceID      int64DeveloperID  int64APPID        *int64RefProductID *int64 // for product pluginIconURI      *stringServerURL    *stringVersion      *stringVersionDesc  *stringCreatedAt    int64UpdatedAt    int64Manifest     *PluginManifestOpenapiDoc   *Openapi3T
}// 文件位置:backend/api/model/crossdomain/plugin/tool.go
type ToolInfo struct {ID              int64PluginID        int64Name            stringMethod          HTTPMethodSubURL          stringActivatedStatus ActivatedStatusDebugStatus     DebugStatusCreatedAt       int64UpdatedAt       int64RequestSchema   *openapi3.SchemaResponseSchema  openapi3.Responses
}

1. IDL接口定义层

IDL基础类型定义(base.thrift)

文件位置:idl/base.thrift
核心代码:

namespace py base
namespace go base
namespace java com.bytedance.thrift.basestruct TrafficEnv {1: bool   Open = false,2: string Env  = ""   ,
}struct Base {1:          string             LogID      = "",2:          string             Caller     = "",3:          string             Addr       = "",4:          string             Client     = "",5: optional TrafficEnv         TrafficEnv     ,6: optional map<string,string> Extra          ,
}struct BaseResp {1:          string             StatusMessage = "",2:          i32                StatusCode    = 0 ,3: optional map<string,string> Extra             ,
}

文件作用:
定义了Coze Studio项目中所有接口的基础数据结构,作为其他IDL文件的依赖基础。

插件开发接口定义(plugin_develop.thrift)

文件位置:idl/plugin/plugin_develop.thrift

当Coze用户登录平台后点击"资源库" → 接着在表格中点击要编辑的插件行时,前端会调用插件编辑相关的接口。该文件定义了插件编辑的核心数据结构和接口。

检查并锁定插件编辑接口
struct CheckAndLockPluginEditRequest {1  : required i64    plugin_id (api.body = "plugin_id", api.js_conv = "str"),255: optional base.Base Base                                                   ,
}struct CheckAndLockPluginEditResponse {1  : required i32                                              code   ,2  : required string                                           msg     ,3  :          plugin_develop_common.CheckAndLockPluginEditData data     ,255: optional base.BaseResp                                    BaseResp                   ,
}
更新插件元数据接口
struct UpdatePluginMetaRequest {1  : required i64                                                                                     plugin_id (api.js_conv = "str")     ,2  : optional string                                                                                     name           ,3  : optional string                                                                                     desc           ,4  : optional string                                                                                     url            , // plugin service url5  : optional plugin_develop_common.PluginIcon                                                           icon           ,6  : optional plugin_develop_common.AuthorizationType                                                    auth_type      ,7  : optional plugin_develop_common.AuthorizationServiceLocation                                         location       , // When the sub-authorization type is api/token, the token parameter position8  : optional string                                                                                     key            , // When the sub-authorization type is api/token, the token parameter key9  : optional string                                                                                     service_token  , // When the sub-authorization type is api/token, the token parameter value10 : optional string                                                                                     oauth_info     , // When the sub-authorization type is oauth, for oauth information, see GetOAuthSchema return value11 : optional map<plugin_develop_common.ParameterLocation,list<plugin_develop_common.commonParamSchema>> common_params  , // JSON serialization12 : optional plugin_develop_common.CreationMethod                                                       creation_method, // ignore13 : optional i32                                                                                        edit_version   , // ignore14 : optional plugin_develop_common.PluginType                                                           plugin_type    ,15 : optional i32                                                                                        sub_auth_type  , // Level 2 authorization type16 : optional string                                                                                     auth_payload   , // ignore17 : optional bool                                                                                       fixed_export_ip, // ignore255: optional base.Base                                                                                  Base           ,
}struct UpdatePluginMetaResponse {1  :          i64           code        ,2  :          string        msg         ,3  :          i32           edit_version,255: optional base.BaseResp BaseResp    ,
}
解锁插件编辑接口
struct UnlockPluginEditRequest {1  : required i64    plugin_id (api.body = "plugin_id", api.js_conv = "str"),255: optional base.Base Base                                                   ,
}struct UnlockPluginEditResponse {1  : required i32           code       ,2  : required string        msg        ,3  : required bool          released ,255: optional base.BaseResp BaseResp                       ,
}

插件开发服务接口(plugin_develop.thrift)

文件位置:idl/plugin/plugin_develop.thrift

该文件定义了PluginDevelopService服务的核心接口,包括插件管理的服务接口定义。

PluginDevelopService服务定义
service PluginDevelopService {CheckAndLockPluginEditResponse CheckAndLockPluginEdit(1: CheckAndLockPluginEditRequest request)(api.post='/api/plugin_api/check_and_lock_plugin_edit', api.category="plugin", api.gen_path="plugin", )UnlockPluginEditResponse UnlockPluginEdit(1: UnlockPluginEditRequest request)(api.post='/api/plugin_api/unlock_plugin_edit', api.category="plugin", api.gen_path="plugin")UpdatePluginMetaResponse UpdatePluginMeta(1: UpdatePluginMetaRequest request) (api.post = '/api/plugin_api/update_plugin_meta', api.category = "plugin")// 其他服务接口...
}

插件接口路由映射说明:

  • CheckAndLockPluginEdit: POST /api/plugin_api/check_and_lock_plugin_edit - 检查并锁定插件以进行编辑
  • UpdatePluginMeta: POST /api/plugin_api/update_plugin_meta - 更新插件元数据
  • UnlockPluginEdit: POST /api/plugin_api/unlock_plugin_edit - 解锁插件编辑

接口功能说明:

  • 数据结构设计: CheckAndLockPluginEditRequest包含插件ID字段;UpdatePluginMetaRequest包含插件ID、名称、描述、URL等可更新字段;UnlockPluginEditRequest包含插件ID字段
  • 编辑操作: 支持通过UI界面编辑插件,包括基本信息更新、授权配置修改等

IDL主API服务聚合文件(api.thrift)

文件位置:idl/api.thrift

该文件是整个Coze项目的API服务聚合入口点,负责将所有业务模块的IDL服务定义统一聚合,为代码生成工具提供完整的服务接口定义。

核心代码:


include "./plugin/plugin_develop.thrift"namespace go coze// 插件开发核心服务聚合
service PluginDevelopService extends plugin_develop.PluginDevelopService {}
// 其他业务服务聚合

插件接口聚合说明:
通过 service PluginDevelopService extends plugin_develop.PluginDevelopService {} 聚合定义,api.thrift将plugin_develop.thrift中定义的所有插件相关接口统一暴露.

2. API网关层

接口定义-plugin_develop.go文件详细分析

文件位置:backend\api\model\plugin_develop\plugin_develop.go
核心代码:

type PluginDevelopService interface {CheckAndLockPluginEdit(ctx context.Context, request *CheckAndLockPluginEditRequest) (r *CheckAndLockPluginEditResponse, err error)UnlockPluginEdit(ctx context.Context, request *UnlockPluginEditRequest) (r *UnlockPluginEditResponse, err error)UpdatePluginMeta(ctx context.Context, request *UpdatePluginMetaRequest) (r *UpdatePluginMetaResponse, err error)}
插件相关接口模型定义

当Coze用户登录平台后点击"资源库" → 接着在表格中点击要编辑的插件行时,前端会调用插件编辑相关接口来编辑插件资源。

CheckAndLockPluginEditRequest 检查并锁定插件编辑请求结构体

type CheckAndLockPluginEditRequest struct {// 插件IDPluginID int64 `thrift:"plugin_id,1,required" form:"plugin_id,required" json:"plugin_id,required" query:"plugin_id,required"`Base     *base.Base `thrift:"Base,255" form:"Base" json:"Base" query:"Base"`
}

UpdatePluginMetaRequest 更新插件元数据请求结构体

type UpdatePluginMetaRequest struct {// 插件IDPluginID int64 `thrift:"plugin_id,1,required" form:"plugin_id,required" json:"plugin_id,required" query:"plugin_id,required"`// 插件名称Name         *string `thrift:"name,2" form:"name" json:"name" query:"name"`// 插件描述Desc         *string `thrift:"desc,3" form:"desc" json:"desc" query:"desc"`// 插件服务地址前缀Url          *string `thrift:"url,4" form:"url" json:"url" query:"url"`// 插件图标Icon         *plugin_develop_common.PluginIcon `thrift:"icon,5" form:"icon" json:"icon" query:"icon"`// 插件授权类型AuthType     *plugin_develop_common.AuthorizationType `thrift:"auth_type,6" form:"auth_type" json:"auth_type" query:"auth_type"`// 空间IDBase         *base.Base `thrift:"Base,255" form:"Base" json:"Base" query:"Base"`// 其他字段...
}

UnlockPluginEditRequest 解锁插件编辑请求结构体

type UnlockPluginEditRequest struct {// 插件IDPluginID int64 `thrift:"plugin_id,1,required" form:"plugin_id,required" json:"plugin_id,required" query:"plugin_id,required"`Base     *base.Base `thrift:"Base,255" form:"Base" json:"Base" query:"Base"`
}
接口功能说明

业务功能

  • 插件编辑锁定:确保在同一时间只有一个用户可以编辑特定插件,防止冲突
  • 插件元数据更新:根据用户输入更新插件的基本信息、授权配置等
  • 编辑解锁:当用户完成编辑后,释放插件的编辑锁定,允许其他用户编辑
  • 权限验证:确保只有有权限的用户才能编辑插件
  • 数据存储:将更新后的插件信息持久化存储
  • 操作审计:记录编辑操作的日志和审计信息

技术特性

  • 类型安全:使用强类型定义确保插件数据的一致性
  • 多格式支持:支持thrift、form、json、query等多种序列化格式
  • 参数验证:通过required标记确保必要参数的完整性
  • 统一响应:遵循统一的响应格式规范

文件作用
由thriftgo自动生成的Go代码文件,基于plugin_develop.thrift IDL定义生成对应的Go结构体和接口,提供类型安全的插件API模型。该文件实现了完整的Thrift RPC通信机制,包括客户端调用、服务端处理、序列化/反序列化等功能,确保了插件服务间的可靠通信。

插件接口处理器实现

文件位置:backend/api/handler/coze/plugin_develop_service.go

该文件包含了用户登录后点击"资源库" → 接着在表格中点击要编辑的插件行功能的核心API接口处理器,主要负责处理插件资源的编辑功能。

检查并锁定插件编辑处理器
// CheckAndLockPluginEdit .
// @router /api/plugin_api/check_and_lock_plugin_edit [POST]
func CheckAndLockPluginEdit(ctx context.Context, c *app.RequestContext) {var err errorvar req plugin_develop.CheckAndLockPluginEditRequesterr = c.BindAndValidate(&req)if err != nil {invalidParamRequestResponse(c, err.Error())return}if req.PluginID <= 0 {invalidParamRequestResponse(c, "pluginID is invalid")return}resp, err := plugin.PluginApplicationSVC.CheckAndLockPluginEdit(ctx, &req)if err != nil {internalServerErrorResponse(ctx, c, err)return}c.JSON(consts.StatusOK, resp)
}
更新插件元数据处理器
// UpdatePluginMeta .
// @router /api/plugin_api/update_plugin_meta [POST]
func UpdatePluginMeta(ctx context.Context, c *app.RequestContext) {var err errorvar req plugin_develop.UpdatePluginMetaRequesterr = c.BindAndValidate(&req)if err != nil {invalidParamRequestResponse(c, err.Error())return}if req.PluginID <= 0 {invalidParamRequestResponse(c, "pluginID is invalid")return}if req.Name != nil && *req.Name == "" {invalidParamRequestResponse(c, "plugin name is invalid")return}if req.Desc != nil && *req.Desc == "" {invalidParamRequestResponse(c, "plugin desc is invalid")return}if req.URL != nil && (*req.URL == "" || len(*req.URL) > 512) {invalidParamRequestResponse(c, "plugin server url is invalid")return}resp, err := plugin.PluginApplicationSVC.UpdatePluginMeta(ctx, &req)if err != nil {internalServerErrorResponse(ctx, c, err)return}c.JSON(consts.StatusOK, resp)
}
解锁插件编辑处理器
// UnlockPluginEdit .
// @router /api/plugin_api/unlock_plugin_edit [POST]
func UnlockPluginEdit(ctx context.Context, c *app.RequestContext) {var err errorvar req plugin_develop.UnlockPluginEditRequesterr = c.BindAndValidate(&req)if err != nil {invalidParamRequestResponse(c, err.Error())return}resp, err := plugin.PluginApplicationSVC.UnlockPluginEdit(ctx, &req)if err != nil {internalServerErrorResponse(ctx, c, err)return}c.JSON(consts.StatusOK, resp)
}

实现功能

  1. 参数验证:验证插件ID、名称、描述、URL等参数的有效性
  2. 业务调用:调用PluginApplicationSVC应用服务层的相应方法处理插件编辑业务逻辑
  3. 错误处理:统一的错误处理机制,包括参数错误和内部服务错误
  4. 响应返回:返回标准化的操作响应结果

参数校验逻辑

  • 插件ID验证:确保插件ID大于0,防止无效的编辑操作
  • 插件名称验证:确保更新的插件名称不为空
  • 插件描述验证:确保更新的插件描述不为空
  • URL长度验证:确保插件服务URL长度不超过512字符

路由注册实现-api.go文件详细分析

文件位置:backend/api/router/coze/api.go

该文件是Coze Studio后端的核心路由注册文件,由hertz generator自动生成,负责将所有HTTP API接口路由与对应的处理函数进行绑定和注册。对于插件编辑功能,构建了专门的路由结构:

/api/plugin_api/check_and_lock_plugin_edit [POST]
├── rootMw() # 根级中间件
├── _apiMw() # API组中间件
├── _plugin_apiMw() # 插件API组中间件
├── _checkandlockplugineditMw() # 检查并锁定插件编辑接口专用中间件
└── coze.CheckAndLockPluginEdit # 检查并锁定插件编辑处理函数/api/plugin_api/update_plugin_meta [POST]
├── rootMw() # 根级中间件
├── _apiMw() # API组中间件
├── _plugin_apiMw() # 插件API组中间件
├── _updatepluginmetaMw() # 更新插件元数据接口专用中间件
└── coze.UpdatePluginMeta # 更新插件元数据处理函数/api/plugin_api/unlock_plugin_edit [POST]
├── rootMw() # 根级中间件
├── _apiMw() # API组中间件
├── _plugin_apiMw() # 插件API组中间件
├── _unlockplugineditMw() # 解锁插件编辑接口专用中间件
└── coze.UnlockPluginEdit # 解锁插件编辑处理函数

核心代码:

{_plugin_api := _api.Group("/plugin_api", _plugin_apiMw()...)_plugin_api.POST("/check_and_lock_plugin_edit", append(_checkandlockplugineditMw(), coze.CheckAndLockPluginEdit)...)_plugin_api.POST("/update_plugin_meta", append(_updatepluginmetaMw(), coze.UpdatePluginMeta)...)_plugin_api.POST("/unlock_plugin_edit", append(_unlockplugineditMw(), coze.UnlockPluginEdit)...)// 其他插件相关路由...
}

3. 应用服务层

PluginApplicationService 应用服务层概述

PluginApplicationService是插件编辑功能的核心应用服务层组件,负责协调各个领域服务和数据访问层,处理插件编辑的业务逻辑。该服务实现了PluginDevelopService接口,为API网关层提供具体的业务处理能力。

检查并锁定插件编辑实现

检查并锁定插件编辑是用户开始编辑插件前的关键步骤,确保在同一时间只有一个用户可以编辑特定插件,防止数据冲突。

func (p *PluginApplicationService) CheckAndLockPluginEdit(ctx context.Context, req *pluginAPI.CheckAndLockPluginEditRequest) (resp *pluginAPI.CheckAndLockPluginEditResponse, err error) {// 初始化响应结构体并设置锁定状态为已锁定resp = &pluginAPI.CheckAndLockPluginEditResponse{Code: 0,Msg:  "",Data: &plugin_develop_common.CheckAndLockPluginEditData{Seized: true,},}return resp, nil
}

更新插件元数据实现

更新插件元数据是插件编辑的核心操作,负责根据用户提交的信息更新插件的基本属性。

func (p *PluginApplicationService) UpdatePluginMeta(ctx context.Context, req *pluginAPI.UpdatePluginMetaRequest) (resp *pluginAPI.UpdatePluginMetaResponse, err error) {// 初始化响应结构体resp = &pluginAPI.UpdatePluginMetaResponse{}// 验证用户权限和授权信息authInfo, err := p.getUpdateAuthInfo(ctx, req)if err != nil {// 处理权限错误return nil, err}// 构建更新请求updateReq := &domain.UpdateDraftPluginRequest{PluginID:      req.PluginID,Name:          req.Name,Desc:          req.Desc,ServerURL:     req.URL,Icon:          req.Icon,AuthType:      req.AuthType,AuthLocation:  req.Location,AuthKey:       req.Key,AuthValue:     req.ServiceToken,OAuthInfo:     req.OAuthInfo,CommonParams:  req.CommonParams,PluginType:    req.PluginType,SubAuthType:   req.SubAuthType,FixedExportIP: req.FixedExportIP,SpaceID:       authInfo.SpaceID,DeveloperID:   authInfo.UserID,}// 调用领域服务更新插件err = p.domainSVC.UpdateDraftPlugin(ctx, updateReq)if err != nil {// 处理更新错误return nil, err}// 发布资源变更事件p.publishResourceEvent(ctx, req.PluginID, authInfo)// 设置响应信息resp.Code = 0resp.Msg = ""resp.EditVersion = authInfo.EditVersionreturn resp, nil
}

解锁插件编辑实现

解锁插件编辑是用户完成编辑后释放编辑锁的操作,允许其他用户对插件进行编辑。

func (p *PluginApplicationService) UnlockPluginEdit(ctx context.Context, req *pluginAPI.UnlockPluginEditRequest) (resp *pluginAPI.UnlockPluginEditResponse, err error) {// 初始化响应结构体并设置释放状态为已释放resp = &pluginAPI.UnlockPluginEditResponse{Code:     0,Msg:      "",Released: true,}return resp, nil
}

应用服务层工作流程

插件编辑功能的完整工作流程如下:

  1. 编辑准备阶段

    • 用户点击要编辑的插件行
    • 前端调用CheckAndLockPluginEdit接口
    • 应用服务层验证权限并获取编辑锁
    • 返回插件当前信息给前端进行展示
  2. 编辑进行阶段

    • 用户在前端界面修改插件信息
    • 完成修改后点击保存
    • 前端调用UpdatePluginMeta接口
    • 应用服务层验证权限、检查锁定状态
    • 调用领域服务更新插件数据
    • 返回更新结果
  3. 编辑完成阶段

    • 用户完成所有编辑操作
    • 前端调用UnlockPluginEdit接口
    • 应用服务层释放编辑锁
    • 插件可以被其他用户编辑

核心业务逻辑与协作

应用服务层在插件编辑过程中主要负责以下核心业务逻辑:

  1. 权限验证:确保只有有权限的用户才能编辑特定插件
  2. 并发控制:通过编辑锁定机制防止并发编辑冲突
  3. 数据验证:验证用户提交的数据符合业务规则和约束
  4. 事务管理:确保插件数据更新的原子性和一致性
  5. 版本管理:维护插件的编辑版本号,用于冲突检测
  6. 领域协调:协调调用各个领域服务完成完整的编辑流程

应用服务层作为API网关层和领域服务层之间的桥梁,将复杂的业务流程分解为可管理的步骤,确保插件编辑功能的正确性和可靠性。

http://www.dtcms.com/a/423391.html

相关文章:

  • JuiceSSH+cpolar:手机如何轻松远程连接内网虚拟机?
  • 模式组合应用-代理模式
  • 招聘网站的SEO怎么做建站免费软件
  • 内嵌式模组在物联网设备中如何体现?
  • 【Vue实现跳转页面】功能 - 总结
  • 网站刷流量对网站有影响吗猪八戒网做网站如何付款
  • Linux网络编程05:IO多路转接(万字图文解析)
  • 在 Kubernetes 集群中手动部署开发的应用程序
  • 不联网设备如何精确记时的
  • 网站首页添加代码寄生虫seo教程
  • 黄冈网站推广策略黄浦网站建设
  • 在JavaScript / HTML中,浏览器提示 “Refused to execute inline event handler” 错误
  • 怎样做一个公司网站个人网站做商城
  • 模拟面试 - 第6轮
  • PostgreSQL WAL 日志发展史 - pg8
  • 第4篇 vs2019+QT调用SDK连接海康相机显示图片
  • 高通平台WiFi学习--WLAN Offload技术
  • 微信小程序app.js中每30秒调用一次wx.getLocation
  • 遥感云平台-GEE分块下载与拼接
  • 深圳市建设监理协会网站wordpress后台接口数据
  • UNIX下C语言编程与实践10-UNIX 动态库隐式调用:编译链接配置与路径问题排查
  • 网站虚拟主持人制作建设一个网站需要条件
  • 网站建设中文百北京住房和城乡建设局门户网站
  • uni-app 模板语法修复说明
  • OpenLayers地图交互 -- 章节十八:拖拽旋转和缩放交互详解
  • 6DOF-Euler Angles
  • 【代码随想录day 29】 力扣 860.柠檬水找零
  • 医疗智能体的技术演进与路径分析:从多模态大模型到高阶综合智能体
  • 西安制作网站的电话深圳seo网站推广方案
  • 开放、协同,2025 云栖大会“操作系统开源与 AI 进化分论坛”精彩回顾