3737 _require_v3 ,
3838 _schema_from_info ,
3939 _validate_v3_required_features ,
40+ _video_feature_names ,
4041)
4142from pypaimon .multimodal .lerobot .source import (
4243 _close_quietly ,
5253)
5354
5455
56+ _VIDEO_LAYOUT_ERROR = (
57+ "LeRobot video import requires a bucket-unaware target table so each "
58+ "Episode is written by one writer."
59+ )
60+
61+
5562def load_from_lerobot (
5663 connection ,
5764 table_name : str ,
@@ -94,14 +101,20 @@ def load_from_lerobot(
94101 _positive_integer (local_info .get ("fps" ), "fps" )
95102 _validated_counts (local_info , resolved_source .path )
96103 _validate_v3_required_features (local_info )
104+ video_fields = _video_feature_names (local_info )
97105 LeRobotDataset = _import_lerobot_dataset ()
98106 dataset = _open_resolved_dataset (
99- LeRobotDataset , resolved_source , local_info )
107+ LeRobotDataset ,
108+ resolved_source ,
109+ local_info ,
110+ download_videos = bool (video_fields ),
111+ )
100112 try :
101113 info = dict (dataset .meta .info )
102114 _require_v3 (info , resolved_source .path )
103115 _validated_counts (info , resolved_source .path )
104116 _validate_v3_required_features (info )
117+ video_fields = _video_feature_names (info )
105118
106119 lerobot_schema = _schema_from_info (info )
107120 metadata = _load_dataset_metadata (
@@ -117,6 +130,7 @@ def load_from_lerobot(
117130 options ,
118131 metadata ,
119132 tag_name ,
133+ video_fields ,
120134 )
121135 finally :
122136 close = getattr (dataset , "close" , None )
@@ -134,14 +148,21 @@ def _import_dataset(
134148 batch_size ,
135149 options ,
136150 metadata ,
137- tag_name ):
151+ tag_name ,
152+ video_fields ):
138153 table = _create_target_table (
139- connection , table_name , source_schema , options , metadata )
154+ connection ,
155+ table_name ,
156+ source_schema ,
157+ options ,
158+ metadata ,
159+ video_fields ,
160+ )
140161 tables = _prepare_metadata_tables (
141162 connection , table .raw_table , metadata )
142163 episodes_snapshot_id = _append_arrow_tables (
143164 tables ["episodes" ],
144- _validated_episode_tables (metadata ),
165+ _validated_episode_tables (metadata , video_fields ),
145166 )
146167 frames_snapshot_id = None
147168 if int (info ["total_frames" ]) > 0 :
@@ -153,6 +174,7 @@ def _import_dataset(
153174 source_schema ,
154175 batch_size ,
155176 metadata ,
177+ video_fields ,
156178 )
157179 _commit_metadata (
158180 connection ,
@@ -195,8 +217,25 @@ def _required_count(info, name, source):
195217
196218
197219def _create_target_table (
198- connection , table_name , source_schema , options , metadata ):
220+ connection , table_name , source_schema , options , metadata ,
221+ video_fields = ()):
199222 create_options = dict (options or {})
223+ configured = create_options .get ("video-frame-field" )
224+ if configured is not None :
225+ requested = {
226+ name .strip () for name in str (configured ).split ("," )
227+ if name .strip ()
228+ }
229+ if requested != set (video_fields ):
230+ raise ValueError (
231+ "LeRobot video features %s do not match "
232+ "'video-frame-field'=%r."
233+ % (list (video_fields ), configured )
234+ )
235+ if video_fields :
236+ if str (create_options .get ("bucket" , "-1" )).strip () != "-1" :
237+ raise ValueError (_VIDEO_LAYOUT_ERROR )
238+ create_options ["video-frame-field" ] = "," .join (video_fields )
200239 managed_options = _managed_table_options (
201240 connection ._identifier (table_name ), metadata )
202241 reserved_options = set (_COMPANION_OPTION_KEYS .values ()).intersection (
0 commit comments