Skip to content

Commit 29c06c8

Browse files
author
Mohamed Khaled
committed
Improve ModelRequirements performance and architecture
1 parent 78c8f53 commit 29c06c8

File tree

1 file changed

+133
-35
lines changed

1 file changed

+133
-35
lines changed

src/Providers/Models/DTO/ModelRequirements.php

Lines changed: 133 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -94,44 +94,42 @@ public function getRequiredOptions(): array
9494
/**
9595
* Checks whether the given model metadata meets these requirements.
9696
*
97-
* @since 0.2.0
97+
* @since n.e.x.t
9898
*
9999
* @param ModelMetadata $metadata The model metadata to check against.
100100
* @return bool True if the model meets all requirements, false otherwise.
101101
*/
102102
public function areMetBy(ModelMetadata $metadata): bool
103103
{
104-
// Check if all required capabilities are supported
104+
// Create lookup maps for better performance (instead of nested foreach loops)
105+
$capabilitiesMap = [];
106+
foreach ($metadata->getSupportedCapabilities() as $capability) {
107+
$capabilitiesMap[$capability->value] = $capability;
108+
}
109+
110+
$optionsMap = [];
111+
foreach ($metadata->getSupportedOptions() as $option) {
112+
$optionsMap[$option->getName()->value] = $option;
113+
}
114+
115+
// Check if all required capabilities are supported using map lookup
105116
foreach ($this->requiredCapabilities as $requiredCapability) {
106-
$supported = false;
107-
foreach ($metadata->getSupportedCapabilities() as $supportedCapability) {
108-
if ($supportedCapability->equals($requiredCapability)) {
109-
$supported = true;
110-
break;
111-
}
112-
}
113-
if (!$supported) {
117+
if (!isset($capabilitiesMap[$requiredCapability->value])) {
114118
return false;
115119
}
116120
}
117121

118122
// Check if all required options are supported with the specified values
119123
foreach ($this->requiredOptions as $requiredOption) {
120-
$optionSupported = false;
121-
$supportedOptions = $metadata->getSupportedOptions();
122-
123-
foreach ($supportedOptions as $supportedOption) {
124-
if ($supportedOption->getName()->equals($requiredOption->getName())) {
125-
// Check if the required value is supported by this option
126-
if ($supportedOption->isSupportedValue($requiredOption->getValue())) {
127-
$optionSupported = true;
128-
break;
129-
}
130-
}
124+
// Use map lookup instead of linear search
125+
if (!isset($optionsMap[$requiredOption->getName()->value])) {
126+
return false;
131127
}
132128

133-
// If no supported options at all, this is only OK if we have no required options
134-
if (!$optionSupported) {
129+
$supportedOption = $optionsMap[$requiredOption->getName()->value];
130+
131+
// Check if the required value is supported by this option
132+
if (!$supportedOption->isSupportedValue($requiredOption->getValue())) {
135133
return false;
136134
}
137135
}
@@ -142,7 +140,7 @@ public function areMetBy(ModelMetadata $metadata): bool
142140
/**
143141
* Creates ModelRequirements from prompt data and model configuration.
144142
*
145-
* @since 0.2.0
143+
* @since n.e.x.t
146144
*
147145
* @param CapabilityEnum $capability The capability the model must support.
148146
* @param list<Message> $messages The messages in the conversation.
@@ -193,8 +191,41 @@ public static function fromPromptData(CapabilityEnum $capability, array $message
193191
}
194192
}
195193

196-
//
197-
// Convert ModelConfig to RequiredOptions (moved from ModelConfig::toRequiredOptions)
194+
// Convert ModelConfig to RequiredOptions
195+
$requiredOptions = self::toRequiredOptions($modelConfig);
196+
197+
// Add additional options based on message analysis
198+
if ($hasFunctionMessageParts) {
199+
$requiredOptions = self::includeInRequiredOptions(
200+
$requiredOptions,
201+
new RequiredOption(OptionEnum::functionDeclarations(), true)
202+
);
203+
}
204+
205+
// Add input modalities if we have any inputs
206+
if (!empty($inputModalities)) {
207+
// Remove duplicates
208+
$inputModalities = array_unique($inputModalities, SORT_REGULAR);
209+
$requiredOptions = self::includeInRequiredOptions(
210+
$requiredOptions,
211+
new RequiredOption(OptionEnum::inputModalities(), array_values($inputModalities))
212+
);
213+
}
214+
215+
// Step 6: Return new ModelRequirements
216+
return new self($capabilities, $requiredOptions);
217+
}
218+
219+
/**
220+
* Converts ModelConfig to an array of RequiredOptions.
221+
*
222+
* @since n.e.x.t
223+
*
224+
* @param ModelConfig $modelConfig The model configuration.
225+
* @return list<RequiredOption> The required options.
226+
*/
227+
private static function toRequiredOptions(ModelConfig $modelConfig): array
228+
{
198229
$requiredOptions = [];
199230

200231
// Map properties that have corresponding OptionEnum values
@@ -261,20 +292,87 @@ public static function fromPromptData(CapabilityEnum $capability, array $message
261292
);
262293
}
263294

264-
// Step 5: Add additional options based on message analysis
265-
if ($hasFunctionMessageParts) {
295+
// Handle properties without OptionEnum values as custom options
296+
if ($modelConfig->getStopSequences() !== null) {
297+
$requiredOptions[] = new RequiredOption(OptionEnum::stopSequences(), $modelConfig->getStopSequences());
298+
}
299+
300+
if ($modelConfig->getPresencePenalty() !== null) {
301+
$requiredOptions[] = new RequiredOption(OptionEnum::presencePenalty(), $modelConfig->getPresencePenalty());
302+
}
303+
304+
if ($modelConfig->getFrequencyPenalty() !== null) {
305+
$requiredOptions[] = new RequiredOption(
306+
OptionEnum::frequencyPenalty(),
307+
$modelConfig->getFrequencyPenalty()
308+
);
309+
}
310+
311+
if ($modelConfig->getLogprobs() !== null) {
312+
$requiredOptions[] = new RequiredOption(OptionEnum::logprobs(), $modelConfig->getLogprobs());
313+
}
314+
315+
if ($modelConfig->getTopLogprobs() !== null) {
316+
$requiredOptions[] = new RequiredOption(OptionEnum::topLogprobs(), $modelConfig->getTopLogprobs());
317+
}
318+
319+
if ($modelConfig->getFunctionDeclarations() !== null) {
266320
$requiredOptions[] = new RequiredOption(OptionEnum::functionDeclarations(), true);
267321
}
268322

269-
// Add input modalities if we have any inputs
270-
if (!empty($inputModalities)) {
271-
// Remove duplicates
272-
$inputModalities = array_unique($inputModalities, SORT_REGULAR);
273-
$requiredOptions[] = new RequiredOption(OptionEnum::inputModalities(), array_values($inputModalities));
323+
if ($modelConfig->getWebSearch() !== null) {
324+
$requiredOptions[] = new RequiredOption(OptionEnum::webSearch(), true);
274325
}
275326

276-
// Step 6: Return new ModelRequirements
277-
return new self($capabilities, $requiredOptions);
327+
if ($modelConfig->getOutputFileType() !== null) {
328+
$requiredOptions[] = new RequiredOption(OptionEnum::outputFileType(), $modelConfig->getOutputFileType());
329+
}
330+
331+
if ($modelConfig->getOutputMediaOrientation() !== null) {
332+
$requiredOptions[] = new RequiredOption(
333+
OptionEnum::outputMediaOrientation(),
334+
$modelConfig->getOutputMediaOrientation()
335+
);
336+
}
337+
338+
if ($modelConfig->getOutputMediaAspectRatio() !== null) {
339+
$requiredOptions[] = new RequiredOption(
340+
OptionEnum::outputMediaAspectRatio(),
341+
$modelConfig->getOutputMediaAspectRatio()
342+
);
343+
}
344+
345+
// Add custom options as individual RequiredOptions
346+
foreach ($modelConfig->getCustomOptions() as $key => $value) {
347+
$requiredOptions[] = new RequiredOption(OptionEnum::customOptions(), [$key => $value]);
348+
}
349+
350+
return $requiredOptions;
351+
}
352+
353+
/**
354+
* Includes a RequiredOption in the array, ensuring no duplicates based on option name.
355+
*
356+
* @since n.e.x.t
357+
*
358+
* @param list<RequiredOption> $requiredOptions The existing required options.
359+
* @param RequiredOption $newOption The new option to include.
360+
* @return list<RequiredOption> The updated required options array.
361+
*/
362+
private static function includeInRequiredOptions(array $requiredOptions, RequiredOption $newOption): array
363+
{
364+
// Check if we already have this option name
365+
foreach ($requiredOptions as $index => $existingOption) {
366+
if ($existingOption->getName()->equals($newOption->getName())) {
367+
// Replace existing option with new one
368+
$requiredOptions[$index] = $newOption;
369+
return $requiredOptions;
370+
}
371+
}
372+
373+
// Option not found, add it
374+
$requiredOptions[] = $newOption;
375+
return $requiredOptions;
278376
}
279377

280378
/**

0 commit comments

Comments
 (0)