diff --git a/.eslintrc.json b/.eslintrc.json index 59ca3019..957f2cf5 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -4,7 +4,15 @@ "es2021": true }, "extends": ["eslint:recommended", "plugin:react/recommended"], - "overrides": [], + "overrides": [ + { + "files": ["src/utils/__tests__/**/*.mjs", "**/*.test.mjs"], + "env": { + "jest": true, + "node": true + } + } + ], "parserOptions": { "ecmaVersion": "latest", "sourceType": "module" diff --git a/coverage/lcov-report/base.css b/coverage/lcov-report/base.css new file mode 100644 index 00000000..f418035b --- /dev/null +++ b/coverage/lcov-report/base.css @@ -0,0 +1,224 @@ +body, html { + margin:0; padding: 0; + height: 100%; +} +body { + font-family: Helvetica Neue, Helvetica, Arial; + font-size: 14px; + color:#333; +} +.small { font-size: 12px; } +*, *:after, *:before { + -webkit-box-sizing:border-box; + -moz-box-sizing:border-box; + box-sizing:border-box; + } +h1 { font-size: 20px; margin: 0;} +h2 { font-size: 14px; } +pre { + font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; + margin: 0; + padding: 0; + -moz-tab-size: 2; + -o-tab-size: 2; + tab-size: 2; +} +a { color:#0074D9; text-decoration:none; } +a:hover { text-decoration:underline; } +.strong { font-weight: bold; } +.space-top1 { padding: 10px 0 0 0; } +.pad2y { padding: 20px 0; } +.pad1y { padding: 10px 0; } +.pad2x { padding: 0 20px; } +.pad2 { padding: 20px; } +.pad1 { padding: 10px; } +.space-left2 { padding-left:55px; } +.space-right2 { padding-right:20px; } +.center { text-align:center; } +.clearfix { display:block; } +.clearfix:after { + content:''; + display:block; + height:0; + clear:both; + visibility:hidden; + } +.fl { float: left; } +@media only screen and (max-width:640px) { + .col3 { width:100%; max-width:100%; } + .hide-mobile { display:none!important; } +} + +.quiet { + color: #7f7f7f; + color: rgba(0,0,0,0.5); +} +.quiet a { opacity: 0.7; } + +.fraction { + font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; + font-size: 10px; + color: #555; + background: #E8E8E8; + padding: 4px 5px; + border-radius: 3px; + vertical-align: middle; +} + +div.path a:link, div.path a:visited { color: #333; } +table.coverage { + border-collapse: collapse; + margin: 10px 0 0 0; + padding: 0; +} + +table.coverage td { + margin: 0; + padding: 0; + vertical-align: top; +} +table.coverage td.line-count { + text-align: right; + padding: 0 5px 0 20px; +} +table.coverage td.line-coverage { + text-align: right; + padding-right: 10px; + min-width:20px; +} + +table.coverage td span.cline-any { + display: inline-block; + padding: 0 5px; + width: 100%; +} +.missing-if-branch { + display: inline-block; + margin-right: 5px; + border-radius: 3px; + position: relative; + padding: 0 4px; + background: #333; + color: yellow; +} + +.skip-if-branch { + display: none; + margin-right: 10px; + position: relative; + padding: 0 4px; + background: #ccc; + color: white; +} +.missing-if-branch .typ, .skip-if-branch .typ { + color: inherit !important; +} +.coverage-summary { + border-collapse: collapse; + width: 100%; +} +.coverage-summary tr { border-bottom: 1px solid #bbb; } +.keyline-all { border: 1px solid #ddd; } +.coverage-summary td, .coverage-summary th { padding: 10px; } +.coverage-summary tbody { border: 1px solid #bbb; } +.coverage-summary td { border-right: 1px solid #bbb; } +.coverage-summary td:last-child { border-right: none; } +.coverage-summary th { + text-align: left; + font-weight: normal; + white-space: nowrap; +} +.coverage-summary th.file { border-right: none !important; } +.coverage-summary th.pct { } +.coverage-summary th.pic, +.coverage-summary th.abs, +.coverage-summary td.pct, +.coverage-summary td.abs { text-align: right; } +.coverage-summary td.file { white-space: nowrap; } +.coverage-summary td.pic { min-width: 120px !important; } +.coverage-summary tfoot td { } + +.coverage-summary .sorter { + height: 10px; + width: 7px; + display: inline-block; + margin-left: 0.5em; + background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; +} +.coverage-summary .sorted .sorter { + background-position: 0 -20px; +} +.coverage-summary .sorted-desc .sorter { + background-position: 0 -10px; +} +.status-line { height: 10px; } +/* yellow */ +.cbranch-no { background: yellow !important; color: #111; } +/* dark red */ +.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } +.low .chart { border:1px solid #C21F39 } +.highlighted, +.highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{ + background: #C21F39 !important; +} +/* medium red */ +.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } +/* light red */ +.low, .cline-no { background:#FCE1E5 } +/* light green */ +.high, .cline-yes { background:rgb(230,245,208) } +/* medium green */ +.cstat-yes { background:rgb(161,215,106) } +/* dark green */ +.status-line.high, .high .cover-fill { background:rgb(77,146,33) } +.high .chart { border:1px solid rgb(77,146,33) } +/* dark yellow (gold) */ +.status-line.medium, .medium .cover-fill { background: #f9cd0b; } +.medium .chart { border:1px solid #f9cd0b; } +/* light yellow */ +.medium { background: #fff4c2; } + +.cstat-skip { background: #ddd; color: #111; } +.fstat-skip { background: #ddd; color: #111 !important; } +.cbranch-skip { background: #ddd !important; color: #111; } + +span.cline-neutral { background: #eaeaea; } + +.coverage-summary td.empty { + opacity: .5; + padding-top: 4px; + padding-bottom: 4px; + line-height: 1; + color: #888; +} + +.cover-fill, .cover-empty { + display:inline-block; + height: 12px; +} +.chart { + line-height: 0; +} +.cover-empty { + background: white; +} +.cover-full { + border-right: none !important; +} +pre.prettyprint { + border: none !important; + padding: 0 !important; + margin: 0 !important; +} +.com { color: #999 !important; } +.ignore-none { color: #999; font-weight: normal; } + +.wrapper { + min-height: 100%; + height: auto !important; + height: 100%; + margin: 0 auto -48px; +} +.footer, .push { + height: 48px; +} diff --git a/coverage/lcov-report/block-navigation.js b/coverage/lcov-report/block-navigation.js new file mode 100644 index 00000000..cc121302 --- /dev/null +++ b/coverage/lcov-report/block-navigation.js @@ -0,0 +1,87 @@ +/* eslint-disable */ +var jumpToCode = (function init() { + // Classes of code we would like to highlight in the file view + var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no']; + + // Elements to highlight in the file listing view + var fileListingElements = ['td.pct.low']; + + // We don't want to select elements that are direct descendants of another match + var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > ` + + // Selecter that finds elements on the page to which we can jump + var selector = + fileListingElements.join(', ') + + ', ' + + notSelector + + missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b` + + // The NodeList of matching elements + var missingCoverageElements = document.querySelectorAll(selector); + + var currentIndex; + + function toggleClass(index) { + missingCoverageElements + .item(currentIndex) + .classList.remove('highlighted'); + missingCoverageElements.item(index).classList.add('highlighted'); + } + + function makeCurrent(index) { + toggleClass(index); + currentIndex = index; + missingCoverageElements.item(index).scrollIntoView({ + behavior: 'smooth', + block: 'center', + inline: 'center' + }); + } + + function goToPrevious() { + var nextIndex = 0; + if (typeof currentIndex !== 'number' || currentIndex === 0) { + nextIndex = missingCoverageElements.length - 1; + } else if (missingCoverageElements.length > 1) { + nextIndex = currentIndex - 1; + } + + makeCurrent(nextIndex); + } + + function goToNext() { + var nextIndex = 0; + + if ( + typeof currentIndex === 'number' && + currentIndex < missingCoverageElements.length - 1 + ) { + nextIndex = currentIndex + 1; + } + + makeCurrent(nextIndex); + } + + return function jump(event) { + if ( + document.getElementById('fileSearch') === document.activeElement && + document.activeElement != null + ) { + // if we're currently focused on the search input, we don't want to navigate + return; + } + + switch (event.which) { + case 78: // n + case 74: // j + goToNext(); + break; + case 66: // b + case 75: // k + case 80: // p + goToPrevious(); + break; + } + }; +})(); +window.addEventListener('keydown', jumpToCode); diff --git a/coverage/lcov-report/ends-with-question-mark.mjs.html b/coverage/lcov-report/ends-with-question-mark.mjs.html new file mode 100644 index 00000000..83c4f618 --- /dev/null +++ b/coverage/lcov-report/ends-with-question-mark.mjs.html @@ -0,0 +1,120 @@ + + + + +
++ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +| 1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 | +22x +6x + +16x +16x + + + + + + + | export function endsWithQuestionMark(question) {
+ if (typeof question !== 'string') {
+ return false;
+ }
+ const trimmedQuestion = question.trim();
+ return (
+ trimmedQuestion.endsWith('?') || // ASCII
+ trimmedQuestion.endsWith('?') || // Chinese/Japanese
+ trimmedQuestion.endsWith('؟') || // Arabic
+ trimmedQuestion.endsWith('⸮') // Reversed/inverted question mark (used in some contexts including Arabic)
+ )
+}
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +| 1 +2 +3 +4 +5 | +5x +2x + + | export function getClientPosition(e) {
+ const rect = e.getBoundingClientRect()
+ return { x: rect.left, y: rect.top }
+}
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +| 1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 | + +14x +6x +6x +9x + + +8x +8x +11x +11x + + + +14x + + | export function getConversationPairs(records, isCompletion) {
+ let pairs
+ if (isCompletion) {
+ pairs = ''
+ for (const record of records) {
+ pairs += 'Human: ' + record.question + '\nAI: ' + record.answer + '\n'
+ }
+ } else {
+ pairs = []
+ for (const record of records) {
+ pairs.push({ role: 'user', content: record['question'] })
+ pairs.push({ role: 'assistant', content: record['answer'] })
+ }
+ }
+
+ return pairs
+}
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +| File | ++ | Statements | ++ | Branches | ++ | Functions | ++ | Lines | ++ |
|---|---|---|---|---|---|---|---|---|---|
| ends-with-question-mark.mjs | +
+
+ |
+ 100% | +4/4 | +100% | +6/6 | +100% | +1/1 | +100% | +4/4 | +
| get-client-position.mjs | +
+
+ |
+ 100% | +2/2 | +100% | +0/0 | +100% | +1/1 | +100% | +2/2 | +
| get-conversation-pairs.mjs | +
+
+ |
+ 100% | +9/9 | +100% | +2/2 | +100% | +1/1 | +100% | +9/9 | +
| is-edge.mjs | +
+
+ |
+ 100% | +3/3 | +100% | +2/2 | +100% | +1/1 | +100% | +3/3 | +
| is-firefox.mjs | +
+
+ |
+ 100% | +1/1 | +100% | +0/0 | +100% | +1/1 | +100% | +1/1 | +
| is-mobile.mjs | +
+
+ |
+ 100% | +9/9 | +100% | +11/11 | +100% | +1/1 | +100% | +9/9 | +
| is-safari.mjs | +
+
+ |
+ 100% | +1/1 | +100% | +0/0 | +100% | +1/1 | +100% | +1/1 | +
| model-name-convert.mjs | +
+
+ |
+ 94.84% | +92/97 | +90.41% | +66/73 | +100% | +25/25 | +96.34% | +79/82 | +
| parse-int-with-clamp.mjs | +
+
+ |
+ 100% | +8/8 | +100% | +6/6 | +100% | +1/1 | +100% | +5/5 | +
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +| 1 +2 +3 +4 +5 +6 +7 | +9x +2x + +7x + + | export function isEdge() {
+ if (navigator.userAgent == null) { // Check for null or undefined
+ return false;
+ }
+ return navigator.userAgent.toLowerCase().includes('edg');
+}
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +| 1 +2 +3 +4 | +8x + + | export function isFirefox() {
+ return navigator.userAgent.toLowerCase().includes('firefox')
+}
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +| 1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 | + + +11x +3x + + +8x +8x + + + + +8x +1x + + + +7x + + +5x + +7x + + | // https://stackoverflow.com/questions/11381673/detecting-a-mobile-browser
+
+export function isMobile() {
+ if (navigator.userAgentData) {
+ return navigator.userAgentData.mobile;
+ }
+
+ let check = false;
+ const a = navigator.userAgent || navigator.vendor || window.opera;
+
+ // Prevent TypeError when userAgent/vendor/opera is null or undefined, or if all are empty strings.
+ // The `substr` method on an empty string is fine, but `test` on an empty string might not be what's intended
+ // if the regex expects some content. However, the primary goal here is to prevent TypeErrors from null/undefined.
+ if (!a) {
+ return false; // check is already false, so just return
+ }
+
+ // eslint-disable-next-line no-useless-escape
+ if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a) ||
+ // eslint-disable-next-line no-useless-escape
+ /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0, 4))) {
+ check = true;
+ }
+ return check;
+}
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +| 1 +2 +3 +4 | +7x + + | export function isSafari() {
+ return navigator.vendor === 'Apple Computer, Inc.'
+}
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +| 1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 | + + +13x +13x +6x +6x +1x +5x + + +7x +7x +5x +5x +5x + + + +5x +1x + + +7x + + + +60x +42x + +18x + + + + +24x +22x + +2x + + + + +10x + +5x + + + + +4x +2x +4x + + + +115x + + + +14x +14x +14x +8x +8x +8x +8x +8x + + + + + + + + + + + + +29x +8x + +21x +12x +9x + + +9x + + + +4x + +8x +5x +3x +1x + +8x +4x + + +12x +3x + +9x +9x +9x + +12x +4x + +8x + + + + +1x + + + +5x + + + + + + +9x + + +9x +3x + + +6x +6x +6x +6x + +6x + + + +27x +27x +112x +91x + + + + +3x + + + + +5x +3x + +5x +4x +4x + + + +14x +11x + + + +11x +8x + + | import { AlwaysCustomGroups, ModelGroups, ModelMode, Models } from '../config/index.mjs'
+
+export function modelNameToDesc(modelName, t, extraCustomModelName = '') {
+ if (!t) t = (x) => x
+ if (modelName in Models) {
+ const desc = t(Models[modelName].desc)
+ if (modelName === 'customModel' && extraCustomModelName)
+ return `${desc} (${extraCustomModelName})`
+ return desc
+ }
+
+ let desc = modelName
+ if (isCustomModelName(modelName)) {
+ const presetPart = modelNameToPresetPart(modelName)
+ const customPart = modelNameToCustomPart(modelName)
+ Iif (presetPart in Models) {
+ if (customPart in ModelMode)
+ desc = `${t(Models[presetPart].desc)} (${t(ModelMode[customPart])})`
+ else desc = `${t(Models[presetPart].desc)} (${customPart})`
+ } else if (presetPart in ModelGroups) {
+ desc = `${t(ModelGroups[presetPart].desc)} (${customPart})`
+ }
+ }
+ return desc
+}
+
+export function modelNameToPresetPart(modelName) {
+ if (isCustomModelName(modelName)) {
+ return modelName.split('-')[0]
+ } else {
+ return modelName
+ }
+}
+
+export function modelNameToCustomPart(modelName) {
+ if (isCustomModelName(modelName)) {
+ return modelName.substring(modelName.indexOf('-') + 1)
+ } else {
+ return modelName
+ }
+}
+
+export function modelNameToValue(modelName) {
+ if (modelName in Models) return Models[modelName].value
+
+ return modelNameToCustomPart(modelName)
+}
+
+export function getModelValue(configOrSession) {
+ let value
+ if (configOrSession.apiMode) value = modelNameToValue(apiModeToModelName(configOrSession.apiMode))
+ else value = modelNameToValue(configOrSession.modelName)
+ return value
+}
+
+export function isCustomModelName(modelName) {
+ return modelName ? modelName.includes('-') : false
+}
+
+export function modelNameToApiMode(modelName) {
+ const presetPart = modelNameToPresetPart(modelName)
+ const found = getModelNameGroup(presetPart)
+ if (found) {
+ const [groupName] = found
+ const isCustom = isCustomModelName(modelName)
+ let customName = ''
+ Eif (isCustom) customName = modelNameToCustomPart(modelName)
+ return {
+ groupName,
+ itemName: presetPart,
+ isCustom,
+ customName,
+ customUrl: '',
+ apiKey: '',
+ active: true,
+ }
+ }
+}
+
+export function apiModeToModelName(apiMode) {
+ if (AlwaysCustomGroups.includes(apiMode.groupName))
+ return apiMode.groupName + '-' + apiMode.customName
+
+ if (apiMode.isCustom) {
+ if (apiMode.itemName === 'custom') return apiMode.groupName + '-' + apiMode.customName
+ return apiMode.itemName + '-' + apiMode.customName
+ }
+
+ return apiMode.itemName
+}
+
+export function getApiModesFromConfig(config, onlyActive) {
+ const stringApiModes = config.customApiModes
+ .map((apiMode) => {
+ if (onlyActive) {
+ if (apiMode.active) return apiModeToModelName(apiMode)
+ } else return apiModeToModelName(apiMode)
+ return false
+ })
+ .filter((apiMode) => apiMode)
+ const originalApiModes = config.activeApiModes
+ .map((modelName) => {
+ // 'customModel' is always active
+ if (stringApiModes.includes(modelName) || modelName === 'customModel') {
+ return
+ }
+ if (modelName === 'azureOpenAi') modelName += '-' + config.azureDeploymentName
+ if (modelName === 'ollama') modelName += '-' + config.ollamaModelName
+ return modelNameToApiMode(modelName)
+ })
+ .filter((apiMode) => apiMode)
+ return [
+ ...originalApiModes,
+ ...config.customApiModes.filter((apiMode) => (onlyActive ? apiMode.active : true)),
+ ]
+}
+
+export function getApiModesStringArrayFromConfig(config, onlyActive) {
+ return getApiModesFromConfig(config, onlyActive).map(apiModeToModelName)
+}
+
+export function isApiModeSelected(apiMode, configOrSession) {
+ return configOrSession.apiMode
+ ? JSON.stringify(configOrSession.apiMode) === JSON.stringify(apiMode)
+ : configOrSession.modelName === apiModeToModelName(apiMode)
+}
+
+// also match custom modelName, e.g. when modelName is bingFree4, configOrSession model is bingFree4-fast, it returns true
+export function isUsingModelName(modelName, configOrSession) {
+ let configOrSessionModelName = configOrSession.apiMode
+ ? apiModeToModelName(configOrSession.apiMode)
+ : configOrSession.modelName
+ if (modelName === configOrSessionModelName) {
+ return true
+ }
+
+ Eif (isCustomModelName(configOrSessionModelName)) {
+ const presetPart = modelNameToPresetPart(configOrSessionModelName)
+ Iif (presetPart in Models) configOrSessionModelName = presetPart
+ else Iif (presetPart in ModelGroups) configOrSessionModelName = ModelGroups[presetPart].value[0]
+ }
+ return configOrSessionModelName === modelName
+}
+
+export function getModelNameGroup(modelName) {
+ const presetPart = modelNameToPresetPart(modelName)
+ return (
+ Object.entries(ModelGroups).find(([k]) => presetPart === k) ||
+ Object.entries(ModelGroups).find(([, g]) => g.value.includes(presetPart))
+ )
+}
+
+export function getApiModeGroup(apiMode) {
+ return getModelNameGroup(apiModeToModelName(apiMode))
+}
+
+export function isInApiModeGroup(apiModeGroup, configOrSession) {
+ let foundGroup
+ if (configOrSession.apiMode) foundGroup = getApiModeGroup(configOrSession.apiMode)
+ else foundGroup = getModelNameGroup(configOrSession.modelName)
+
+ if (!foundGroup) return false
+ const [, { value: groupValue }] = foundGroup
+ return groupValue === apiModeGroup
+}
+
+export function isGPT4(modelName) {
+ if (!modelName) return false;
+ return modelName.toLowerCase().startsWith('gpt-4');
+}
+
+export function isClaude3(modelName) {
+ if (!modelName) return false;
+ return modelName.toLowerCase().startsWith('claude-3');
+}
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +| 1 +2 +3 +4 +5 +6 +7 +8 +9 +10 | +40x + +40x +30x +22x + +40x + + | export function parseIntWithClamp(value, min, max, defaultValue) {
+ value = parseInt(value, 10)
+
+ if (isNaN(value)) value = defaultValue
+ else if (value > max) value = max
+ else if (value < min) value = min
+
+ return value
+}
+ |