| 1613 | 1615 | callback: async (args, query) => { |
| 1614 | 1616 | const clamp = (v) => Number.isNaN(v) ? null : Math.min(1, Math.max(0, v)); |
| 1615 | 1617 | const threshold = clamp(Number(args?.threshold ?? settings.score_threshold)); |
| 1618 | + const validateCount = (v) => Number.isNaN(v) || !Number.isInteger(v) || v < 1 ? null : v; |
| 1619 | + const count = validateCount(Number(args?.count)) ?? settings.chunk_count_db; |
| 1616 | 1620 | const source = String(args?.source ?? ''); |
| 1617 | 1621 | const attachments = source ? getDataBankAttachmentsForSource(source, false) : getDataBankAttachments(false); |
| 1618 | 1622 | const collectionIds = await ingestDataBankAttachments(String(source)); |
| 1619 | 1623 | const queryResults = await queryMultipleCollections(collectionIds, String(query), settings.chunk_count_dbcount, threshold); |
| 1620 | | - |
| 1624 | + |
| 1621 | 1625 | // Map collection IDs to fileGet URLs |
| 1622 | 1626 | const urls = Object |
| 1623 | 1627 | .keys(queryResults) |
| 1624 | 1628 | .map(x => attachments.find(y => getFileCollectionId(y.url) === x)) |
| 1625 | 1629 | .filter(x => x) |
| 1626 | 1630 | .map(x => x.url); |
| 1631 | + |
| 1632 | + // Gets the actual text content of chunks |
| 1633 | + const getChunksText = () => { |
| 1634 | + let textResult = ''; |
| 1635 | + for (const collectionId in queryResults) { |
| 1636 | + const metadata = queryResults[collectionId].metadata?.filter(x => x.text)?.sort((a, b) => a.index - b.index)?.map(x => x.text)?.filter(onlyUnique) || []; |
| 1637 | + textResult += metadata.join('\n') + '\n\n'; |
| 1638 | + } |
| 1639 | + return textResult; |
| 1640 | + }; |
| 1641 | + |
| 1642 | + if (args.return === 'chunks') { |
| 1643 | + return getChunksText(); |
| 1644 | + } |
| 1627 | 1645 | |
| 1628 | | - return JSON.stringify(urls); |
| 1646 | + // @ts-ignore |
| 1647 | + return slashCommandReturnHelper.doReturn(args.return ?? 'object', urls, { objectToStringFunc: list => list.join('\n') }); |
| 1648 | + |
| 1629 | 1649 | }, |
| 1630 | 1650 | aliases: ['databank-search', 'data-bank-search'], |
| 1631 | 1651 | helpString: 'Search the Data Bank for a specific query using vector similarity. Returns a list of file URLs with the most relevant content.', |
| 1632 | 1652 | namedArgumentList: [ |
| 1633 | 1653 | new SlashCommandNamedArgument('threshold', 'Threshold for the similarity score in the [0, 1] range. Uses the global config value if not set.', ARGUMENT_TYPE.NUMBER, false, false, ''), |
| 1654 | + new SlashCommandNamedArgument('count', 'Maximum number of query results to return.', ARGUMENT_TYPE.NUMBER, false, false, ''), |
| 1634 | 1655 | new SlashCommandNamedArgument('source', 'Optional filter for the attachments by source.', ARGUMENT_TYPE.STRING, false, false, '', ['global', 'character', 'chat']), |
| 1656 | + SlashCommandNamedArgument.fromProps({ |
| 1657 | + name: 'return', |
| 1658 | + description: 'How you want the return value to be provided', |
| 1659 | + typeList: [ARGUMENT_TYPE.STRING], |
| 1660 | + defaultValue: 'object', |
| 1661 | + enumList: [ |
| 1662 | + new SlashCommandEnumValue('chunks', 'Return the actual content chunks', enumTypes.enum, '{}'), |
| 1663 | + ...slashCommandReturnHelper.enumList({ allowObject: true }) |
| 1664 | + ], |
| 1665 | + forceEnum: true, |
| 1666 | + }) |
| 1635 | 1667 | ], |
| 1636 | 1668 | unnamedArgumentList: [ |
| 1637 | 1669 | new SlashCommandArgument('Query to search by.', ARGUMENT_TYPE.STRING, true, false), |