systemprompt_models/artifacts/audio/
mod.rs1use crate::artifacts::metadata::ExecutionMetadata;
2use crate::artifacts::traits::Artifact;
3use crate::artifacts::types::ArtifactType;
4use crate::execution::context::RequestContext;
5use schemars::JsonSchema;
6use serde::{Deserialize, Serialize};
7use serde_json::{Value as JsonValue, json};
8use systemprompt_identifiers::SkillId;
9
10fn default_artifact_type() -> String {
11 "audio".to_string()
12}
13
14const fn default_true() -> bool {
15 true
16}
17
18#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
19pub struct AudioArtifact {
20 #[serde(rename = "x-artifact-type")]
21 #[serde(default = "default_artifact_type")]
22 pub artifact_type: String,
23 pub src: String,
24 #[serde(skip_serializing_if = "Option::is_none")]
25 pub mime_type: Option<String>,
26 #[serde(skip_serializing_if = "Option::is_none")]
27 pub title: Option<String>,
28 #[serde(skip_serializing_if = "Option::is_none")]
29 pub artist: Option<String>,
30 #[serde(skip_serializing_if = "Option::is_none")]
31 pub artwork: Option<String>,
32 #[serde(default = "default_true")]
33 pub controls: bool,
34 #[serde(default)]
35 pub autoplay: bool,
36 #[serde(default)]
37 #[serde(rename = "loop")]
38 pub loop_playback: bool,
39 #[serde(skip)]
40 #[schemars(skip)]
41 metadata: ExecutionMetadata,
42}
43
44impl AudioArtifact {
45 pub const ARTIFACT_TYPE_STR: &'static str = "audio";
46
47 pub fn new(src: impl Into<String>, ctx: &RequestContext) -> Self {
48 Self {
49 artifact_type: "audio".to_string(),
50 src: src.into(),
51 mime_type: None,
52 title: None,
53 artist: None,
54 artwork: None,
55 controls: true,
56 autoplay: false,
57 loop_playback: false,
58 metadata: ExecutionMetadata::with_request(ctx),
59 }
60 }
61
62 pub fn with_mime_type(mut self, mime_type: impl Into<String>) -> Self {
63 self.mime_type = Some(mime_type.into());
64 self
65 }
66
67 pub fn with_title(mut self, title: impl Into<String>) -> Self {
68 self.title = Some(title.into());
69 self
70 }
71
72 pub fn with_artist(mut self, artist: impl Into<String>) -> Self {
73 self.artist = Some(artist.into());
74 self
75 }
76
77 pub fn with_artwork(mut self, artwork: impl Into<String>) -> Self {
78 self.artwork = Some(artwork.into());
79 self
80 }
81
82 pub const fn with_autoplay(mut self) -> Self {
83 self.autoplay = true;
84 self
85 }
86
87 pub const fn with_loop(mut self) -> Self {
88 self.loop_playback = true;
89 self
90 }
91
92 pub const fn without_controls(mut self) -> Self {
93 self.controls = false;
94 self
95 }
96
97 pub fn with_execution_id(mut self, id: impl Into<String>) -> Self {
98 self.metadata.execution_id = Some(id.into());
99 self
100 }
101
102 pub fn with_skill(
103 mut self,
104 skill_id: impl Into<SkillId>,
105 skill_name: impl Into<String>,
106 ) -> Self {
107 self.metadata.skill_id = Some(skill_id.into());
108 self.metadata.skill_name = Some(skill_name.into());
109 self
110 }
111}
112
113impl Artifact for AudioArtifact {
114 fn artifact_type(&self) -> ArtifactType {
115 ArtifactType::Audio
116 }
117
118 fn to_schema(&self) -> JsonValue {
119 json!({
120 "type": "object",
121 "properties": {
122 "src": {
123 "type": "string",
124 "description": "Audio source URL or base64 data URI"
125 },
126 "mime_type": {
127 "type": "string",
128 "description": "MIME type (e.g., audio/mpeg)"
129 },
130 "title": {
131 "type": "string",
132 "description": "Track title"
133 },
134 "artist": {
135 "type": "string",
136 "description": "Artist name"
137 },
138 "artwork": {
139 "type": "string",
140 "description": "Album artwork URL"
141 },
142 "controls": {
143 "type": "boolean",
144 "description": "Show playback controls",
145 "default": true
146 },
147 "autoplay": {
148 "type": "boolean",
149 "description": "Auto-play on load",
150 "default": false
151 },
152 "loop": {
153 "type": "boolean",
154 "description": "Loop playback",
155 "default": false
156 }
157 },
158 "required": ["src"],
159 "x-artifact-type": "audio"
160 })
161 }
162}