use super::*; pub(crate) fn map_visual_novel_agent_session_procedure_result( result: VisualNovelAgentSessionProcedureResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::procedure_failed(result.error_message)); } let session = result .session .ok_or_else(|| SpacetimeClientError::missing_snapshot("visual novel agent session 快照"))?; Ok(map_visual_novel_agent_session_snapshot(session)) } pub(crate) fn map_visual_novel_work_procedure_result( result: VisualNovelWorkProcedureResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::procedure_failed(result.error_message)); } let work = result .work .ok_or_else(|| SpacetimeClientError::missing_snapshot("visual novel work 快照"))?; Ok(map_visual_novel_work_snapshot(work)) } pub(crate) fn map_visual_novel_works_procedure_result( result: VisualNovelWorksProcedureResult, ) -> Result, SpacetimeClientError> { if !result.ok { return Err(SpacetimeClientError::procedure_failed(result.error_message)); } Ok(result .items .into_iter() .map(map_visual_novel_work_snapshot) .collect()) } pub(crate) fn map_visual_novel_run_procedure_result( result: VisualNovelRunProcedureResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::procedure_failed(result.error_message)); } let run = result .run .ok_or_else(|| SpacetimeClientError::missing_snapshot("visual novel run 快照"))?; Ok(map_visual_novel_run_snapshot(run)) } pub(crate) fn map_visual_novel_history_procedure_result( result: VisualNovelHistoryProcedureResult, ) -> Result, SpacetimeClientError> { if !result.ok { return Err(SpacetimeClientError::procedure_failed(result.error_message)); } Ok(result .items .into_iter() .map(map_visual_novel_history_entry) .collect()) } pub(crate) fn map_visual_novel_runtime_event_procedure_result( result: VisualNovelRuntimeEventProcedureResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::procedure_failed(result.error_message)); } let event = result .event .ok_or_else(|| SpacetimeClientError::missing_snapshot("visual novel runtime event 快照"))?; Ok(map_visual_novel_runtime_event(event)) } fn map_visual_novel_agent_session_snapshot( snapshot: VisualNovelAgentSessionSnapshot, ) -> VisualNovelAgentSessionRecord { VisualNovelAgentSessionRecord { session_id: snapshot.session_id, owner_user_id: snapshot.owner_user_id, source_mode: snapshot.source_mode, status: snapshot.status, seed_text: snapshot.seed_text, source_asset_ids: snapshot.source_asset_ids, current_turn: snapshot.current_turn, progress_percent: snapshot.progress_percent, messages: snapshot .messages .into_iter() .map(map_visual_novel_agent_message) .collect(), draft: snapshot.draft.map(visual_novel_json_to_value), pending_action: snapshot.pending_action.map(visual_novel_json_to_value), last_assistant_reply: snapshot.last_assistant_reply, published_profile_id: snapshot.published_profile_id, created_at: format_timestamp_micros(snapshot.created_at_micros), updated_at: format_timestamp_micros(snapshot.updated_at_micros), } } fn map_visual_novel_agent_message( snapshot: VisualNovelAgentMessageSnapshot, ) -> VisualNovelAgentMessageRecord { VisualNovelAgentMessageRecord { message_id: snapshot.message_id, session_id: snapshot.session_id, role: snapshot.role, kind: snapshot.kind, text: snapshot.text, created_at: format_timestamp_micros(snapshot.created_at_micros), } } fn map_visual_novel_work_snapshot( snapshot: VisualNovelWorkSnapshot, ) -> VisualNovelWorkProfileRecord { VisualNovelWorkProfileRecord { work_id: snapshot.work_id, profile_id: snapshot.profile_id, owner_user_id: snapshot.owner_user_id, source_session_id: snapshot.source_session_id, author_display_name: snapshot.author_display_name, work_title: snapshot.work_title, work_description: snapshot.work_description, tags: snapshot.tags, cover_image_src: snapshot.cover_image_src, source_asset_ids: snapshot.source_asset_ids, draft: visual_novel_json_to_value(snapshot.draft), publication_status: snapshot.publication_status, publish_ready: snapshot.publish_ready, play_count: snapshot.play_count, created_at: format_timestamp_micros(snapshot.created_at_micros), updated_at: format_timestamp_micros(snapshot.updated_at_micros), published_at: snapshot.published_at_micros.map(format_timestamp_micros), } } pub(crate) fn map_visual_novel_gallery_view_row( row: VisualNovelGalleryViewRow, ) -> VisualNovelWorkProfileRecord { VisualNovelWorkProfileRecord { work_id: row.work_id, profile_id: row.profile_id, owner_user_id: row.owner_user_id, source_session_id: row.source_session_id, author_display_name: row.author_display_name, work_title: row.work_title, work_description: row.work_description, tags: row.tags, cover_image_src: row.cover_image_src, source_asset_ids: row.source_asset_ids, // 中文注释:公开列表 view 不暴露完整 draft,详情页仍通过 detail procedure 读取。 draft: serde_json::Value::Null, publication_status: row.publication_status, publish_ready: row.publish_ready, play_count: row.play_count, created_at: format_timestamp_micros(row.created_at_micros), updated_at: format_timestamp_micros(row.updated_at_micros), published_at: row.published_at_micros.map(format_timestamp_micros), } } fn map_visual_novel_run_snapshot(snapshot: VisualNovelRunSnapshot) -> VisualNovelRunRecord { VisualNovelRunRecord { run_id: snapshot.run_id, owner_user_id: snapshot.owner_user_id, profile_id: snapshot.profile_id, mode: snapshot.mode, status: snapshot.status, current_scene_id: snapshot.current_scene_id, current_phase_id: snapshot.current_phase_id, visible_character_ids: snapshot.visible_character_ids, flags: visual_novel_json_to_value(snapshot.flags), metrics: visual_novel_json_to_value(snapshot.metrics), history: snapshot .history .into_iter() .map(map_visual_novel_history_entry) .collect(), available_choices: visual_novel_json_to_value(snapshot.available_choices), text_mode_enabled: snapshot.text_mode_enabled, created_at: format_timestamp_micros(snapshot.created_at_micros), updated_at: format_timestamp_micros(snapshot.updated_at_micros), } } fn map_visual_novel_history_entry( snapshot: VisualNovelRuntimeHistoryEntrySnapshot, ) -> VisualNovelHistoryEntryRecord { VisualNovelHistoryEntryRecord { entry_id: snapshot.entry_id, run_id: snapshot.run_id, owner_user_id: snapshot.owner_user_id, profile_id: snapshot.profile_id, turn_index: snapshot.turn_index, source: snapshot.source, action_text: snapshot.action_text, steps: visual_novel_json_to_value(snapshot.steps), snapshot_before_hash: snapshot.snapshot_before_hash, snapshot_after_hash: snapshot.snapshot_after_hash, created_at: format_timestamp_micros(snapshot.created_at_micros), } } fn map_visual_novel_runtime_event( snapshot: VisualNovelRuntimeEventSnapshot, ) -> VisualNovelRuntimeEventRecord { VisualNovelRuntimeEventRecord { event_id: snapshot.event_id, run_id: snapshot.run_id, owner_user_id: snapshot.owner_user_id, profile_id: snapshot.profile_id, event_kind: snapshot.event_kind, client_event_id: snapshot.client_event_id, history_entry_id: snapshot.history_entry_id, payload: visual_novel_json_to_value(snapshot.payload), occurred_at: format_timestamp_micros(snapshot.occurred_at_micros), } } fn visual_novel_json_to_value(value: VisualNovelJsonValue) -> serde_json::Value { match value { VisualNovelJsonValue::Null => serde_json::Value::Null, VisualNovelJsonValue::Bool(value) => serde_json::Value::Bool(value), VisualNovelJsonValue::Number(value) => serde_json::Number::from_f64(value) .map(serde_json::Value::Number) .unwrap_or(serde_json::Value::Null), VisualNovelJsonValue::String(value) => serde_json::Value::String(value), VisualNovelJsonValue::Array(items) => { serde_json::Value::Array(items.into_iter().map(visual_novel_json_to_value).collect()) } VisualNovelJsonValue::Object(fields) => { let object = fields .into_iter() .map(|field| (field.key, visual_novel_json_to_value(field.value))) .collect(); serde_json::Value::Object(object) } } }