<?php
/**
* DO NOT EDIT THIS FILE DIRECTLY.
*
* Copy this file to your /config directory and rename it to dexter.php
* to override the default settings. You can remove any settings you don't want to change,
* and they will fall back to the defaults defined here.
*/
return [
// Choose which provider you're using.
'provider' => 'meilisearch', // or "algolia"
// Then set the required config values for it.
'algolia' => [
'appId' => '',
'apiKey' => '',
'mode' => 'keywordSearch', // or neuralSearch if using the Premium or Elevate plans.
],
'meilisearch' => [
'url' => '',
'appKey' => '',
],
// The endpoint URL for the search API that returns a JSON response, e.g. https://site.com/dexter/search
// Change this if it collides with another URL on your site, or you just want to use a different path.
'endpointUrl' => 'dexter/search',
// A prefix will be added to each index based on the environment. If you're using the .env file, you can
// set this to $_ENV['ENVIRONMENT'] to read from the .env file, or override this in your config/dexter.php file
// with a hard-coded value, or another custom ENV variable. You can also leave it blank to use no prefix.
'env' => 'test',
// Add a suffix to the end of all indices. This will be automatically updated by the dexterUpdateConfig event
// in the events/UpdateConfigEvent.php file unless you disable it unless you set autoUpdateSuffix set to false.
// Can be a string or a callable function. For example:
//'suffix' => function (...$args) {
// if (do something) {
// return '_' . $mySuffix;
// }
//
// return '';
//},
// If true, the site's handle will be appended to the end of the index name. If you want to index multiple sites,
// content into the same index, set this to false.
'appendSiteSuffix' => true,
// Add the group name handle to be used to construct a menu a hierarchical menus, specifically
// designed to render output necessary for Algolia's React HierarchicalMenu component
// https://www.algolia.com/doc/api-reference/widgets/hierarchical-menu/react/
// The category custom field must also be included in the customFields array.
'categoryMenuGroups' => [],
// Any other category groups. Will index with the group name as the object key, and each
// assigned category within the group with its ID and name.
'categoryGroups' => [],
// Similar to categoryGroups where you add the group ID to this config array, but will index
// as a flat list of categories in an array, regardless of the group.
'categories' => [],
// A list of field names to be indexed. If nothing is defined, everything will be indexed.
'indexableFields' => [
//'entries' => [
// 'title',
// 'contentBlocks', // Index contentBlocks and all nested fields.
// 'contentBlocks.*.fields.heading', // Index just the heading field of each content block.
//],
// The above will apply to all entries. If you want different fields for specific types, use the following format:
//'entries[typeHandle]' => [
//],
//'categories' => [
//],
//'categories[groupHandle]' => [
//],
//'files' => [
// 'url',
// 'attribution',
// 'imageCaption',
// 'contentBlocks.*.fields.richText',
//],
//'files[volumeHandle]' => [
//],
//'users' => [
//],
//'users[groupHandle]' => [
//],
],
// Required - only entries within the defined types will be indexed. Files from defined volumes can
// also be indexed. In the example below, the numerical value at the end is the channel ID or upload directory ID.
// Since channel names can change, and upload directories don't have short names, Dexter uses their respective IDs.
// Dexter cannot target specific subdirectories within an upload destination.
'indices' => [
'entries' => [
//'page' => 'pages',
//'productPages' => 'pages',
//'blog' => 'blog',
],
'files' => [
//'digitalOcean' => 'files',
],
'categories' => [
//'callSigns' => 'call_signs',
//'fruits' => 'fruits',
],
'users' => [
],
],
// Adds a __full_text property when indexing entries, which is a conglomeration of all text found in individual
// fields being indexed. Useful for full-text searching and required if you are using the FileDescribePipeline.
'includeFullText' => true,
// Custom pipelines for additional customization.
// Need to be properly namespaced, but can be loaded from anywhere.
'entryPipelines' => [
// MyCustomPipeline::class,
// \BoldMinded\DexterPipelines\Pipelines\ExamplePipeline::class,
],
// Pipelines applied only when indexing categories.
'categoryPipelines' => [
// MyCustomCategoryPipeline::class,
],
// Pipelies applied only when indexing files.
'filePipelines' => [
// MyCustomFilePipeline::class,
// \BoldMinded\Dexter\Service\Pipeline\FileDescribePipeline::class,
],
'userPipelines' => [
// MyCustomMemberPipeline::class,
],
// If indexing files, and a pdf, txt, csv, or other text-based file is uploaded it will try to scrape the contents
// of the file and add it to the __full_text property.
'parseDocumentContents' => [
'enabled' => true,
'describePrompt' => 'Summarize this text.',
'maxPages' => 5, // Limit the number of pages to parse from a text file.
'maxWords' => 1000, // Limit the number of words to parse from a text file.
'categoryGroupHandle' => '',
// If true, the source file description and categories will be created with the AI response.
// If parseDocumentContents.enabled is true, you generally want to keep this enabled as well.
'createAltText' => true,
'createDescription' => true,
'createCategories' => true,
// If true, any updates to the file will fetch a new AI response and update the source file accordingly.
// Leave false if you want to manually manage the description and categories after it is initially created.
'replaceAltText' => false,
'replaceDescription' => false,
'replaceCategories' => false,
// The field handle of a Plain Text field to store the description. Use dot notation for nested fields.
'altTextFieldHandle' => 'alt',
'descriptionFieldHandle' => '',
'categoriesFieldHandle' => '',
],
// If indexing image files (jpg, png, or gif) it will send the image to OpenAI to describe the contents
// of the file and add it to the __full_text property.
'parseImageContents' => [
'enabled' => true,
'describePrompt' => 'Describe this image in detail, including any text that may be present.',
'categoryGroupHandle' => '',
// If true, the source file description and categories will be created with the AI response.
// If parseImageContents.enabled is true, you generally want to keep this enabled as well.
'createAltText' => true,
'createDescription' => true,
'createCategories' => true,
// If true, any updates to the file will fetch a new AI response and update the source file accordingly.
// Leave false if you want to manually manage the description and categories after it is initially created.
'replaceAltText' => false,
'replaceDescription' => false,
'replaceCategories' => false,
// The field handle of a Plain Text field to store the description. Use dot notation for nested fields.
'altTextFieldHandle' => 'alt',
'descriptionFieldHandle' => '',
'categoriesFieldHandle' => '',
],
'aiProvider' => 'openAi',
'embeddingProvider' => 'openAi',
'openAi' => [
'key' => $_ENV['OPENAI_API_KEY'] ?? '',
'embedModel' => 'text-embedding-3-small',
'model' => 'gpt-4o',
'temperature' => 1.0, // The temperature of the response, 0.0 to 2.0.
'frequencyPenalty' => 0.0, // The frequency penalty of the response,
'presencePenalty' => 0.0, // The presence penalty of the response.
'maxTokens' => 300, // The maximum number of tokens to return in the response.
],
// If you are using Meilisearch, you can enable AI/vector-based searching. Using this feature requires
// includeFullText to be enabled. When content is indexed, it will use the __full_text property to generate
// embeddings/vectors for each object. This will allow you to search for similar content based on the text
// in the __full_text property. You must also include the following filter in your search queries:
// "hybrid": {
// "embedder": "fullText"
// }
// https://www.meilisearch.com/docs/learn/ai_powered_search/getting_started_with_ai_search
'enableContextSearch' => false,
// If true, Dexter will use the defined aiProvider to further filter the search results.
// This will not add additional results to the list, it will only perform an additional search filtering
// the initial results based on the query, which can take into account advanced logic such as "NOT" and "OR" operators.
// enableContextSearch must be enabled
'enableAdvancedSearch' => false,
// This is the property name that is used for the index primaryKey. In most cases the default "objectID" is sufficient.
// https://www.meilisearch.com/docs/learn/getting_started/primary_key
// If in the event you want to change the primary key name (you can set it to "entry_id" if you want), you can
// set the config value to a callable function. By default, the values of this field will be "entry_123" or "file_456",
// depending on if your indexing entries or files.
// For example:
/*
'primaryKey' => function (string $indexName, array $values) {
return ''; // do something fancy here
},
*/
'primaryKey' => 'objectID',
// Highly recommended if you are using the endpointUrl to perform searches, either via an Ajax
// or server side curl request. You must pass a valid value along with the search request.
// Add the token in the headers:
// X-CSRF-Token: [your token here]
// An example POST body:
// {
// "index": "test_files",
// "query": "small birds",
// "filters": {
// "limit": 6,
// "hybrid": {
// "embedder": "fullText"
// }
// }
// }
'secureSearch' => true,
// Only entries or files with the following statuses will be indexed
'statuses' => [
'enabled',
'live',
],
// This is a default list of stop words that will be removed from the __full_text property.
// You can use the dexter_remove_stop_words extension hook to modify this list at runtime (ideal for multilingual sites),
// or you can set your own list of stop words in the config.
'stopWords' => [
'a', 'about', 'above', 'after', 'again', 'against', 'all', 'am', 'an', 'and', 'any', 'are',
'as', 'at', 'be', 'because', 'been', 'before', 'being', 'below', 'between', 'both', 'but',
'by', 'could', 'did', 'do', 'does', 'doing', 'down', 'during', 'each', 'few', 'for', 'from',
'further', 'had', 'has', 'have', 'having', 'he', 'her', 'here', 'hers', 'herself', 'him',
'himself', 'his', 'how', 'i', 'if', 'in', 'into', 'is', 'it', 'its', 'itself', 'let\'s',
'me', 'more', 'most', 'my', 'myself', 'nor', 'of', 'on', 'once', 'only', 'or', 'other',
'ought', 'our', 'ours', 'ourselves', 'out', 'over', 'own', 'same', 'she', 'should', 'so',
'some', 'such', 'than', 'that', 'the', 'their', 'theirs', 'them', 'themselves', 'then',
'there', 'these', 'they', 'this', 'those', 'through', 'to', 'too', 'under', 'until', 'up',
'very', 'was', 'we', 'were', 'what', 'when', 'where', 'which', 'while', 'who', 'whom',
'why', 'will', 'with', 'would', 'you', 'your', 'yours', 'yourself', 'yourselves',
],
// Highly recommended to use the queue if you need to batch re-index hundreds or thousands of entries.
'useQueue' => true,
];