Skip to content

Commit d51a35f

Browse files
committed
refactor: improves Result structure
1 parent 4e04fb5 commit d51a35f

File tree

2 files changed

+210
-40
lines changed

2 files changed

+210
-40
lines changed

src/Files/Utilities/MimeTypeUtil.php

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,81 @@ public static function getMimeTypeForExtension(string $extension): string
101101

102102
return self::$mimeTypes[$extension] ?? 'text/plain';
103103
}
104+
105+
/**
106+
* Checks if a MIME type is an image type.
107+
*
108+
* @since n.e.x.t
109+
*
110+
* @param string $mimeType The MIME type to check.
111+
* @return bool True if the MIME type is an image type.
112+
*/
113+
public static function isImageType(string $mimeType): bool
114+
{
115+
return strpos($mimeType, 'image/') === 0;
116+
}
117+
118+
/**
119+
* Checks if a MIME type is an audio type.
120+
*
121+
* @since n.e.x.t
122+
*
123+
* @param string $mimeType The MIME type to check.
124+
* @return bool True if the MIME type is an audio type.
125+
*/
126+
public static function isAudioType(string $mimeType): bool
127+
{
128+
return strpos($mimeType, 'audio/') === 0;
129+
}
130+
131+
/**
132+
* Checks if a MIME type is a video type.
133+
*
134+
* @since n.e.x.t
135+
*
136+
* @param string $mimeType The MIME type to check.
137+
* @return bool True if the MIME type is a video type.
138+
*/
139+
public static function isVideoType(string $mimeType): bool
140+
{
141+
return strpos($mimeType, 'video/') === 0;
142+
}
143+
144+
/**
145+
* Checks if a MIME type is a text type.
146+
*
147+
* @since n.e.x.t
148+
*
149+
* @param string $mimeType The MIME type to check.
150+
* @return bool True if the MIME type is a text type.
151+
*/
152+
public static function isTextType(string $mimeType): bool
153+
{
154+
return strpos($mimeType, 'text/') === 0;
155+
}
156+
157+
/**
158+
* Checks if a MIME type is a document type.
159+
*
160+
* @since n.e.x.t
161+
*
162+
* @param string $mimeType The MIME type to check.
163+
* @return bool True if the MIME type is a document type.
164+
*/
165+
public static function isDocumentType(string $mimeType): bool
166+
{
167+
$documentTypes = [
168+
'application/pdf',
169+
'application/msword',
170+
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
171+
'application/vnd.ms-excel',
172+
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
173+
'application/vnd.ms-powerpoint',
174+
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
175+
'application/vnd.oasis.opendocument.text',
176+
'application/vnd.oasis.opendocument.spreadsheet',
177+
];
178+
179+
return in_array($mimeType, $documentTypes, true);
180+
}
104181
}

src/Results/DTO/GenerativeAiResult.php

Lines changed: 133 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace WordPress\AiClient\Results\DTO;
66

77
use WordPress\AiClient\Files\Contracts\FileInterface;
8+
use WordPress\AiClient\Files\Utilities\MimeTypeUtil;
89
use WordPress\AiClient\Messages\DTO\Message;
910
use WordPress\AiClient\Messages\Enums\MessagePartTypeEnum;
1011
use WordPress\AiClient\Results\Contracts\ResultInterface;
@@ -48,9 +49,14 @@ class GenerativeAiResult implements ResultInterface
4849
* @param Candidate[] $candidates The generated candidates.
4950
* @param TokenUsage $tokenUsage Token usage statistics.
5051
* @param array<string, mixed> $providerMetadata Provider-specific metadata.
52+
* @throws \InvalidArgumentException If no candidates provided.
5153
*/
5254
public function __construct(string $id, array $candidates, TokenUsage $tokenUsage, array $providerMetadata = [])
5355
{
56+
if (empty($candidates)) {
57+
throw new \InvalidArgumentException('At least one candidate must be provided');
58+
}
59+
5460
$this->id = $id;
5561
$this->candidates = $candidates;
5662
$this->tokenUsage = $tokenUsage;
@@ -99,28 +105,75 @@ public function getProviderMetadata(): array
99105
return $this->providerMetadata;
100106
}
101107

108+
/**
109+
* Gets the total number of candidates.
110+
*
111+
* @since n.e.x.t
112+
*
113+
* @return int The total number of candidates.
114+
*/
115+
public function getTotalCandidates(): int
116+
{
117+
return count($this->candidates);
118+
}
119+
120+
/**
121+
* Checks if the result has multiple candidates.
122+
*
123+
* @since n.e.x.t
124+
*
125+
* @return bool True if there are multiple candidates, false otherwise.
126+
*/
127+
public function hasMultipleCandidates(): bool
128+
{
129+
return count($this->candidates) > 1;
130+
}
131+
102132
/**
103133
* Converts the first candidate to text.
104134
*
105135
* @since n.e.x.t
106136
*
107137
* @return string The text content.
108-
* @throws \RuntimeException If no candidates or no text content.
138+
* @throws \RuntimeException If no text content.
109139
*/
110140
public function toText(): string
111141
{
112-
if (empty($this->candidates)) {
113-
throw new \RuntimeException('No candidates available');
142+
$message = $this->candidates[0]->getMessage();
143+
foreach ($message->getParts() as $part) {
144+
$text = $part->getText();
145+
if ($text !== null) {
146+
return $text;
147+
}
114148
}
115149

150+
throw new \RuntimeException('No text content found in first candidate');
151+
}
152+
153+
/**
154+
* Converts the first candidate to a file.
155+
*
156+
* @since n.e.x.t
157+
*
158+
* @return FileInterface The file.
159+
* @throws \RuntimeException If no file content.
160+
*/
161+
public function toFile(): FileInterface
162+
{
116163
$message = $this->candidates[0]->getMessage();
117164
foreach ($message->getParts() as $part) {
118-
if ($part->getType()->equals(MessagePartTypeEnum::text()) && $part->getText() !== null) {
119-
return $part->getText();
165+
$inlineFile = $part->getInlineFile();
166+
if ($inlineFile !== null) {
167+
return $inlineFile;
168+
}
169+
170+
$remoteFile = $part->getRemoteFile();
171+
if ($remoteFile !== null) {
172+
return $remoteFile;
120173
}
121174
}
122175

123-
throw new \RuntimeException('No text content found in first candidate');
176+
throw new \RuntimeException('No file content found in first candidate');
124177
}
125178

126179
/**
@@ -129,25 +182,19 @@ public function toText(): string
129182
* @since n.e.x.t
130183
*
131184
* @return FileInterface The image file.
132-
* @throws \RuntimeException If no candidates or no image content.
185+
* @throws \RuntimeException If no image content.
133186
*/
134187
public function toImageFile(): FileInterface
135188
{
136-
if (empty($this->candidates)) {
137-
throw new \RuntimeException('No candidates available');
138-
}
189+
$file = $this->toFile();
139190

140-
$message = $this->candidates[0]->getMessage();
141-
foreach ($message->getParts() as $part) {
142-
if ($part->getType()->equals(MessagePartTypeEnum::inlineFile()) && $part->getInlineFile() !== null) {
143-
return $part->getInlineFile();
144-
}
145-
if ($part->getType()->equals(MessagePartTypeEnum::remoteFile()) && $part->getRemoteFile() !== null) {
146-
return $part->getRemoteFile();
147-
}
191+
if (!MimeTypeUtil::isImageType($file->getMimeType())) {
192+
throw new \RuntimeException(
193+
sprintf('File is not an image. MIME type: %s', $file->getMimeType())
194+
);
148195
}
149196

150-
throw new \RuntimeException('No image content found in first candidate');
197+
return $file;
151198
}
152199

153200
/**
@@ -156,12 +203,19 @@ public function toImageFile(): FileInterface
156203
* @since n.e.x.t
157204
*
158205
* @return FileInterface The audio file.
159-
* @throws \RuntimeException If no candidates or no audio content.
206+
* @throws \RuntimeException If no audio content.
160207
*/
161208
public function toAudioFile(): FileInterface
162209
{
163-
// Similar implementation to toImageFile, but checking for audio MIME types
164-
return $this->toImageFile(); // Simplified for now
210+
$file = $this->toFile();
211+
212+
if (!MimeTypeUtil::isAudioType($file->getMimeType())) {
213+
throw new \RuntimeException(
214+
sprintf('File is not an audio file. MIME type: %s', $file->getMimeType())
215+
);
216+
}
217+
218+
return $file;
165219
}
166220

167221
/**
@@ -170,12 +224,19 @@ public function toAudioFile(): FileInterface
170224
* @since n.e.x.t
171225
*
172226
* @return FileInterface The video file.
173-
* @throws \RuntimeException If no candidates or no video content.
227+
* @throws \RuntimeException If no video content.
174228
*/
175229
public function toVideoFile(): FileInterface
176230
{
177-
// Similar implementation to toImageFile, but checking for video MIME types
178-
return $this->toImageFile(); // Simplified for now
231+
$file = $this->toFile();
232+
233+
if (!MimeTypeUtil::isVideoType($file->getMimeType())) {
234+
throw new \RuntimeException(
235+
sprintf('File is not a video file. MIME type: %s', $file->getMimeType())
236+
);
237+
}
238+
239+
return $file;
179240
}
180241

181242
/**
@@ -184,14 +245,9 @@ public function toVideoFile(): FileInterface
184245
* @since n.e.x.t
185246
*
186247
* @return Message The message.
187-
* @throws \RuntimeException If no candidates available.
188248
*/
189249
public function toMessage(): Message
190250
{
191-
if (empty($this->candidates)) {
192-
throw new \RuntimeException('No candidates available');
193-
}
194-
195251
return $this->candidates[0]->getMessage();
196252
}
197253

@@ -208,8 +264,9 @@ public function toTexts(): array
208264
foreach ($this->candidates as $candidate) {
209265
$message = $candidate->getMessage();
210266
foreach ($message->getParts() as $part) {
211-
if ($part->getType()->equals(MessagePartTypeEnum::text()) && $part->getText() !== null) {
212-
$texts[] = $part->getText();
267+
$text = $part->getText();
268+
if ($text !== null) {
269+
$texts[] = $text;
213270
break;
214271
}
215272
}
@@ -230,12 +287,15 @@ public function toImageFiles(): array
230287
foreach ($this->candidates as $candidate) {
231288
$message = $candidate->getMessage();
232289
foreach ($message->getParts() as $part) {
233-
if ($part->getType()->equals(MessagePartTypeEnum::inlineFile()) && $part->getInlineFile() !== null) {
234-
$files[] = $part->getInlineFile();
290+
$inlineFile = $part->getInlineFile();
291+
if ($inlineFile !== null && MimeTypeUtil::isImageType($inlineFile->getMimeType())) {
292+
$files[] = $inlineFile;
235293
break;
236294
}
237-
if ($part->getType()->equals(MessagePartTypeEnum::remoteFile()) && $part->getRemoteFile() !== null) {
238-
$files[] = $part->getRemoteFile();
295+
296+
$remoteFile = $part->getRemoteFile();
297+
if ($remoteFile !== null && MimeTypeUtil::isImageType($remoteFile->getMimeType())) {
298+
$files[] = $remoteFile;
239299
break;
240300
}
241301
}
@@ -252,8 +312,24 @@ public function toImageFiles(): array
252312
*/
253313
public function toAudioFiles(): array
254314
{
255-
// Similar implementation to toImageFiles, but checking for audio MIME types
256-
return $this->toImageFiles(); // Simplified for now
315+
$files = [];
316+
foreach ($this->candidates as $candidate) {
317+
$message = $candidate->getMessage();
318+
foreach ($message->getParts() as $part) {
319+
$inlineFile = $part->getInlineFile();
320+
if ($inlineFile !== null && MimeTypeUtil::isAudioType($inlineFile->getMimeType())) {
321+
$files[] = $inlineFile;
322+
break;
323+
}
324+
325+
$remoteFile = $part->getRemoteFile();
326+
if ($remoteFile !== null && MimeTypeUtil::isAudioType($remoteFile->getMimeType())) {
327+
$files[] = $remoteFile;
328+
break;
329+
}
330+
}
331+
}
332+
return $files;
257333
}
258334

259335
/**
@@ -265,8 +341,24 @@ public function toAudioFiles(): array
265341
*/
266342
public function toVideoFiles(): array
267343
{
268-
// Similar implementation to toImageFiles, but checking for video MIME types
269-
return $this->toImageFiles(); // Simplified for now
344+
$files = [];
345+
foreach ($this->candidates as $candidate) {
346+
$message = $candidate->getMessage();
347+
foreach ($message->getParts() as $part) {
348+
$inlineFile = $part->getInlineFile();
349+
if ($inlineFile !== null && MimeTypeUtil::isVideoType($inlineFile->getMimeType())) {
350+
$files[] = $inlineFile;
351+
break;
352+
}
353+
354+
$remoteFile = $part->getRemoteFile();
355+
if ($remoteFile !== null && MimeTypeUtil::isVideoType($remoteFile->getMimeType())) {
356+
$files[] = $remoteFile;
357+
break;
358+
}
359+
}
360+
}
361+
return $files;
270362
}
271363

272364
/**
@@ -298,6 +390,7 @@ public static function getJsonSchema(): array
298390
'candidates' => [
299391
'type' => 'array',
300392
'items' => Candidate::getJsonSchema(),
393+
'minItems' => 1,
301394
'description' => 'The generated candidates.',
302395
],
303396
'tokenUsage' => TokenUsage::getJsonSchema(),

0 commit comments

Comments
 (0)