///|
pub(all) struct RobotGaitClipDirectoryImportRequest {
root : String
source_dir : String
clip_id : @robot_data.RobotGaitClipId
robot_id : @robot_data.RobotId
model_id : @robot_data.RobotModelId
imported_at_ms : Int64
source_label : String
} derive(Debug, Eq, ToJson, FromJson)
///|
pub(all) struct ImportedRobotGaitClipPayload {
source_path : String
relative_path : String
payload_path : String
gait : @robot_data.RobotGaitClipPayloadRef
} derive(Debug, Eq, ToJson, FromJson)
///|
pub(all) struct RobotGaitClipDirectoryImportResult {
root : String
source_dir : String
clip_id : @robot_data.RobotGaitClipId
robot_id : @robot_data.RobotId
model_id : @robot_data.RobotModelId
payload_count : Int
gait_clip : @robot_data.RobotGaitClipManifest
payloads : Array[ImportedRobotGaitClipPayload]
materialization : RobotCatalogMaterialization
} derive(Debug, Eq, ToJson, FromJson)
///|
pub fn robot_gait_clip_directory_import_request(
root : String,
source_dir : String,
clip_id : @robot_data.RobotGaitClipId,
robot_id : @robot_data.RobotId,
model_id : @robot_data.RobotModelId,
imported_at_ms : Int64,
source_label? : String = "Robot gait clip directory import",
) -> RobotGaitClipDirectoryImportRequest {
{
root,
source_dir,
clip_id,
robot_id,
model_id,
imported_at_ms,
source_label,
}
}
///|
fn gait_clip_source_files(
source_dir : String,
) -> Result[Array[(String, String)], @data_store.DataStoreIssue] {
let names = match read_sorted_names(source_dir) {
Ok(value) => value
Err(error) => return Err(error)
}
let files : Array[(String, String)] = []
for name in names {
if !@data_core.data_relative_path_is_safe(name) {
return Err(
import_issue(
"unsafe-robot-gait-clip-path", name, "robot gait clip source contains an unsafe relative path",
),
)
}
let path = join(source_dir, name)
if !is_directory(path) {
files.push((path, name))
}
}
Ok(files)
}
///|
fn gait_clip_content_type(relative_path : String) -> String {
if relative_path.has_suffix(".json") {
"application/json"
} else if relative_path.has_suffix(".csv") {
"text/csv"
} else {
"text/plain"
}
}
///|
fn gait_clip_role(relative_path : String) -> String {
let mut value = relative_path
if value.has_suffix(".json") {
value = value[0:value.length() - 5].to_owned()
} else if value.has_suffix(".csv") {
value = value[0:value.length() - 4].to_owned()
} else if value.has_suffix(".txt") {
value = value[0:value.length() - 4].to_owned()
}
value
}
///|
fn gait_clip_payload_data_ref(
clip_id : @robot_data.RobotGaitClipId,
relative_path : String,
body : String,
) -> @data_core.DataRef {
let payload_path = "payloads/robot_data/gait_clips/\{clip_id}/\{relative_path}"
@data_core.data_ref(
"robot-gait-clip-\{safe_ref_segment(clip_id)}-\{safe_ref_segment(relative_path)}",
"robot-gait-clip",
@data_core.data_uri(payload_path),
content_type=gait_clip_content_type(relative_path),
byte_count=body.length().to_int64(),
checksum=text_sum(body),
)
}
///|
pub fn import_robot_gait_clip_directory(
request : RobotGaitClipDirectoryImportRequest,
) -> Result[RobotGaitClipDirectoryImportResult, @data_store.DataStoreIssue] {
match validate_episode_import_id(request.clip_id, "robot-gait-clip-id") {
Ok(_) => ()
Err(error) => return Err(error)
}
let model_dossier = match
robot_model_catalog_dossier_from_root(request.root, request.model_id) {
Ok(value) => value
Err(error) => return Err(error)
}
let model = match model_ref_from_dossier(model_dossier, request.robot_id) {
Ok(value) => value
Err(error) => return Err(error)
}
let files = match gait_clip_source_files(request.source_dir) {
Ok(value) => value
Err(error) => return Err(error)
}
if files.length() == 0 {
return Err(
import_issue(
"empty-robot-gait-clip-directory",
request.source_dir,
"robot gait clip source directory has no file payloads",
),
)
}
let payloads : Array[ImportedRobotGaitClipPayload] = []
for index in 0..
return Err(
import_issue(
"read-robot-gait-clip-payload", source_path, "failed to read robot gait clip payload as text",
),
)
}
let data_ref = gait_clip_payload_data_ref(
request.clip_id,
relative_path,
body,
)
let payload_path = match stage_text_data_ref(request.root, data_ref, body) {
Ok(value) => value
Err(error) => return Err(error)
}
let payload = match payload_from_data_ref(data_ref) {
Ok(value) => value
Err(error) => return Err(error)
}
let gait = @robot_data.robot_gait_clip_payload_ref(
gait_clip_role(relative_path),
1,
0.0,
payload,
)
payloads.push({ source_path, relative_path, payload_path, gait })
}
let gait_clip = @robot_data.robot_gait_clip_manifest(
request.clip_id,
request.robot_id,
"source-robot-gait-clip-\{request.clip_id}",
request.source_label,
request.source_dir,
@data_core.DataStatus::Verified,
request.imported_at_ms,
[model],
payloads.map(fn(payload) { payload.gait }),
"Robot gait clip for \{request.robot_id}",
)
match write_gait_clips(request.root, [gait_clip]) {
Ok(_) => ()
Err(error) => return Err(error)
}
match @data_store.rebuild_catalog(request.root, request.imported_at_ms) {
Ok(_) => ()
Err(error) => return Err(error)
}
let validation = match
@data_validate.validate_and_write_root(request.root, request.imported_at_ms) {
Ok(value) => value
Err(error) => return Err(error)
}
let catalog = match @data_store.read_catalog(request.root) {
Ok(value) => value
Err(error) => return Err(error)
}
Ok({
root: request.root,
source_dir: request.source_dir,
clip_id: request.clip_id,
robot_id: request.robot_id,
model_id: request.model_id,
payload_count: payloads.length(),
gait_clip,
payloads,
materialization: {
root: request.root,
catalog_path: validation.catalog_path,
validation_report_path: validation.report_path,
source_count: 1,
dataset_count: 1,
version_count: 1,
lineage_count: 1,
telemetry_stream_count: 0,
gait_clip_count: 1,
gait_annotation_count: 0,
gait_alignment_count: 0,
task_label_count: 0,
rollout_count: 0,
quality_report_count: 0,
catalog_entry_count: catalog.entries.length(),
validation_status: validation.status,
blocker_count: validation.blocker_count,
warning_count: validation.warning_count,
},
})
}