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

Flutter - 原生交互 - 相机Camera - 01

环境

Flutter 3.29

macOS Sequoia 15.4.1

Xcode 16.3

集成

Flutter提供了camera插件来拍照和录视频,它提供了一系列可用的相机,并使用特定的相机展示相机预览、拍照、录视频。

添加依赖

  • camera: 提供使用设备相机模块的工具
  • path_provider: 寻找存储图片的正确路径
  • path: 创建适配任何平台的路径
flutter pub add camera path_provider path

执行完成后iOS工程的GeneratedPluginRegistrant.m文件会自动生成对应的集成代码

#if __has_include(<camera_avfoundation/CameraPlugin.h>)
#import <camera_avfoundation/CameraPlugin.h>
#else
@import camera_avfoundation;
#endif#if __has_include(<path_provider_foundation/PathProviderPlugin.h>)
#import <path_provider_foundation/PathProviderPlugin.h>
#else
@import path_provider_foundation;
#endif
...[CameraPlugin registerWithRegistrar:[registry registrarForPlugin:@"CameraPlugin"]];[PathProviderPlugin registerWithRegistrar:[registry registrarForPlugin:@"PathProviderPlugin"]];

分析

[registry registrarForPlugin:@“CameraPlugin”]

AppDelegate.swfitapplication(_:didFinishLaunchingWithOptions:)中将FlutterAppDelegate的子类AppDelegate对象作为参数传入并调用该方法

GeneratedPluginRegistrant.register(with: self)

源码: FlutterAppDelegate.mm

- (NSObject<FlutterPluginRegistrar>*)registrarForPlugin:(NSString*)pluginKey {/// <1> 获取应用的flutterRootViewController对象FlutterViewController* flutterRootViewController = [self rootFlutterViewController];if (flutterRootViewController) {/// <4> 返回一个FlutterEngine对象return [[flutterRootViewController pluginRegistry] registrarForPlugin:pluginKey];}return nil;
}// Returns the key window's rootViewController, if it's a FlutterViewController.
// Otherwise, returns nil.
- (FlutterViewController*)rootFlutterViewController {///- (FlutterViewController*(^ rootFlutterViewControllerGetter) (void))/// <2> 检查是否有外部注入,有则使用自定义的回调获取FlutterViewController对象if (_rootFlutterViewControllerGetter != nil) {return _rootFlutterViewControllerGetter();}/// <3> 没有则检查window的rootViewController属性,如果是FlutterViewController则返回,否则返回nilUIViewController* rootViewController = _window.rootViewController;if ([rootViewController isKindOfClass:[FlutterViewController class]]) {return (FlutterViewController*)rootViewController;}return nil;
}
[flutterRootViewController pluginRegistry]

第<4>步中的方法调用在 FlutterViewController.mm

///  pluginRegistry方法获得一个遵守FlutterPluginRegistry协议的对象
- (id<FlutterPluginRegistry>)pluginRegistry {return self.engine;
}
.../// engine是FlutterEngine对象
- (void)sharedSetupWithProject:(nullable FlutterDartProject*)projectinitialRoute:(nullable NSString*)initialRoute {
...
engine = [[FlutterEngine alloc] initWithName:@"io.flutter"project:projectallowHeadlessExecution:self.engineAllowHeadlessExecutionrestorationEnabled:self.restorationIdentifier != nil];
...
_engine = engine;
...              - (instancetype)initWithEngine:(FlutterEngine*)enginenibName:(nullable NSString*)nibNamebundle:(nullable NSBundle*)nibBundle {
...
_engine = engine;          

FlutterPluginRegistry协议的继承结构

17485097331657.png

FlutterEngine对象调用registrarForPlugin:方法

源码: FlutterEngine.mm

/// 文件: FlutterEngine.mm
...
/*** All registrars returned from registrarForPlugin:*/
@property(nonatomic, readonly)NSMutableDictionary<NSString*, FlutterEngineRegistrar*>* pluginRegistrars;
...- (id<FlutterPluginRegistrar>)registrarForPlugin:(NSString*)pluginName {/// <5> 检查可变字典中是否已存在插件名的keyid<FlutterPluginRegistrar> registrar = self.pluginRegistrars[pluginName];if (!registrar) {/// <6> 首次注册,生成FlutterEngineRegistrar对象并持有pluginName和弱引用FlutterEngine 对象/// 为什么是弱引用?/// 文件:FlutterViewController.m 强引入了FlutterEngine对象/// @property(nonatomic, readonly) FlutterEngine* engine;FlutterEngineRegistrar* registrarImpl =[[FlutterEngineRegistrar alloc] initWithPlugin:pluginName flutterEngine:self];/// 接收传入的pluginName  + self即FlutterEngine对象/// @interface FlutterEngineRegistrar : NSObject <FlutterPluginRegistrar>/// @property(nonatomic, weak) FlutterEngine* flutterEngine;/// @implementation FlutterEngineRegistrar {///   NSString* _pluginKey;/// }/// 因为FlutterViewController.m 已经强引入了FlutterEngine对象,所以这里的flutterEngine弱引用即可/// @property(nonatomic, readonly) FlutterEngine* engine;/// /// <7> 添加到FlutterEngine对象的可变字典中self.pluginRegistrars[pluginName] = registrarImpl;registrar = registrarImpl;}/// <8> 返回FlutterEngineRegistrar注册对象,其中保存FlutterEngine相关的信息,负责与Flutter的iOS插件交互return registrar;
}
[CameraPlugin registerWithRegistrar:registrar]
/// camera插件的类定义
public final class CameraPlugin: NSObject, FlutterPlugin {
@protocol FlutterPlugin <NSObject, FlutterApplicationLifeCycleDelegate>
@required
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar;

Flutter中的iOS插件遵守FlutterPlugin协议且必须实现+registerWithRegistrar:方法

以camera插件为例,CameraPlugin.swift是对外的Swift的接口包装

public static func register(with registrar: FlutterPluginRegistrar) {let instance = CameraPlugin(/// 文件: FlutterEngine.mm/// <9> 从FlutterEngineRegistrar对象中获取纹理的对象/// - (NSObject<FlutterTextureRegistry>*)textures {///   return _flutterEngine.textureRegistry;/// }registry: registrar.textures(),/// Returns a `FlutterBinaryMessenger` for creating Dart/iOS communication/// channels to be used by the plugin./// <10> 从FlutterEngineRegistrar返回Dart与iOS原生消息的对象messenger: registrar.messenger(),globalAPI: FCPCameraGlobalEventApi(binaryMessenger: registrar.messenger()),deviceDiscoverer: FLTDefaultCameraDeviceDiscoverer(),permissionManager: FLTCameraPermissionManager(permissionService: FLTDefaultPermissionService()),deviceFactory: { name in// TODO(RobertOdrowaz) Implement better error handling and remove non-null assertionFLTDefaultCaptureDevice(device: AVCaptureDevice(uniqueID: name)!)},captureSessionFactory: { FLTDefaultCaptureSession(captureSession: AVCaptureSession()) },captureDeviceInputFactory: FLTDefaultCaptureDeviceInputFactory(),captureSessionQueue: DispatchQueue(label: "io.flutter.camera.captureSessionQueue"))/// <11>设置Dart相机API的消息通道SetUpFCPCameraApi(registrar.messenger(), instance)}
registrar.messenger()

从前面可知registrar是一个FlutterEngineRegistrar

/// 文件: FlutterEngine.mm
@implementation FlutterEngineRegistrar {
...
- (NSObject<FlutterBinaryMessenger>*)messenger {/// 返回的是FlutterEngineRegistrar对象绑定的FlutterEngine中的binaryMessenger属性return _flutterEngine.binaryMessenger;
}
...@implementation FlutterEngine {
...
FlutterBinaryMessengerRelay* _binaryMessenger;
.../// FlutterEngine对象中的binaryMessenger属性是FlutterBinaryMessengerRelay对象
/// 且parent属性关联的是FlutterEngine对象
_binaryMessenger = [[FlutterBinaryMessengerRelay alloc] initWithParent:self];
SetUpFCPCameraApi(registrar.messenger(), instance)

代码执行进入文件 message.g.m

void SetUpFCPCameraApiWithSuffix(id<FlutterBinaryMessenger> binaryMessenger,NSObject<FCPCameraApi> *api, NSString *messageChannelSuffix) {messageChannelSuffix = messageChannelSuffix.length > 0? [NSString stringWithFormat:@".%@", messageChannelSuffix]: @"";/// Returns the list of available cameras./// 建立设备的相机可用列表API{FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc]initWithName:[NSString stringWithFormat:@"%@%@",@"dev.flutter.pigeon.camera_avfoundation."@"CameraApi.getAvailableCameras",messageChannelSuffix]binaryMessenger:binaryMessengercodec:FCPGetMessagesCodec()];if (api) {NSCAssert([api respondsToSelector:@selector(availableCamerasWithCompletion:)],@"FCPCameraApi api (%@) doesn't respond to @selector(availableCamerasWithCompletion:)",api);[channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {[api availableCamerasWithCompletion:^(NSArray<FCPPlatformCameraDescription *> *_Nullable output,FlutterError *_Nullable error) {callback(wrapResult(output, error));}];}];} else {[channel setMessageHandler:nil];}}.../// 绑定一系列相机操作的API

FlutterBasicMessageChannel类在FlutterChannel.m中,先初始化一个FlutterBasicMessageChannel对象,实现上只是接收外界参数

- (instancetype)initWithName:(NSString*)namebinaryMessenger:(NSObject<FlutterBinaryMessenger>*)messengercodec:(NSObject<FlutterMessageCodec>*)codectaskQueue:(NSObject<FlutterTaskQueue>*)taskQueue {self = [super init];NSAssert(self, @"Super init cannot be nil");_name = [name copy];_messenger = messenger;_codec = codec;_taskQueue = taskQueue;return self;
}
[channel setMessageHandler:^(id _Nullable message, FlutterReply callback) ...];

接着判断入参的api是否不为空,api是生成的CameraPlugin对象,所以不为空,然后消息的回调

- (void)setMessageHandler:(FlutterMessageHandler)handler {/// 未自定义回调时,这里应该是多次调用则清空上一次的,然后再重新创建if (!handler) {if (_connection > 0) {[_messenger cleanUpConnection:_connection];_connection = 0;} else {[_messenger setMessageHandlerOnChannel:_name binaryMessageHandler:nil];}return;}// Grab reference to avoid retain on self.// `self` might be released before the block, so the block needs to retain the codec to// make sure it is not released with `self`/// 从前面的代码可以知道这个self即channel对象只有一个局部对象在持有,所以超过作用域会被回收,所以这里接收到codecNSObject<FlutterMessageCodec>* codec = _codec;FlutterBinaryMessageHandler messageHandler = ^(NSData* message, FlutterBinaryReply callback) {handler([codec decode:message], ^(id reply) {callback([codec encode:reply]);});};_connection = SetMessageHandler(_messenger, _name, messageHandler, _taskQueue);
}
static FlutterBinaryMessengerConnection SetMessageHandler(NSObject<FlutterBinaryMessenger>* messenger,NSString* name,FlutterBinaryMessageHandler handler,NSObject<FlutterTaskQueue>* taskQueue) {/// 是否要在指定的任务队列上执行/// name在这里是 dev.flutter.pigeon.camera_avfoundation.CameraApi.getAvailableCameras.../// handler是设置的回调/// 发送给FlutterBinaryMessengerRelay对象if (taskQueue) {NSCAssert([messenger respondsToSelector:@selector(setMessageHandlerOnChannel:binaryMessageHandler:taskQueue:)],@"");return [messenger setMessageHandlerOnChannel:namebinaryMessageHandler:handlertaskQueue:taskQueue];} else {return [messenger setMessageHandlerOnChannel:name binaryMessageHandler:handler];}
}

进入到FlutterBinaryMessengerRelay对象的setMessageHandlerOnChannel:binaryMessageHandler:taskQueue:

文件: FlutterBinaryMessengerRelay.mm

- (FlutterBinaryMessengerConnection)setMessageHandlerOnChannel:(NSString*)channelbinaryMessageHandler:(FlutterBinaryMessageHandler)handlertaskQueue:(NSObject<FlutterTaskQueue>*)taskQueue {/// parent就是engine对象,因此又回到engine上setMessageHandlerOnChannel:binaryMessageHandler:                                         taskQueue:if (self.parent) {return [self.parent setMessageHandlerOnChannel:channelbinaryMessageHandler:handlertaskQueue:taskQueue];} else {FML_LOG(WARNING) << "Communicating on a dead channel.";return -1;}
}

文件: FlutterEngine.mm

- (FlutterBinaryMessengerConnection)setMessageHandlerOnChannel:(NSString*)channelbinaryMessageHandler:(FlutterBinaryMessageHandler)handlertaskQueue:(NSObject<FlutterTaskQueue>* _Nullable)taskQueue {NSParameterAssert(channel);if (_shell && _shell->IsSetup()) {/// 获取原生平台的线程,并传入channel名,回调,任务队列self.platformView->GetPlatformMessageHandlerIos()->SetMessageHandler(channel.UTF8String,handler, taskQueue);/// std::unique_ptr<flutter::ConnectionCollection> _connections;/// ///  文件:connection_collection.mm///  ConnectionCollection::Connection   ConnectionCollection::AquireConnection(const std::string& name) {///   Connection nextConnection = ++counter_;///   connections_[name] = nextConnection;///   return nextConnection;/// }/// FlutterEngine对象中的连接集合属性,AcquireConnection方法让connections字典中key为channel的计数加1return _connections->AquireConnection(channel.UTF8String);} else {NSAssert(!handler, @"Setting a message handler before the FlutterEngine has been run.");// Setting a handler to nil for a channel that has not yet been set up is a no-op.return flutter::ConnectionCollection::MakeErrorConnection(-1);}
}

文件: platform_view_ios.h

/// 调用GetPlatformMessageHandlerIos即返回platform_message_handler_属性
class PlatformViewIOS final : public PlatformView {
...
std::shared_ptr<PlatformMessageHandlerIos> GetPlatformMessageHandlerIos() const {return platform_message_handler_;}
...

文件: platform_view_ios.mm


PlatformViewIOS::PlatformViewIOS(PlatformView::Delegate& delegate,const std::shared_ptr<IOSContext>& context,__weak FlutterPlatformViewsController* platform_views_controller,const flutter::TaskRunners& task_runners): PlatformView(delegate, task_runners),ios_context_(context),platform_views_controller_(platform_views_controller),accessibility_bridge_([this](bool enabled) { PlatformView::SetSemanticsEnabled(enabled); }),/// 从初始化列表中可以看出platform_message_handler_的值通过GetPlatformTaskRunner获取UI的主线程platform_message_handler_(new PlatformMessageHandlerIos(task_runners.GetPlatformTaskRunner())) {}

到这里Flutter的插件的原生代码部分已经将channel,回调,执行队列(可选)给原生平台的主线程。

获取可用相机列表

/// Dart端调用获取可用摄像头列表
final cameras = await availableCameras();

文件: camera_controller.dart

/// Completes with a list of available cameras.
///
/// May throw a [CameraException].
Future<List<CameraDescription>> availableCameras() async {return CameraPlatform.instance.availableCameras();
}

调用CameraPlatform对象的availableCameras方法

文件: camera_platform.dart

abstract class CameraPlatform extends PlatformInterface {/// Constructs a CameraPlatform.CameraPlatform() : super(token: _token);.../// Completes with a list of available cameras.////// This method returns an empty list when no cameras are available.Future<List<CameraDescription>> availableCameras() {throw UnimplementedError('availableCameras() is not implemented.');}

CameraPlatform是个抽象类,要找具体的实现。找到camera插件的pubspec.yaml

flutter:plugin:implements: cameraplatforms:ios:pluginClass: CameraPlugindartPluginClass: AVFoundationCamera

dartPluginClass: Optional. The Dart class that serves as the entry point for a Flutter plugin. This can be used with the Android, iOS, Linux macOS, and Windows platforms.

因此camera插件dart的入口应该是AVFoundationCamera这个类,它继承了上面的CameraPlatform抽象类

文件: avfoundation_camera.dart

class AVFoundationCamera extends CameraPlatform {/// Creates a new AVFoundation-based [CameraPlatform] implementation instance.AVFoundationCamera({ CameraApi? api}): _hostApi = api ?? CameraApi();...Future<List<CameraDescription>> availableCameras() async {try {return (await _hostApi.getAvailableCameras()).map(cameraDescriptionFromPlatform).toList();} on PlatformException catch (e) {throw CameraException(e.code, e.message);}}

从上面代码可知实际调用的是_hostApigetAvailableCameras方法

Future<List<PlatformCameraDescription>> getAvailableCameras() async {/// 前面建立channel时已经传入了,这样原生执行完相关方法后能通过channel调用对应的回调final String pigeonVar_channelName ='dev.flutter.pigeon.camera_avfoundation.CameraApi.getAvailableCameras$pigeonVar_messageChannelSuffix';/// A named channel for communicating with platform plugins using asynchronous message passing./// 创建异步消息final BasicMessageChannel<Object?> pigeonVar_channel =BasicMessageChannel<Object?>(pigeonVar_channelName,pigeonChannelCodec,binaryMessenger: pigeonVar_binaryMessenger,);/// 阻塞**发送消息**final List<Object?>? pigeonVar_replyList =await pigeonVar_channel.send(null) as List<Object?>?;/// 消息为空抛异常if (pigeonVar_replyList == null) {throw _createConnectionError(pigeonVar_channelName);} else if (pigeonVar_replyList.length > 1) {throw PlatformException(code: pigeonVar_replyList[0]! as String,message: pigeonVar_replyList[1] as String?,details: pigeonVar_replyList[2],);} else if (pigeonVar_replyList[0] == null) {throw PlatformException(code: 'null-error',message: 'Host platform returned null value for non-null return value.',);} else {/// 得到可用列表转换为Flutter上的摄像头描述的对象return (pigeonVar_replyList[0] as List<Object?>?)!.cast<PlatformCameraDescription>();}}
await pigeonVar_channel.send(null) as List<Object?>?;
/// Sends the specified [message] to the platform plugins on this channel.////// Returns a [Future] which completes to the received response, which may/// be null.Future<T?> send(T message) async {/// 调用binaryMessenger对象编码发送消息 && 得到返回后再解码return codec.decodeMessage(await binaryMessenger.send(name, codec.encodeMessage(message)));}

Flutter Dart端发送指定channel消息 && 调用原来添加的回调走到Flutter原生插件部分这里,比如当前走到获取可用摄像头的回调

...
[api availableCamerasWithCompletion:^(NSArray<FCPPlatformCameraDescription *> *_Nullable output,FlutterError *_Nullable error) {callback(wrapResult(output, error));}];

即调用api(CameraPlugin)的availableCamerasWithCompletion:方法

extension CameraPlugin: FCPCameraApi {public func availableCameras(completion: @escaping ([FCPPlatformCameraDescription]?, FlutterError?) -> Void) {captureSessionQueue.async { [weak self] inguard let strongSelf = self else { return }var discoveryDevices: [AVCaptureDevice.DeviceType] = [.builtInWideAngleCamera,.builtInTelephotoCamera,].../// 前置,后置等摄像头,然后统一添加到reply这个数组对象for device in devices {var lensFacing: FCPPlatformCameraLensDirectionswitch device.position {case .back:lensFacing = .backcase .front:lensFacing = .frontcase .unspecified:...}reply.append(cameraDescription)}/// 最后执行callback(wrapResult(output, error));/// 获取成功后,Flutter的Dart部分可以获取到可用的摄像头列表completion(reply, nil)
}

总结

17486664768352.jpg

  1. 原生插件将方法的channel(约定的字符串),回调设置给Flutter原生平台代码(C++ && OC)
  2. Flutter的Dart层发送消息并传递channel,Flutter根据channel找到设置的回调(Dart -> C++ && OC),然后执行原生插件提供的方法(C++ && OC)
  3. 获取执行结果并返回给Flutter的原生平台代码(C++ && OC),再发送给Dart代码(C++ && OC -> Dart)

参考

  1. camera
  2. 使用 Camera 插件实现拍照功能
  3. do-not-use-buildcontexts-across-async-gaps
  4. Flutter pubspec options
  5. 一张图理解Flutter中Dart与原生环境通信

相关文章:

Flutter - 原生交互 - 相机Camera - 01

环境 Flutter 3.29 macOS Sequoia 15.4.1 Xcode 16.3 集成 Flutter提供了camera插件来拍照和录视频&#xff0c;它提供了一系列可用的相机&#xff0c;并使用特定的相机展示相机预览、拍照、录视频。 添加依赖 camera: 提供使用设备相机模块的工具path_provider: 寻找存储图…...

湖北理元理律师事务所:个人债务管理的温度与精度

湖北理元理律师事务所&#xff1a;个人债务管理的温度与精度 面对信用卡、网贷、医疗债等多重债务压力&#xff0c;普通人常陷入“拆东墙补西墙”的恶性循环。湖北理元理律师事务所通过计划集团公司服务平台&#xff0c;推出“有温度的债务优化计划”&#xff0c;其人性化设计…...

Compose原理 - 整体架构与主流程

一、整体架构 在官方文档中&#xff08;Jetpack Compose 架构层 | Android Developers&#xff09;&#xff0c;对Compose的分层有所阐述&#xff1a; 其中 Runtime&#xff1a;提供Compose的基础运行能力&#xff0c;包括State、Side-effects、CompositionLocal、Compositio…...

从0开始学vue:实现一个简单页面

Vue.js 是一个渐进式JavaScript框架&#xff0c;用于构建用户界面。下面我将带你从零开始学习Vue.js并创建一个简单的可运行页面。 1. 准备工作 首先&#xff0c;你需要了解几种学习Vue.js的方式&#xff1a; 方式一&#xff1a;使用CDN引入&#xff08;最简单的方式&#x…...

在机器视觉测量和机器视觉定位中,棋盘格标定如何影响精度

棋盘格标定是机器视觉(尤其是基于相机的系统)中进行相机内参(焦距、主点、畸变系数)和外参(相机相对于世界坐标系的位置和姿态)标定的经典且广泛应用的方法。它的质量直接、显著且多方面地影响最终的视觉测量和定位精度。 以下是棋盘格标定如何影响精度的详细分析: 标定…...

CppCon 2014 学习: C++ Test-driven Development

“Elephant in the Room”这个比喻常用来形容那些大家都知道但没人愿意讨论的重大问题。 这段内容讲的是软件质量管理的经典做法和潜在的问题&#xff1a; 经典做法&#xff1a;开发完成后才进行人工测试&#xff08;manual testing after creation&#xff09;。隐喻“Cape o…...

RAGflow详解及实战指南

目录 前言 一、RAGflow核心技术解析 1. 技术原理&#xff1a;检索与生成的协同进化 2. 架构设计&#xff1a;分层模块化与高扩展性 3. 核心优势&#xff1a;精准、高效、安全 二、RAGflow实战应用场景 1. 企业知识库搭建 2. 智能客服系统 3. 投资分析报告生成 4. 制造…...

JWT 不对外,Session ID 对外:构建安全可控的微服务认证架构

以下是一篇围绕“JWT不对外&#xff0c;Session ID对外”的专业架构设计文章&#xff0c;适用于技术团队评审、技术博客发布或系统设计文档引用&#xff1a; JWT 不对外&#xff0c;Session ID 对外&#xff1a;构建安全可控的微服务认证架构 在构建分布式微服务系统时&#x…...

[Godot] 如何导出安卓 APK 并在手机上调试

在之前的文章中&#xff0c;我们已经详细介绍了如何配置 Godot 的安卓应用开发环境&#xff0c;包括安装 Android SDK、配置 Java 环境、设置 Godot 的 Android 导出模板等。本篇文章将进一步讲解如何将 Godot 项目导出为安卓 APK 文件&#xff0c;并实现在手机上进行调试运行。…...

React 路由管理与动态路由配置实战

React 路由管理与动态路由配置实战 前言 在现代单页应用(SPA)开发中&#xff0c;路由管理已经成为前端架构的核心部分。随着React应用规模的扩大&#xff0c;静态路由配置往往难以满足复杂业务场景的需求&#xff0c;尤其是当应用需要处理权限控制、动态菜单和按需加载等高级…...

ZYNQ sdk lwip配置UDP组播收发数据

🚀 一、颠覆认知:组播 vs 单播 vs 广播 通信方式目标设备网络负载典型应用场景单播1对1O(n)SSH远程登录广播1对全网O(1)ARP地址解析组播1对N组O(1)视频会议/物联网群控创新价值:在智能工厂中,ZYNQ通过组播同时控制100台AGV小车,比传统单播方案降低92%网络流量! 🔧 二、…...

11.21 LangGraph多轮对话系统实战:三步构建高效信息整理引擎,效率提升300%!

关键词:LangGraph 工作流设计, 信息整理助理, 多轮对话系统, 状态管理, 条件分支控制 信息整理助理工作流设计 信息整理助理需要完成 多源数据收集 → 信息分类 → 深度分析 → 结构化输出 的完整流程。通过 LangGraph 的图结构工作流,可实现复杂逻辑的模块化编排: #mermai…...

高光谱成像相机:基于高光谱成像技术的玉米种子纯度检测研究

种子纯度是衡量种子质量的核心指标之一&#xff0c;直接影响农作物产量与品质。传统检测方法&#xff08;如形态学观察、生化分析&#xff09;存在耗时长、破坏样本、依赖人工等缺陷。近年来&#xff0c;高光谱成像技术因其融合光谱与图像信息的优势&#xff0c;成为无损检测领…...

Linux《文件系统》

在之前的系统IO当中已经了解了“内存”级别的文件操作&#xff0c;了解了文件描述符、重定向、缓冲区等概念&#xff0c;在了解了这些的知识之后还封装出了我们自己的libc库。接下来在本篇当中将会将视角从内存转向磁盘&#xff0c;研究文件在内存当中是如何进行存储的&#xf…...

NLP学习路线图(十六):N-gram模型

一、为何需要语言模型&#xff1f;概率视角下的语言本质 自然语言处理的核心挑战在于让机器“理解”人类语言。这种理解的一个关键方面是处理语言的歧义性、创造性和结构性。语言模型&#xff08;Language Model, LM&#xff09;为此提供了一种强大的数学框架&#xff1a;它赋…...

【Python办公】将Excel表格转json(字典)数据-可自定义key和value

目录 专栏导读背景介绍库的安装数据源准备代码1:key1列,value所有列代码1:key多列,value所有列代码3:key自选,value自选总结专栏导读 🌸 欢迎来到Python办公自动化专栏—Python处理办公问题,解放您的双手 🏳️‍🌈 博客主页:请点击——> 一晌小贪欢的博客主页求关…...

Java内存区域与内存溢出异常分析与解决

在 Java 开发中&#xff0c;内存管理和内存溢出异常&#xff08; OutOfMemoryError&#xff09;是一个至关重要的主题。Java 虚拟机&#xff08;JVM&#xff09;的内存区域分为多个部分&#xff0c;每个区域都有其特定的用途和限制。当这些区域的内存耗尽时&#xff0c;就会触发…...

Python训练第四十天

DAY 40 训练和测试的规范写法 知识点回顾&#xff1a; 彩色和灰度图片测试和训练的规范写法&#xff1a;封装在函数中展平操作&#xff1a;除第一个维度batchsize外全部展平dropout操作&#xff1a;训练阶段随机丢弃神经元&#xff0c;测试阶段eval模式关闭dropout 昨天我们介绍…...

硬件实时时钟(RTC)

硬件实时时钟&#xff08;RTC&#xff09;详解 硬件实时时钟&#xff08;Real-Time Clock&#xff0c;RTC&#xff09;是计算机主板上的一个独立计时芯片&#xff0c;用于在系统关机后持续记录时间。它不依赖操作系统&#xff0c;由纽扣电池&#xff08;如CR2032&#xff09;供…...

InternVL2.5-多模态大模型评估专业图片

具备图像理解功能的大模型InternVL2.5&#xff0c;能有效解析大部分图片。 对于专业图片如医学细胞切片&#xff0c;从专业角度解析&#xff0c;能推动模型应用到更广泛的领域。 InternVL2.5解析示例 prompt(胸部癌变细胞图片,来自PanNuke) 请评估这个组织的风险 InternVL2.…...

医疗数理范式化:从范式迁移到认知革命的深度解析

引言 在当代医疗领域,数理思维已经从辅助工具逐渐发展成为核心决策支持系统的关键组成部分。随着数字技术的迅猛发展,医疗行业正经历着前所未有的变革,而数理思维作为这一变革的核心驱动力,正在深刻重塑医疗实践的方方面面。数理思维在医疗领域的应用,本质上是将抽象的数…...

图神经网络在信息检索重排序中的应用:原理、架构与Python代码解析

现代信息检索系统和搜索引擎普遍采用两阶段检索架构&#xff0c;在人工智能应用中也被称为检索增强生成&#xff08;Retrieval-Augmented Generation, RAG&#xff09;。在初始检索阶段&#xff0c;系统采用高效的检索方法&#xff0c;包括词汇检索算法&#xff08;如BM25&…...

leetcode hot100 二叉树(一)

1.二叉树的中序遍历 中序遍历&#xff08;中根遍历&#xff09;&#xff1a;左-根-右顺序&#xff0c;递归实现。注意设置递归终止条件。 class Solution { public:void search(TreeNode* root,vector<int>& ans){if(!root) return ;search(root->left,ans);ans.…...

【技术支持】安卓11开机启动设置

<!-- 开机自启动权限 --><uses-permission android:name"android.permission.RECEIVE_BOOT_COMPLETED" /><!-- 自启动权限 --><uses-permission android:name"android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" /><!-…...

现代数据湖架构全景解析:存储、表格式、计算引擎与元数据服务的协同生态

本文全面剖析现代数据湖架构的核心组件,深入探讨对象存储(OSS/S3)、表格式(Iceberg/Hudi/Delta Lake)、计算引擎(Spark/Flink/Presto)及元数据服务(HMS/Amoro)的协作关系,并提供企业级选型指南。 一、数据湖架构演进与核心价值 数据湖架构演进历程 现代数据湖核心价…...

全志F1c200开发笔记——移植Debian文件系统

1.搭建环境 sudo apt install qemu-user-static -y sudo apt install debootstrap -y mkdir rootfs 2.拉取文件系统 这边我参照墨云大神的文档&#xff0c;但是华为镜像已经没有armel了&#xff0c;我找到了官方仓库&#xff0c;还是有的&#xff0c;拉取速度比较慢 sudo d…...

dis css port brief 命令详细解释

华为交换机命令 display css port brief 详细解释 display css port brief 是华为交换机中用于 快速查看堆叠&#xff08;CSS&#xff0c;Cluster Switch System&#xff09;端口状态及关键参数 的命令&#xff0c;适用于日常运维、堆叠链路健康检查及故障定位。以下是该命令的…...

支持功能安全ASIL-B的矩阵管理芯片IS32LT3365,助力ADB大灯系统轻松实现功能安全等级

随着自动驾驶技术的快速发展&#xff0c;汽车前灯智能化也越来越高。自适应远光灯 (ADB) 作为一种智能照明系统&#xff0c;在提升驾驶安全性和舒适性方面发挥着重要作用。ADB 系统通过摄像头和传感器获取前方道路信息&#xff0c;例如来车的位置、距离和速度&#xff0c;并根据…...

BFS入门刷题

目录 P1746 离开中山路 P1443 马的遍历 P1747 好奇怪的游戏 P2385 [USACO07FEB] Bronze Lilypad Pond B P1746 离开中山路 #include <iostream> #include <queue> #include <cstring> using namespace std; int n; int startx, starty; int endx, endy; …...

UE5 编辑器工具蓝图

文章目录 简述使用方法样例自动生成Actor&#xff0c;并根据模型的包围盒设置Actor的大小批量修改场景中Actor的属性&#xff0c;设置Actor的名字&#xff0c;设置Actor到指定的文件夹 简述 使用编辑器工具好处是可以在非运行时可以对资源或场景做一些操作&#xff0c;例如自动…...