913 lines
26 KiB
PHP
913 lines
26 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Config;
|
|
|
|
final class PromptBuilderConfig
|
|
{
|
|
/**
|
|
* @param array<string, mixed> $config
|
|
*/
|
|
public function __construct(
|
|
private readonly array $config = [],
|
|
private readonly ?DomainVocabularyConfig $vocabulary = null,
|
|
) {
|
|
}
|
|
|
|
public function getCharsPerToken(): int
|
|
{
|
|
return $this->getRequiredInt('budget.chars_per_token');
|
|
}
|
|
|
|
public function getHistoryPaddingChars(): int
|
|
{
|
|
return $this->getRequiredInt('budget.history_padding_chars');
|
|
}
|
|
|
|
public function getOutputReserveRatio(): float
|
|
{
|
|
return $this->getRequiredFloat('budget.output_reserve_ratio');
|
|
}
|
|
|
|
public function getOutputReserveMinTokens(): int
|
|
{
|
|
return $this->getRequiredInt('budget.output_reserve_min_tokens');
|
|
}
|
|
|
|
public function getOutputReserveMaxTokens(): int
|
|
{
|
|
return $this->getRequiredInt('budget.output_reserve_max_tokens');
|
|
}
|
|
|
|
public function getSafetyReserveRatio(): float
|
|
{
|
|
return $this->getRequiredFloat('budget.safety_reserve_ratio');
|
|
}
|
|
|
|
public function getSafetyReserveMinTokens(): int
|
|
{
|
|
return $this->getRequiredInt('budget.safety_reserve_min_tokens');
|
|
}
|
|
|
|
public function getSafetyReserveMaxTokens(): int
|
|
{
|
|
return $this->getRequiredInt('budget.safety_reserve_max_tokens');
|
|
}
|
|
|
|
public function getMinPromptBudgetTokens(): int
|
|
{
|
|
return $this->getRequiredInt('budget.min_prompt_budget_tokens');
|
|
}
|
|
|
|
public function getMaxShopResultsInPrompt(): int
|
|
{
|
|
return $this->getRequiredInt('shop_results.max_results_in_prompt');
|
|
}
|
|
|
|
public function getDetailedShopResultsMaxCount(): int
|
|
{
|
|
return $this->getRequiredInt('shop_results.detailed_max_count');
|
|
}
|
|
|
|
public function getTechnicalProductKeywordMatchThreshold(): int
|
|
{
|
|
return $this->getRequiredInt('technical_product_keyword_match_threshold');
|
|
}
|
|
|
|
|
|
|
|
private function getRequiredInt(string $path): int
|
|
{
|
|
$value = $this->getRequiredValue($path);
|
|
|
|
if (!is_numeric($value)) {
|
|
throw new \InvalidArgumentException(sprintf('RetrieX prompt config value "%s" must be numeric.', $path));
|
|
}
|
|
|
|
return (int) $value;
|
|
}
|
|
|
|
private function getRequiredFloat(string $path): float
|
|
{
|
|
$value = $this->getRequiredValue($path);
|
|
|
|
if (!is_numeric($value)) {
|
|
throw new \InvalidArgumentException(sprintf('RetrieX prompt config value "%s" must be numeric.', $path));
|
|
}
|
|
|
|
return (float) $value;
|
|
}
|
|
|
|
private function getRequiredBool(string $path): bool
|
|
{
|
|
$value = $this->getRequiredValue($path);
|
|
|
|
if (!is_bool($value)) {
|
|
throw new \InvalidArgumentException(sprintf('RetrieX prompt config value "%s" must be boolean.', $path));
|
|
}
|
|
|
|
return $value;
|
|
}
|
|
|
|
|
|
private function getRequiredString(string $path): string
|
|
{
|
|
$value = $this->getRequiredValue($path);
|
|
|
|
if (!is_scalar($value)) {
|
|
throw new \InvalidArgumentException(sprintf('RetrieX prompt config value "%s" must be a scalar string.', $path));
|
|
}
|
|
|
|
$value = (string) $value;
|
|
if (trim($value) === '') {
|
|
throw new \InvalidArgumentException(sprintf('RetrieX prompt config value "%s" must not be empty.', $path));
|
|
}
|
|
|
|
return $value;
|
|
}
|
|
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
private function getRequiredStringList(string $path): array
|
|
{
|
|
$value = $this->getRequiredValue($path);
|
|
|
|
if (!is_array($value)) {
|
|
throw new \InvalidArgumentException(sprintf('RetrieX prompt config value "%s" must be a string list.', $path));
|
|
}
|
|
|
|
$out = [];
|
|
foreach ($value as $item) {
|
|
if (!is_scalar($item)) {
|
|
continue;
|
|
}
|
|
|
|
$item = trim((string) $item);
|
|
if ($item === '' || in_array($item, $out, true)) {
|
|
continue;
|
|
}
|
|
|
|
$out[] = $item;
|
|
}
|
|
|
|
if ($out === []) {
|
|
throw new \InvalidArgumentException(sprintf('RetrieX prompt config value "%s" must contain at least one string.', $path));
|
|
}
|
|
|
|
return $out;
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
private function getConfiguredStringListOrVocabularyView(string $configPath, string $viewPathConfigPath): array
|
|
{
|
|
if ($this->hasPath($configPath)) {
|
|
return $this->getRequiredStringList($configPath);
|
|
}
|
|
|
|
if ($this->vocabulary === null) {
|
|
throw new \InvalidArgumentException(sprintf(
|
|
'RetrieX prompt config path "%s" is missing and no vocabulary resolver is available.',
|
|
$configPath
|
|
));
|
|
}
|
|
|
|
$viewPath = $this->getRequiredString($viewPathConfigPath);
|
|
$terms = $this->vocabulary->view($viewPath, []);
|
|
|
|
if ($terms === []) {
|
|
throw new \InvalidArgumentException(sprintf(
|
|
'RetrieX prompt vocabulary view "%s" resolved to an empty list.',
|
|
$viewPath
|
|
));
|
|
}
|
|
|
|
return $terms;
|
|
}
|
|
|
|
/**
|
|
* @return array<string, string[]>
|
|
*/
|
|
private function getVocabularyStringListMap(string $mapPathConfigPath): array
|
|
{
|
|
if (!$this->hasPath($mapPathConfigPath)) {
|
|
return [];
|
|
}
|
|
|
|
if ($this->vocabulary === null) {
|
|
throw new \InvalidArgumentException(sprintf(
|
|
'RetrieX prompt vocabulary map config path "%s" is set but no vocabulary resolver is available.',
|
|
$mapPathConfigPath
|
|
));
|
|
}
|
|
|
|
$mapPath = $this->getRequiredString($mapPathConfigPath);
|
|
$map = $this->vocabulary->map($mapPath, []);
|
|
|
|
if ($map === []) {
|
|
throw new \InvalidArgumentException(sprintf(
|
|
'RetrieX prompt vocabulary map "%s" resolved to an empty map.',
|
|
$mapPath
|
|
));
|
|
}
|
|
|
|
return $map;
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $item
|
|
* @param array<string, string[]> $vocabularyMap
|
|
* @return string[]
|
|
*/
|
|
private function getParameterStringList(array $item, string $id, string $localKey, array $vocabularyMap): array
|
|
{
|
|
if (array_key_exists($localKey, $item)) {
|
|
return $this->normalizeMixedStringList($item[$localKey]);
|
|
}
|
|
|
|
return $vocabularyMap[$id] ?? [];
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
private function getOptionalStringList(string $path): array
|
|
{
|
|
$value = $this->getOptionalValue($path);
|
|
|
|
if ($value === null) {
|
|
return [];
|
|
}
|
|
|
|
if (!is_array($value)) {
|
|
throw new \InvalidArgumentException(sprintf('RetrieX prompt config value "%s" must be a string list.', $path));
|
|
}
|
|
|
|
$out = [];
|
|
foreach ($value as $item) {
|
|
if (!is_scalar($item)) {
|
|
continue;
|
|
}
|
|
|
|
$item = trim((string) $item);
|
|
if ($item === '' || in_array($item, $out, true)) {
|
|
continue;
|
|
}
|
|
|
|
$out[] = $item;
|
|
}
|
|
|
|
return $out;
|
|
}
|
|
|
|
|
|
|
|
private function hasPath(string $path): bool
|
|
{
|
|
$current = $this->config;
|
|
|
|
foreach (explode('.', $path) as $segment) {
|
|
if (!is_array($current) || !array_key_exists($segment, $current)) {
|
|
return false;
|
|
}
|
|
|
|
$current = $current[$segment];
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private function getOptionalValue(string $path): mixed
|
|
{
|
|
$current = $this->config;
|
|
|
|
foreach (explode('.', $path) as $segment) {
|
|
if (!is_array($current) || !array_key_exists($segment, $current)) {
|
|
return null;
|
|
}
|
|
|
|
$current = $current[$segment];
|
|
}
|
|
|
|
return $current;
|
|
}
|
|
|
|
private function getRequiredValue(string $path): mixed
|
|
{
|
|
$current = $this->config;
|
|
|
|
foreach (explode('.', $path) as $segment) {
|
|
if (!is_array($current) || !array_key_exists($segment, $current)) {
|
|
throw new \InvalidArgumentException(sprintf('Missing required RetrieX prompt config path "%s".', $path));
|
|
}
|
|
|
|
$current = $current[$segment];
|
|
}
|
|
|
|
return $current;
|
|
}
|
|
|
|
public function getSystemSectionLabel(): string
|
|
{
|
|
return $this->getRequiredString('sections.system_label');
|
|
}
|
|
|
|
public function getUserQuestionSectionLabel(): string
|
|
{
|
|
return $this->getRequiredString('sections.user_question_label');
|
|
}
|
|
|
|
public function getConversationContextSectionLabel(): string
|
|
{
|
|
return $this->getRequiredString('sections.conversation_context_label');
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getConversationContextIntroLines(): array
|
|
{
|
|
return $this->getRequiredStringList('conversation_context.intro_lines');
|
|
}
|
|
|
|
public function getShopSearchQuerySectionLabel(): string
|
|
{
|
|
return $this->getRequiredString('sections.shop_search_query_label');
|
|
}
|
|
|
|
public function getShopSearchQuerySourceLine(): string
|
|
{
|
|
return $this->getRequiredString('shop_search.source_line');
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getLiveShopResultsHeaderLines(): array
|
|
{
|
|
return $this->getRequiredStringList('shop_results.header_lines');
|
|
}
|
|
|
|
public function getLiveShopResultsOverflowNoticeTemplate(): string
|
|
{
|
|
return $this->getRequiredString('shop_results.overflow_notice_template');
|
|
}
|
|
|
|
public function getShopRecordHeaderTemplate(): string
|
|
{
|
|
return $this->getRequiredString('shop_results.record_header_template');
|
|
}
|
|
|
|
public function getShopExactProductNameLabel(): string
|
|
{
|
|
return $this->getRequiredString('shop_results.exact_product_name_label');
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getShopAtomicRecordNoteLines(): array
|
|
{
|
|
return $this->getRequiredStringList('shop_results.atomic_record_note_lines');
|
|
}
|
|
|
|
public function getOutputPrioritySectionLabel(): string
|
|
{
|
|
return $this->getRequiredString('sections.output_priority_label');
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getOutputPriorityRules(): array
|
|
{
|
|
return $this->getRequiredStringList('output_priority.rules');
|
|
}
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getOutputPriorityTechnicalRules(): array
|
|
{
|
|
return $this->getRequiredStringList('output_priority.technical_rules');
|
|
}
|
|
|
|
public function getFallbackEscalationSectionLabel(): string
|
|
{
|
|
return $this->getRequiredString('sections.fallback_escalation_label');
|
|
}
|
|
|
|
public function getFallbackEscalationStateLineTemplate(): string
|
|
{
|
|
return $this->getRequiredString('fallback_escalation.state_line_template');
|
|
}
|
|
|
|
public function getFallbackEscalationProvidedShopResultsContextRule(): string
|
|
{
|
|
return $this->getRequiredString('fallback_escalation.provided_shop_results_context_rule');
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getFallbackEscalationBaseRules(): array
|
|
{
|
|
return $this->getRequiredStringList('fallback_escalation.base_rules');
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getFallbackEscalationStateRules(string $state): array
|
|
{
|
|
return $this->getOptionalStringList('fallback_escalation.states.' . $state);
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getFallbackEscalationWithoutShopCheckRules(): array
|
|
{
|
|
return $this->getRequiredStringList('fallback_escalation.without_shop_check_rules');
|
|
}
|
|
|
|
public function getResponseFormatSectionLabel(): string
|
|
{
|
|
return $this->getRequiredString('sections.response_format_label');
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getResponseFormatBaseRules(): array
|
|
{
|
|
return $this->getRequiredStringList('response_format.base_rules');
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getResponseFormatWithShopRules(): array
|
|
{
|
|
return $this->getRequiredStringList('response_format.with_shop_rules');
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getResponseFormatWithoutShopRules(): array
|
|
{
|
|
return $this->getRequiredStringList('response_format.without_shop_rules');
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getResponseFormatTechnicalRules(): array
|
|
{
|
|
return $this->getRequiredStringList('response_format.technical_rules');
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getResponseFormatAccessoryRules(): array
|
|
{
|
|
return $this->getRequiredStringList('response_format.accessory_rules');
|
|
}
|
|
|
|
public function getLanguageRulesSectionLabel(): string
|
|
{
|
|
return $this->getRequiredString('sections.language_rules_label');
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getLanguageRules(): array
|
|
{
|
|
return $this->getRequiredStringList('language.rules');
|
|
}
|
|
|
|
public function getFactGroundingRulesSectionLabel(): string
|
|
{
|
|
return $this->getRequiredString('sections.fact_grounding_rules_label');
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getFactGroundingBaseRules(): array
|
|
{
|
|
return $this->getRequiredStringList('fact_grounding.base_rules');
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getFactGroundingWithShopRules(): array
|
|
{
|
|
return $this->getRequiredStringList('fact_grounding.with_shop_rules');
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getFactGroundingWithoutShopRules(): array
|
|
{
|
|
return $this->getRequiredStringList('fact_grounding.without_shop_rules');
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getFactGroundingTechnicalRules(): array
|
|
{
|
|
return $this->getRequiredStringList('fact_grounding.technical_rules');
|
|
}
|
|
|
|
public function getRetrievedKnowledgeSectionLabel(): string
|
|
{
|
|
return $this->getRequiredString('sections.retrieved_knowledge_label');
|
|
}
|
|
|
|
public function getRetrievedKnowledgeSourceLine(): string
|
|
{
|
|
return $this->getRequiredString('retrieved_knowledge.source_line');
|
|
}
|
|
|
|
public function getUrlContentSectionLabel(): string
|
|
{
|
|
return $this->getRequiredString('sections.url_content_label');
|
|
}
|
|
|
|
public function getUrlContentSourceLine(): string
|
|
{
|
|
return $this->getRequiredString('url_content.source_line');
|
|
}
|
|
|
|
public function getShopProductNumberLabel(): string
|
|
{
|
|
return $this->getRequiredString('shop_results.fields.product_number_label');
|
|
}
|
|
|
|
public function getShopManufacturerLabel(): string
|
|
{
|
|
return $this->getRequiredString('shop_results.fields.manufacturer_label');
|
|
}
|
|
|
|
public function getShopPriceLabel(): string
|
|
{
|
|
return $this->getRequiredString('shop_results.fields.price_label');
|
|
}
|
|
|
|
public function getShopAvailabilityLabel(): string
|
|
{
|
|
return $this->getRequiredString('shop_results.fields.availability_label');
|
|
}
|
|
|
|
public function getShopAvailabilityYesLabel(): string
|
|
{
|
|
return $this->getRequiredString('shop_results.fields.availability_yes_label');
|
|
}
|
|
|
|
public function getShopAvailabilityNoLabel(): string
|
|
{
|
|
return $this->getRequiredString('shop_results.fields.availability_no_label');
|
|
}
|
|
|
|
public function getShopHighlightPrefix(): string
|
|
{
|
|
return $this->getRequiredString('shop_results.fields.highlight_prefix');
|
|
}
|
|
|
|
public function getShopUrlLabel(): string
|
|
{
|
|
return $this->getRequiredString('shop_results.fields.url_label');
|
|
}
|
|
|
|
public function getShopProductImageLabel(): string
|
|
{
|
|
return $this->getRequiredString('shop_results.fields.product_image_label');
|
|
}
|
|
|
|
public function getShopDescriptionLabel(): string
|
|
{
|
|
return $this->getRequiredString('shop_results.fields.description_label');
|
|
}
|
|
|
|
public function getShopMetaInformationLabel(): string
|
|
{
|
|
return $this->getRequiredString('shop_results.fields.meta_information_label');
|
|
}
|
|
|
|
public function getShopRequestedRoleLabel(): string
|
|
{
|
|
return $this->getRequiredString('shop_results.fields.requested_role_label');
|
|
}
|
|
|
|
public function getShopInferredRoleLabel(): string
|
|
{
|
|
return $this->getRequiredString('shop_results.fields.inferred_role_label');
|
|
}
|
|
|
|
public function getShopRoleCompatibilityLabel(): string
|
|
{
|
|
return $this->getRequiredString('shop_results.fields.role_compatibility_label');
|
|
}
|
|
|
|
public function getShopRoleIncompatibleCommercialSuppressionNote(): string
|
|
{
|
|
return $this->getRequiredString('shop_results.fields.role_incompatible_commercial_suppression_note');
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getMainDeviceRequestRoleKeywords(): array
|
|
{
|
|
return $this->getConfiguredStringListOrVocabularyView(
|
|
'role_guard.main_device_request_keywords',
|
|
'vocabulary_views.main_device_request_keywords'
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getMainDeviceProductRoleKeywords(): array
|
|
{
|
|
return $this->getConfiguredStringListOrVocabularyView(
|
|
'role_guard.main_device_product_keywords',
|
|
'vocabulary_views.main_device_product_keywords'
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getAccessoryProductRoleKeywords(): array
|
|
{
|
|
return $this->getConfiguredStringListOrVocabularyView(
|
|
'role_guard.accessory_product_keywords',
|
|
'vocabulary_views.accessory_product_keywords'
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getDirectMainDeviceRequestPatterns(): array
|
|
{
|
|
return $this->getRequiredStringList('role_guard.direct_main_device_request_patterns');
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getTechnicalProductKeywords(): array
|
|
{
|
|
return $this->getConfiguredStringListOrVocabularyView(
|
|
'technical_product_keywords',
|
|
'vocabulary_views.technical_product_keywords'
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getAccessoryRequestKeywords(): array
|
|
{
|
|
return $this->getConfiguredStringListOrVocabularyView(
|
|
'accessory_request_keywords',
|
|
'vocabulary_views.accessory_request_keywords'
|
|
);
|
|
}
|
|
|
|
public function getMeasurementEvidenceSectionLabel(): string
|
|
{
|
|
return $this->getRequiredString('sections.measurement_evidence_label');
|
|
}
|
|
|
|
public function isNumericValueFocusEnabled(): bool
|
|
{
|
|
return $this->getRequiredBool('numeric_value_focus.enabled');
|
|
}
|
|
|
|
public function getNumericValueFocusSectionLabel(): string
|
|
{
|
|
return $this->getRequiredString('sections.numeric_value_focus_label');
|
|
}
|
|
|
|
public function getNumericValueFocusMaxValues(): int
|
|
{
|
|
return $this->getRequiredInt('numeric_value_focus.max_values');
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getNumericValueFocusPatterns(): array
|
|
{
|
|
return $this->getRequiredStringList('numeric_value_focus.value_patterns');
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getNumericValueFocusRules(): array
|
|
{
|
|
return $this->getRequiredStringList('numeric_value_focus.rules');
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getMeasurementEvidenceIntroRules(): array
|
|
{
|
|
return $this->getRequiredStringList('measurement_evidence_guard.intro_rules');
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getMeasurementEvidenceProductSpecificRules(): array
|
|
{
|
|
return $this->getRequiredStringList('measurement_evidence_guard.product_specific_rules');
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getMeasurementEvidenceGenericRequestPatterns(): array
|
|
{
|
|
return $this->getRequiredStringList('measurement_evidence_guard.generic_request_patterns');
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getMeasurementEvidenceGenericPositiveContextTerms(): array
|
|
{
|
|
return $this->getConfiguredStringListOrVocabularyView(
|
|
'measurement_evidence_guard.generic_positive_context_terms',
|
|
'measurement_evidence_guard.vocabulary_views.generic_positive_context_terms'
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getMeasurementEvidenceGenericNegativeContextTerms(): array
|
|
{
|
|
return $this->getConfiguredStringListOrVocabularyView(
|
|
'measurement_evidence_guard.generic_negative_context_terms',
|
|
'measurement_evidence_guard.vocabulary_views.generic_negative_context_terms'
|
|
);
|
|
}
|
|
|
|
public function getMeasurementEvidenceGenericSafeNoEvidenceAnswerTemplate(): string
|
|
{
|
|
return $this->getRequiredString('measurement_evidence_guard.generic_safe_no_evidence_answer_template_de');
|
|
}
|
|
|
|
public function getMeasurementEvidenceGenericSafeNoAccessoryEvidenceAnswerTemplate(): string
|
|
{
|
|
return $this->getRequiredString('measurement_evidence_guard.generic_safe_no_accessory_evidence_answer_template_de');
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getMeasurementEvidenceAccessoryLookupGuardTerms(): array
|
|
{
|
|
return $this->getConfiguredStringListOrVocabularyView(
|
|
'measurement_evidence_guard.accessory_lookup_guard_terms',
|
|
'measurement_evidence_guard.vocabulary_views.accessory_lookup_guard_terms'
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getMeasurementEvidenceAccessoryLookupPassthroughTerms(): array
|
|
{
|
|
return $this->getConfiguredStringListOrVocabularyView(
|
|
'measurement_evidence_guard.accessory_lookup_passthrough_terms',
|
|
'measurement_evidence_guard.vocabulary_views.accessory_lookup_passthrough_terms'
|
|
);
|
|
}
|
|
|
|
public function getMeasurementEvidenceRuleTemplate(string $key): string
|
|
{
|
|
return $this->getRequiredString('measurement_evidence_guard.rule_templates.' . $key);
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getMeasurementEvidenceFinalRules(): array
|
|
{
|
|
return $this->getRequiredStringList('measurement_evidence_guard.final_rules');
|
|
}
|
|
|
|
public function getParameterParsingSplitPattern(): string
|
|
{
|
|
return $this->getRequiredString('parameter_parsing.split_pattern');
|
|
}
|
|
|
|
public function getParameterParsingTrimCharacters(): string
|
|
{
|
|
return $this->getRequiredString('parameter_parsing.trim_characters');
|
|
}
|
|
|
|
/**
|
|
* @return array<int, array<string, mixed>>
|
|
*/
|
|
public function getMeasurementEvidenceParameters(): array
|
|
{
|
|
$value = $this->getRequiredValue('measurement_evidence_guard.parameters');
|
|
|
|
if (!is_array($value)) {
|
|
throw new \InvalidArgumentException('RetrieX prompt config value "measurement_evidence_guard.parameters" must be a list of parameter definitions.');
|
|
}
|
|
|
|
$out = [];
|
|
$genericPositiveContextTerms = $this->getMeasurementEvidenceGenericPositiveContextTerms();
|
|
$genericNegativeContextTerms = $this->getMeasurementEvidenceGenericNegativeContextTerms();
|
|
$requestTermsByParameter = $this->getVocabularyStringListMap('measurement_evidence_guard.vocabulary_maps.request_terms');
|
|
$positiveTermsByParameter = $this->getVocabularyStringListMap('measurement_evidence_guard.vocabulary_maps.positive_terms');
|
|
$nonEquivalentTermsByParameter = $this->getVocabularyStringListMap('measurement_evidence_guard.vocabulary_maps.non_equivalent_terms');
|
|
|
|
foreach ($value as $item) {
|
|
if (!is_array($item)) {
|
|
continue;
|
|
}
|
|
|
|
$id = isset($item['id']) && is_scalar($item['id']) ? trim((string) $item['id']) : '';
|
|
$label = isset($item['label']) && is_scalar($item['label']) ? trim((string) $item['label']) : '';
|
|
|
|
if ($id === '' || $label === '') {
|
|
continue;
|
|
}
|
|
|
|
$out[] = [
|
|
'id' => $id,
|
|
'label' => $label,
|
|
'request_terms' => $this->getParameterStringList($item, $id, 'request_terms', $requestTermsByParameter),
|
|
'positive_terms' => $this->getParameterStringList($item, $id, 'positive_terms', $positiveTermsByParameter),
|
|
'positive_context_terms' => array_key_exists('positive_context_terms', $item)
|
|
? $this->normalizeMixedStringList($item['positive_context_terms'])
|
|
: $genericPositiveContextTerms,
|
|
'negative_context_terms' => array_key_exists('negative_context_terms', $item)
|
|
? $this->normalizeMixedStringList($item['negative_context_terms'])
|
|
: $genericNegativeContextTerms,
|
|
'non_equivalent_terms' => $this->getParameterStringList($item, $id, 'non_equivalent_terms', $nonEquivalentTermsByParameter),
|
|
'safe_no_evidence_answer_de' => isset($item['safe_no_evidence_answer_de']) && is_scalar($item['safe_no_evidence_answer_de'])
|
|
? trim((string) $item['safe_no_evidence_answer_de'])
|
|
: '',
|
|
'safe_no_accessory_evidence_answer_de' => isset($item['safe_no_accessory_evidence_answer_de']) && is_scalar($item['safe_no_accessory_evidence_answer_de'])
|
|
? trim((string) $item['safe_no_accessory_evidence_answer_de'])
|
|
: '',
|
|
];
|
|
}
|
|
|
|
if ($out === []) {
|
|
throw new \InvalidArgumentException('RetrieX prompt config value "measurement_evidence_guard.parameters" must contain at least one valid parameter definition.');
|
|
}
|
|
|
|
return $out;
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
private function normalizeMixedStringList(mixed $value): array
|
|
{
|
|
if (!is_array($value)) {
|
|
return [];
|
|
}
|
|
|
|
$out = [];
|
|
foreach ($value as $item) {
|
|
if (!is_scalar($item)) {
|
|
continue;
|
|
}
|
|
|
|
$item = trim((string) $item);
|
|
if ($item !== '' && !in_array($item, $out, true)) {
|
|
$out[] = $item;
|
|
}
|
|
}
|
|
|
|
return $out;
|
|
}
|
|
|
|
public function getTechnicalProductModelPattern(): string
|
|
{
|
|
return $this->getRequiredString('technical_product_model_pattern');
|
|
}
|
|
} |