1616use OCP \IL10N ;
1717use OCP \TaskProcessing \Exception \ProcessingException ;
1818use OCP \TaskProcessing \Exception \UserFacingProcessingException ;
19+ use OCP \TaskProcessing \IManager as ITaskProcessingManager ;
1920use Psr \Log \LoggerInterface ;
2021use RuntimeException ;
2122
@@ -73,6 +74,7 @@ public function __construct(
7374 private OpenAiSettingsService $ openAiSettingsService ,
7475 private IRootFolder $ rootFolder ,
7576 private LoggerInterface $ logger ,
77+ private ITaskProcessingManager $ taskProcessingManager ,
7678 ) {
7779 }
7880
@@ -81,13 +83,29 @@ public function __construct(
8183 *
8284 * @param int $fileId The ID of the file to build content from.
8385 * @param string $userId The user ID.
86+ * @param ?int $taskId The ID of the task
8487 * @return list<array<string, mixed>> Content parts suitable for OpenAI chat message content.
8588 * @throws ProcessingException
8689 * @throws UserFacingProcessingException
8790 */
88- public function buildFileContentFromId (int $ fileId , string $ userId ): array {
89- $ userFolder = $ this ->rootFolder ->getUserFolder ($ userId );
90- $ file = $ userFolder ->getFirstNodeById ($ fileId );
91+ public function buildFileContentFromId (int $ fileId , string $ userId , ?int $ taskId ): array {
92+ $ file = null ;
93+ if ($ taskId !== null ) {
94+ $ task = $ this ->taskProcessingManager ->getUserTask ($ taskId , $ userId );
95+ $ files = $ this ->taskProcessingManager ->extractFileIdsFromTask ($ task );
96+
97+ if (array_search ($ fileId , $ files , true ) === false ) {
98+ throw new ProcessingException ('File does not exist ' );
99+ }
100+ $ file = $ this ->rootFolder ->getFirstNodeById ($ fileId );
101+
102+ if ($ file === null ) {
103+ $ file = $ this ->rootFolder ->getFirstNodeByIdInPath ($ fileId , '/ ' . $ this ->rootFolder ->getAppDataDirectoryName () . '/ ' );
104+ }
105+ } else {
106+ $ userFolder = $ this ->rootFolder ->getUserFolder ($ userId );
107+ $ file = $ userFolder ->getFirstNodeById ($ fileId );
108+ }
91109 return $ this ->buildFileContentFromFile ($ file );
92110 }
93111
@@ -114,26 +132,30 @@ public function buildFileContentFromFile(?File $file): array {
114132 }
115133
116134 $ fileType = $ file ->getMimeType ();
135+ // Backup incase the file does not have an extension
136+ if ($ fileType === 'application/octet-stream ' ) {
137+ $ fileType = mime_content_type ($ file ->fopen ('rb ' ));
138+ }
117139 if (str_starts_with ($ fileType , 'image/ ' )) {
118- return $ this ->buildImageContent ($ file );
140+ return $ this ->buildImageContent ($ file, $ fileType );
119141 // OpenAI only supports this for very specific models and support is not that common
120142 } elseif (str_starts_with ($ fileType , 'audio/ ' )) {
121- return $ this ->buildAudioContent ($ file );
143+ return $ this ->buildAudioContent ($ file, $ fileType );
122144 // OpenAI does not currently support video attachments
123145 } elseif (str_starts_with ($ fileType , 'video/ ' )) {
124- return $ this ->buildVideoContent ($ file );
146+ return $ this ->buildVideoContent ($ file, $ fileType );
125147 } elseif ($ fileType === 'application/pdf ' ) {
126- return $ this ->buildDocumentContent ($ file );
148+ return $ this ->buildDocumentContent ($ file, $ fileType );
127149 } else {
128- return $ this ->buildTextContent ($ file );
150+ return $ this ->buildTextContent ($ file, $ fileType );
129151 }
130152 }
131153
132154
133155 /**
134156 * @return list<array{type: string, image_url: array{url: string}}>
135157 */
136- private function buildImageContent (File $ file ): array {
158+ private function buildImageContent (File $ file, string $ fileType ): array {
137159 if (!$ this ->openAiSettingsService ->getMultimodalImageEnabled ()) {
138160 throw new UserFacingProcessingException (
139161 'Image attachments are disabled ' ,
@@ -142,7 +164,6 @@ private function buildImageContent(File $file): array {
142164 $ this ->l10n ->t ('Image attachments are unsupported. ' ),
143165 );
144166 }
145- $ fileType = $ file ->getMimeType ();
146167 if ($ this ->isUsingOpenAi () && !in_array ($ fileType , self ::VALID_IMAGE_MIME_TYPES , true )) {
147168 throw new UserFacingProcessingException (
148169 'Invalid input file type for OpenAI ' . $ fileType ,
@@ -162,7 +183,7 @@ private function buildImageContent(File $file): array {
162183 /**
163184 * @return list<array{type: string, input_audio: array{data: string, format: string}}>
164185 */
165- private function buildAudioContent (File $ file ): array {
186+ private function buildAudioContent (File $ file, string $ fileType ): array {
166187 if (!$ this ->openAiSettingsService ->getMultimodalAudioEnabled ()) {
167188 throw new UserFacingProcessingException (
168189 'Audio attachments are disabled ' ,
@@ -171,7 +192,6 @@ private function buildAudioContent(File $file): array {
171192 $ this ->l10n ->t ('Audio attachments are unsupported. ' ),
172193 );
173194 }
174- $ fileType = $ file ->getMimeType ();
175195
176196 if (!array_key_exists ($ fileType , self ::SUPPORTED_INPUT_AUDIO_FORMATS )) {
177197 throw new UserFacingProcessingException (
@@ -194,7 +214,7 @@ private function buildAudioContent(File $file): array {
194214 /**
195215 * @return list<array{type: string, video_url: array{url: string}}>
196216 */
197- private function buildVideoContent (File $ file ): array {
217+ private function buildVideoContent (File $ file, string $ fileType ): array {
198218 if (!$ this ->openAiSettingsService ->getMultimodalVideoEnabled ()) {
199219 throw new UserFacingProcessingException (
200220 'Video attachments are disabled ' ,
@@ -203,7 +223,6 @@ private function buildVideoContent(File $file): array {
203223 $ this ->l10n ->t ('Video attachments are unsupported. ' ),
204224 );
205225 }
206- $ fileType = $ file ->getMimeType ();
207226 return [[
208227 'type ' => 'video_url ' ,
209228 'video_url ' => [
@@ -215,7 +234,7 @@ private function buildVideoContent(File $file): array {
215234 /**
216235 * @return list<array{type: string, file: array{filename: string, file_data: string}}|array{type: string, image_url: array{url: string}}>
217236 */
218- private function buildDocumentContent (File $ file ): array {
237+ private function buildDocumentContent (File $ file, string $ fileType ): array {
219238 if (!$ this ->openAiSettingsService ->getMultimodalDocumentEnabled ()) {
220239 // Fallback to image if documents are not supported
221240 if ($ this ->openAiSettingsService ->getMultimodalImageEnabled ()) {
@@ -228,7 +247,6 @@ private function buildDocumentContent(File $file): array {
228247 $ this ->l10n ->t ('Document attachments are unsupported. ' ),
229248 );
230249 }
231- $ fileType = $ file ->getMimeType ();
232250 return [[
233251 'type ' => 'file ' ,
234252 'file ' => [
@@ -241,8 +259,7 @@ private function buildDocumentContent(File $file): array {
241259 /**
242260 * @return list<array{type: string, text: string}>
243261 */
244- private function buildTextContent (File $ file ): array {
245- $ fileType = $ file ->getMimeType ();
262+ private function buildTextContent (File $ file , string $ fileType ): array {
246263 // Sanity check that this isn't a binary
247264 if (!str_starts_with ($ fileType , 'text/ ' ) && !in_array ($ fileType , self ::VALID_TEXT_MIME_TYPES , true )) {
248265 throw new UserFacingProcessingException (
0 commit comments