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