Merge branch 'staging' into claude-rework
This commit is contained in:
commit
b5e59c819c
|
@ -55,7 +55,7 @@ openai:
|
|||
# Will send a random user ID to OpenAI completion API
|
||||
randomizeUserId: false
|
||||
# If not empty, will add this as a system message to the start of every caption completion prompt
|
||||
# Example: "Perform the instructions to the best of your ability.\n\n" (for LLaVA)
|
||||
# Example: "Perform the instructions to the best of your ability.\n" (for LLaVA)
|
||||
# Not used in image inlining mode
|
||||
captionSystemPrompt: ""
|
||||
# -- DEEPL TRANSLATION CONFIGURATION --
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
"firstRun": true,
|
||||
"username": "User",
|
||||
"api_server": "http://127.0.0.1:5000/api",
|
||||
"api_server_textgenerationwebui": "http://127.0.0.1:5000/api",
|
||||
"preset_settings": "RecoveredRuins",
|
||||
"user_avatar": "user-default.png",
|
||||
"amount_gen": 250,
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
version="1.0"
|
||||
width="350.95343pt"
|
||||
height="433.92468pt"
|
||||
viewBox="0 0 350.95343 433.92468"
|
||||
preserveAspectRatio="xMidYMid"
|
||||
id="svg3"
|
||||
sodipodi:docname="llamacpp.svg"
|
||||
inkscape:version="1.3 (0e150ed, 2023-07-21)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs3" />
|
||||
<sodipodi:namedview
|
||||
id="namedview3"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="true"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="pt"
|
||||
inkscape:zoom="0.61795062"
|
||||
inkscape:cx="360.87026"
|
||||
inkscape:cy="319.60482"
|
||||
inkscape:window-width="1280"
|
||||
inkscape:window-height="688"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="25"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg3" />
|
||||
<path
|
||||
id="path15"
|
||||
d="M 115.66411,7.7769089e-4 C 108.03646,-0.04647231 97.66356,2.0614588 89.22605,5.7471588 51.629188,22.170371 29.279858,72.255744 26.302778,146.75404 l -1.08171,27.05939 10.19027,-9.11895 c 16.68028,-14.92501 43.7359,-30.80127 65.967952,-38.71307 3.63963,-1.29525 7.39727,-3.00875 8.34819,-3.80665 1.00889,-0.84654 -0.84203,-6.76797 -4.44134,-14.21878 -5.75466,-11.912432 -6.12062,-13.824142 -5.45304,-28.480056 0.68369,-15.00947 1.27807,-16.84384 13.33674,-41.2326 C 128.87131,6.4869918 129.50802,4.3066778 123.92323,1.4548327 122.03009,0.48812169 119.13122,0.02222669 115.66411,7.7769089e-4 Z M 204.3319,24.868452 c -7.90831,-0.07627 -17.36177,1.199451 -23.54292,3.870384 -18.58511,8.030767 -38.06958,36.609918 -47.25132,69.305902 -2.22908,7.937702 -4.5161,15.970742 -5.08401,17.852392 -0.86974,2.88178 -0.32873,3.22525 3.43601,2.17653 2.45813,-0.68477 18.29522,-1.73488 35.1935,-2.33437 16.89826,-0.59952 30.72354,-1.40131 30.72354,-1.78192 0,-0.38061 -1.78758,-5.74168 -3.97051,-11.9117 -6.54342,-18.495036 -4.8829,-25.966506 11.1988,-50.400166 7.46265,-11.33831 13.56896,-21.480943 13.56896,-22.542378 0,-2.73047 -6.36368,-4.158497 -14.27205,-4.234674 z M 168.50212,145.23018 c -45.12449,0.0128 -76.75805,10.98462 -110.460932,38.31236 -22.62195,18.34285 -45.99259,54.10069 -54.3650997,83.1786 -4.94441,17.17201 -4.88874,65.42308 0.0924,79.37804 16.4963297,46.21663 57.3528097,79.08349 107.4639617,86.44794 32.21284,4.73407 74.8601,-2.95259 109.24245,-19.68893 l 7.20925,-3.50917 -4.64502,-17.64293 c -2.55479,-9.70397 -5.46337,-20.62804 -6.46485,-24.27571 l -1.82292,-6.63282 -14.30391,6.30496 c -22.86829,10.08133 -41.37356,13.8047 -63.89044,12.8558 -13.70887,-0.57772 -22.19455,-1.94878 -30.04268,-4.85697 -14.96555,-5.54563 -31.436082,-20.30658 -37.827792,-33.90468 -16.63575,-35.39192 -7.26602,-83.4333 21.984032,-112.712 34.5434,-34.57726 78.91103,-41.04325 127.6377,-18.6022 9.71534,4.47445 18.40283,7.701 19.30836,7.16708 1.84426,-1.08761 26.365,-41.92583 26.365,-43.91001 0,-1.77105 -17.98211,-11.91179 -29.15193,-16.43783 -20.81281,-8.43331 -38.421,-11.4793 -66.32745,-11.47153 z m -4.7277,92.6254 v 17.13902 17.13905 h -17.96261 -17.96264 v 15.33281 15.33588 h 17.96264 17.96261 v 17.13903 17.13599 h 16.06964 16.07283 v -17.13599 -17.13903 h 17.01451 17.0178 V 287.46646 272.13365 H 212.9314 195.91689 V 254.9946 237.85558 h -16.07283 z m 121.00426,0 v 17.13902 17.13905 h -17.95945 -17.96254 v 15.33281 15.33588 h 17.96254 17.95945 v 17.13903 17.13599 h 15.12793 15.12482 v -17.13599 -17.13903 h 17.96254 17.95945 V 287.46646 272.13365 H 332.99397 315.03143 V 254.9946 237.85558 h -15.12482 z" />
|
||||
</svg>
|
After Width: | Height: | Size: 3.7 KiB |
|
@ -5,8 +5,7 @@
|
|||
width="64.000000pt" height="64.000000pt" viewBox="0 0 53.000000 60.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
|
||||
<g transform="translate(0.000000,63.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<g transform="translate(0.000000,63.000000) scale(0.100000,-0.100000)" stroke="none">
|
||||
<path d="M40 320 l0 -240 70 0 70 0 0 95 c0 95 0 95 25 95 23 0 25 -3 25 -50
|
||||
l0 -50 70 0 70 0 0 50 c0 47 2 50 25 50 25 0 25 0 25 -95 l0 -95 70 0 70 0 0
|
||||
240 0 240 -70 0 -70 0 0 -44 0 -45 -47 -3 -48 -3 -3 -47 c-3 -43 -5 -48 -28
|
||||
|
|
Before Width: | Height: | Size: 731 B After Width: | Height: | Size: 716 B |
|
@ -0,0 +1,56 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
version="1.0"
|
||||
width="467.388pt"
|
||||
height="618.89093pt"
|
||||
viewBox="0 0 467.388 618.89093"
|
||||
preserveAspectRatio="xMidYMid"
|
||||
id="svg5"
|
||||
sodipodi:docname="ollama.svg"
|
||||
inkscape:version="1.3 (0e150ed, 2023-07-21)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs5" />
|
||||
<sodipodi:namedview
|
||||
id="namedview5"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="false"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="pt"
|
||||
inkscape:zoom="0.20971564"
|
||||
inkscape:cx="309.9435"
|
||||
inkscape:cy="278.94915"
|
||||
inkscape:window-width="1280"
|
||||
inkscape:window-height="688"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="25"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg5" />
|
||||
<g
|
||||
transform="matrix(0.1,0,0,-0.1,-188.01849,632.89095)"
|
||||
stroke="none"
|
||||
id="g5">
|
||||
<path
|
||||
d="m 2849,6312 c -219,-73 -378,-347 -444,-768 -34,-213 -29,-629 9,-774 l 13,-49 -105,-103 c -143,-140 -201,-210 -265,-320 -85,-145 -143,-312 -167,-477 -20,-135 -8,-404 23,-522 34,-129 78,-237 138,-337 l 50,-83 -50,-117 c -96,-227 -130,-376 -138,-618 -12,-345 48,-589 208,-854 l 21,-35 -35,-57 c -43,-72 -100,-243 -122,-368 -26,-149 -31,-393 -11,-523 10,-59 22,-121 28,-138 l 10,-29 177,2 176,3 -1,40 c 0,22 -11,76 -23,120 -42,149 -26,433 34,610 13,39 51,120 84,179 33,60 63,122 67,138 10,46 -4,109 -34,154 -15,22 -46,69 -69,103 -171,254 -206,664 -88,1017 27,80 77,185 130,274 63,105 56,178 -25,260 -138,138 -221,394 -207,634 21,357 227,680 532,833 130,66 183,77 375,78 96,0 183,4 193,9 10,5 36,45 58,90 121,242 304,391 594,484 72,23 96,26 235,26 148,0 160,-1 250,-32 281,-94 469,-249 577,-478 50,-105 54,-107 215,-99 153,8 244,-6 365,-57 143,-59 293,-181 389,-314 62,-87 130,-236 161,-351 22,-84 26,-119 26,-243 0,-124 -4,-159 -26,-242 -31,-118 -101,-257 -167,-332 -83,-95 -88,-166 -19,-277 128,-206 190,-431 191,-689 1,-277 -53,-446 -217,-684 -36,-52 -51,-114 -41,-164 4,-16 34,-78 67,-138 33,-59 71,-140 84,-178 60,-182 76,-461 34,-611 -12,-44 -23,-98 -23,-120 l -1,-40 176,-3 177,-2 11,31 c 46,134 52,474 11,683 -25,129 -78,281 -121,351 l -31,50 21,35 c 159,261 219,507 208,848 -8,252 -53,444 -155,663 l -40,86 31,49 c 59,94 119,235 150,352 29,112 31,126 31,317 1,224 -9,294 -70,472 -19,55 -34,106 -34,113 0,21 -109,198 -159,257 -26,32 -98,107 -159,167 -61,60 -109,113 -106,118 16,25 35,205 41,368 8,260 -15,478 -72,675 -88,303 -214,474 -393,534 -207,70 -405,-47 -542,-318 -75,-151 -139,-379 -156,-558 l -7,-72 -99,50 c -189,95 -399,149 -578,149 -173,0 -383,-52 -560,-138 -52,-26 -98,-48 -101,-50 -3,-1 -9,28 -13,65 -29,288 -146,595 -282,742 -121,130 -274,179 -415,133 z m 153,-374 c 119,-127 208,-471 208,-804 0,-85 -4,-112 -20,-144 -17,-34 -25,-40 -53,-40 -51,0 -267,-30 -326,-45 -30,-8 -56,-13 -58,-12 -1,2 -7,67 -14,145 -16,215 7,467 62,657 39,133 121,275 159,275 7,0 25,-14 42,-32 z m 2529,1 c 124,-133 208,-558 179,-909 -6,-74 -13,-136 -15,-138 -2,-2 -25,3 -52,11 -39,12 -122,24 -352,50 -7,1 -22,18 -33,37 -18,32 -19,50 -15,200 8,255 53,468 132,635 34,71 93,145 115,145 7,0 25,-14 41,-31 z"
|
||||
id="path1" />
|
||||
<path
|
||||
d="m 4115,3729 c -390,-29 -735,-284 -824,-609 -26,-93 -28,-244 -5,-334 38,-149 171,-324 306,-404 85,-50 204,-99 288,-117 99,-22 453,-32 584,-16 350,41 626,253 700,538 20,78 21,240 1,318 -36,140 -144,303 -266,401 -218,174 -474,247 -784,223 z m 329,-258 c 291,-76 497,-291 500,-521 3,-227 -192,-414 -479,-460 -80,-13 -403,-13 -485,1 -212,34 -390,160 -452,319 -29,77 -29,194 1,272 79,206 278,353 544,404 97,18 269,11 371,-15 z"
|
||||
id="path2" />
|
||||
<path
|
||||
d="m 4038,3151 c -58,-52 -40,-123 47,-177 43,-27 45,-31 40,-64 -19,-120 -19,-127 8,-154 22,-22 35,-26 85,-26 91,0 123,41 103,130 -17,74 -15,83 33,113 56,35 76,66 76,116 0,32 -6,44 -31,65 -39,33 -81,33 -136,1 l -43,-24 -42,24 c -58,33 -100,32 -140,-4 z"
|
||||
id="path3" />
|
||||
<path
|
||||
d="m 2932,3664 c -107,-53 -169,-209 -128,-319 44,-115 194,-177 303,-124 89,43 153,148 153,250 0,171 -171,271 -328,193 z"
|
||||
id="path4" />
|
||||
<path
|
||||
d="m 5320,3675 c -119,-54 -165,-193 -104,-320 27,-58 88,-118 141,-141 68,-29 162,-10 227,47 86,76 97,174 35,297 -45,89 -101,125 -198,129 -44,2 -78,-2 -101,-12 z"
|
||||
id="path5" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 4.5 KiB |
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="176.000000pt" height="176.000000pt" viewBox="0 0 176.000000 176.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
|
||||
<g transform="translate(0.000000,176.000000) scale(0.100000,-0.100000)" stroke="none">
|
||||
<path d="M197 1670 c-16 -19 -32 -58 -43 -107 -19 -87 -16 -222 11 -422 21
|
||||
-162 19 -218 -10 -306 -49 -144 -43 -332 14 -443 54 -106 160 -180 297 -207
|
||||
164 -33 202 -44 270 -77 59 -28 80 -33 144 -33 66 0 84 4 154 38 53 25 110 43
|
||||
170 53 122 21 177 38 241 74 158 90 225 282 180 515 -8 42 -21 90 -30 107 -20
|
||||
41 -19 144 1 284 9 60 17 177 17 259 1 134 -1 156 -21 206 -31 77 -50 93 -104
|
||||
85 -84 -13 -183 -89 -319 -243 l-54 -62 -75 19 c-100 26 -224 26 -321 0 l-74
|
||||
-20 -54 63 c-95 109 -182 186 -244 217 -79 39 -117 39 -150 0z m1121 -897 c2
|
||||
-18 -5 -52 -16 -76 -25 -55 -61 -73 -171 -83 l-84 -7 5 51 c7 74 45 114 138
|
||||
146 8 3 40 4 70 3 54 -2 55 -2 58 -34z m-693 16 c24 -7 55 -27 78 -51 33 -34
|
||||
37 -45 37 -88 0 -57 5 -56 -119 -40 -96 13 -136 48 -141 125 -5 64 -4 65 53
|
||||
65 28 0 70 -5 92 -11z m391 -384 c21 -28 18 -33 -31 -63 -32 -19 -48 -36 -53
|
||||
-57 -6 -23 -14 -30 -32 -30 -18 0 -26 7 -32 32 -6 24 -19 38 -48 53 -31 16
|
||||
-40 26 -40 46 0 34 27 42 134 40 73 -2 91 -6 102 -21z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
|
@ -437,14 +437,15 @@
|
|||
Streaming</span>
|
||||
</label>
|
||||
<div class="toggle-description justifyLeft">
|
||||
<span data-i18n="Display the response bit by bit as it is generated.">Display
|
||||
the response bit by bit as it is generated.</span><br>
|
||||
<span data-i18n="When this is off, responses will be displayed all at once when they are complete.">When
|
||||
this is off, responses will be displayed all at once when they are
|
||||
complete.</span>
|
||||
<span data-i18n="Display the response bit by bit as it is generated.">
|
||||
Display the response bit by bit as it is generated.
|
||||
</span><br>
|
||||
<span data-i18n="When this is off, responses will be displayed all at once when they are complete.">
|
||||
When this is off, responses will be displayed all at once when they are complete.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="range-block" data-source="openai,claude,windowai,openrouter,ai21,scale,makersuite,mistralai">
|
||||
<div class="range-block" data-source="openai,claude,windowai,openrouter,ai21,scale,makersuite,mistralai,custom">
|
||||
<div class="range-block-title" data-i18n="Temperature">
|
||||
Temperature
|
||||
</div>
|
||||
|
@ -457,7 +458,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-newbie-hidden class="range-block" data-source="openai,openrouter,ai21">
|
||||
<div data-newbie-hidden class="range-block" data-source="openai,openrouter,ai21,custom">
|
||||
<div class="range-block-title" data-i18n="Frequency Penalty">
|
||||
Frequency Penalty
|
||||
</div>
|
||||
|
@ -470,7 +471,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-newbie-hidden class="range-block" data-source="openai,openrouter,ai21">
|
||||
<div data-newbie-hidden class="range-block" data-source="openai,openrouter,ai21,custom">
|
||||
<div class="range-block-title" data-i18n="Presence Penalty">
|
||||
Presence Penalty
|
||||
</div>
|
||||
|
@ -509,7 +510,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-newbie-hidden class="range-block" data-source="openai,claude,openrouter,ai21,scale,makersuite,mistralai">
|
||||
<div data-newbie-hidden class="range-block" data-source="openai,claude,openrouter,ai21,scale,makersuite,mistralai,custom">
|
||||
<div class="range-block-title" data-i18n="Top-p">
|
||||
Top P
|
||||
</div>
|
||||
|
@ -577,7 +578,7 @@
|
|||
</div>
|
||||
<div class="toggle-description justifyLeft" data-i18n="Wraps activated World Info entries before inserting into the prompt.">
|
||||
Wraps activated World Info entries before inserting into the prompt. Use
|
||||
<tt>{0}</tt> to mark a place where the content is inserted.
|
||||
<code>{0}</code> to mark a place where the content is inserted.
|
||||
</div>
|
||||
<div class="wide100p">
|
||||
<textarea id="wi_format_textarea" class="text_pole textarea_compact autoSetHeight" rows="3" placeholder="—"></textarea>
|
||||
|
@ -591,7 +592,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="toggle-description justifyLeft" data-i18n="Use scenario to mark a place where the content is inserted.">
|
||||
Use <tt>{{scenario}}</tt> to mark a place where the content is inserted.
|
||||
Use <code>{{scenario}}</code> to mark a place where the content is inserted.
|
||||
</div>
|
||||
<div class="wide100p">
|
||||
<textarea id="scenario_format_textarea" class="text_pole textarea_compact autoSetHeight" rows="3" placeholder="—"></textarea>
|
||||
|
@ -605,7 +606,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="toggle-description justifyLeft" data-i18n="Use personality to mark a place where the content is inserted.">
|
||||
Use <tt>{{personality}}</tt> to mark a place where the content is inserted.
|
||||
Use <code>{{personality}}</code> to mark a place where the content is inserted.
|
||||
</div>
|
||||
<div class="wide100p">
|
||||
<textarea id="personality_format_textarea" class="text_pole textarea_compact autoSetHeight" rows="3" placeholder="—"></textarea>
|
||||
|
@ -729,6 +730,9 @@
|
|||
</div>
|
||||
<div class="wide100p">
|
||||
<input id="openai_reverse_proxy" type="text" class="text_pole" placeholder="https://api.openai.com/v1" maxlength="500" />
|
||||
<small class="reverse_proxy_warning">
|
||||
Doesn't work? Try adding <code>/v1</code> at the end!
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="range-block" data-source="openai,claude">
|
||||
|
@ -745,7 +749,7 @@
|
|||
<div id="openai_proxy_password_show" title="Peek a password" class="menu_button fa-solid fa-eye-slash fa-fw"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-newbie-hidden class="range-block" data-source="openai,openrouter,mistralai">
|
||||
<div data-newbie-hidden class="range-block" data-source="openai,openrouter,mistralai,custom">
|
||||
<div class="range-block-title justifyLeft" data-i18n="Seed">
|
||||
Seed
|
||||
</div>
|
||||
|
@ -1508,7 +1512,7 @@
|
|||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="range-block" data-source="openai,openrouter,makersuite">
|
||||
<div class="range-block" data-source="openai,openrouter,makersuite,custom">
|
||||
<label for="openai_image_inlining" class="checkbox_label flexWrap widthFreeExpand">
|
||||
<input id="openai_image_inlining" type="checkbox" />
|
||||
<span data-i18n="Send inline images">Send inline images</span>
|
||||
|
@ -1762,6 +1766,8 @@
|
|||
<option value="aphrodite">Aphrodite</option>
|
||||
<option value="tabby">TabbyAPI</option>
|
||||
<option value="koboldcpp">KoboldCpp</option>
|
||||
<option value="llamacpp">llama.cpp</option>
|
||||
<option value="ollama">Ollama</option>
|
||||
<option value="togetherai">TogetherAI</option>
|
||||
</select>
|
||||
</div>
|
||||
|
@ -1802,7 +1808,11 @@
|
|||
</div>
|
||||
<div class="flex1">
|
||||
<h4>Mancer Model</h4>
|
||||
<select id="mancer_model"></select>
|
||||
<select id="mancer_model">
|
||||
<option>
|
||||
-- Connect to the API --
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div data-tg-type="ooba" class="flex-container flexFlowColumn">
|
||||
|
@ -1811,7 +1821,7 @@
|
|||
oobabooga/text-generation-webui
|
||||
</a>
|
||||
<span data-i18n="Make sure you run it with">
|
||||
Make sure you run it with <tt>--api</tt> flag
|
||||
Make sure you run it with <code>--api</code> flag
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex1">
|
||||
|
@ -1841,6 +1851,44 @@
|
|||
<input id="aphrodite_api_url_text" class="text_pole wide100p" maxlength="500" value="" autocomplete="off" data-server-history="aphrodite">
|
||||
</div>
|
||||
</div>
|
||||
<div data-tg-type="llamacpp">
|
||||
<div class="flex-container flexFlowColumn">
|
||||
<a href="https://github.com/ggerganov/llama.cpp" target="_blank">
|
||||
ggerganov/llama.cpp (inference server)
|
||||
</a>
|
||||
</div>
|
||||
<div class="flex1">
|
||||
<h4 data-i18n="API url">API URL</h4>
|
||||
<small data-i18n="Example: http://127.0.0.1:8080">Example: http://127.0.0.1:8080</small>
|
||||
<input id="llamacpp_api_url_text" class="text_pole wide100p" maxlength="500" value="" autocomplete="off" data-server-history="llamacpp">
|
||||
</div>
|
||||
</div>
|
||||
<div data-tg-type="ollama">
|
||||
<div class="flex-container flexFlowColumn">
|
||||
<a href="https://github.com/jmorganca/ollama" target="_blank">
|
||||
jmorganca/ollama
|
||||
</a>
|
||||
</div>
|
||||
<div class="flex1">
|
||||
<h4 data-i18n="API url">API URL</h4>
|
||||
<small data-i18n="Example: http://127.0.0.1:11434">Example: http://127.0.0.1:11434</small>
|
||||
<input id="ollama_api_url_text" class="text_pole wide100p" maxlength="500" value="" autocomplete="off" data-server-history="ollama">
|
||||
</div>
|
||||
<div class="flex1">
|
||||
<h4>
|
||||
<span data-i18n="Ollama Model">Ollama Model</h4>
|
||||
</h4>
|
||||
<select id="ollama_model">
|
||||
<option>
|
||||
-- Connect to the API --
|
||||
</option>
|
||||
</select>
|
||||
<div id="ollama_download_model" class="menu_button menu_button_icon">
|
||||
<i class="fa-solid fa-download"></i>
|
||||
<span data-i18n="Download">Download</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-tg-type="tabby">
|
||||
<div class="flex-container flexFlowColumn">
|
||||
<a href="https://github.com/theroyallab/tabbyAPI" target="_blank">
|
||||
|
@ -1878,7 +1926,7 @@
|
|||
<div id="api_button_textgenerationwebui" class="api_button menu_button" type="submit" data-i18n="Connect" data-server-connect="ooba_blocking,aphrodite,tabby,koboldcpp">Connect</div>
|
||||
<div class="api_loading menu_button" data-i18n="Cancel">Cancel</div>
|
||||
</div>
|
||||
<label class="checkbox_label margin-bot-10px" for="legacy_api_textgenerationwebui">
|
||||
<label data-tg-type="ooba,aphrodite" class="checkbox_label margin-bot-10px" for="legacy_api_textgenerationwebui">
|
||||
<input type="checkbox" id="legacy_api_textgenerationwebui" />
|
||||
<span data-i18n="Legacy API (pre-OAI, no streaming)">Legacy API (pre-OAI, no streaming)</span>
|
||||
</label>
|
||||
|
@ -1901,6 +1949,7 @@
|
|||
<option value="ai21">AI21</option>
|
||||
<option value="makersuite">Google MakerSuite</option>
|
||||
<option value="mistralai">MistralAI</option>
|
||||
<option value="custom">Custom (OpenAI-compatible)</option>
|
||||
</select>
|
||||
<form id="openai_form" data-source="openai" action="javascript:void(null);" method="post" enctype="multipart/form-data">
|
||||
<h4><span data-i18n="OpenAI API key">OpenAI API key</span></h4>
|
||||
|
@ -2205,9 +2254,40 @@
|
|||
</select>
|
||||
</div>
|
||||
</form>
|
||||
<form id="custom_form" data-source="custom">
|
||||
<h4 data-i18n="Custom Endpoint (Base URL)">Custom Endpoint (Base URL)</h4>
|
||||
<div class="flex-container">
|
||||
<input id="custom_api_url_text" class="text_pole wide100p" maxlength="500" value="" autocomplete="off" placeholder="Example: http://localhost:1234/v1">
|
||||
</div>
|
||||
<div>
|
||||
<small>
|
||||
Doesn't work? Try adding <code>/v1</code> at the end of the URL!
|
||||
</small>
|
||||
</div>
|
||||
<h4>
|
||||
<span data-i18n="Custom API Key">Custom API Key</span>
|
||||
<small>(Optional)</small>
|
||||
</h4>
|
||||
<div class="flex-container">
|
||||
<input id="api_key_custom" name="api_key_custom" class="text_pole flex1" maxlength="500" value="" type="text" autocomplete="off">
|
||||
<div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_custom"></div>
|
||||
</div>
|
||||
<div data-for="api_key_custom" class="neutral_warning">
|
||||
For privacy reasons, your API key will be hidden after you reload the page.
|
||||
</div>
|
||||
<h4>Enter a Model ID</h4>
|
||||
<div class="flex-container">
|
||||
<input id="custom_model_id" class="text_pole wide100p" maxlength="500" value="" autocomplete="off" placeholder="Example: gpt-3.5-turbo">
|
||||
</div>
|
||||
<h4 data-i18n="Available Models">Available Models</h4>
|
||||
<div class="flex-container">
|
||||
<select id="model_custom_select" class="text_pole"></select>
|
||||
</div>
|
||||
</form>
|
||||
<div class="flex-container flex">
|
||||
<div id="api_button_openai" class="api_button menu_button menu_button_icon" type="submit" data-i18n="Connect">Connect</div>
|
||||
<div class="api_loading menu_button" data-i18n="Cancel">Cancel</div>
|
||||
<div data-source="custom" id="customize_additional_parameters" class="menu_button menu_button_icon">Additional Parameters</div>
|
||||
<div data-source="openrouter" id="openrouter_authorize" class="menu_button menu_button_icon" title="Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai" data-i18n="[title]Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai">Authorize</div>
|
||||
<div id="test_api_button" class="menu_button menu_button_icon" title="Verifies your API connection by sending a short test message. Be aware that you'll be credited for it!" data-i18n="[title]Verifies your API connection by sending a short test message. Be aware that you'll be credited for it!">Test Message</div>
|
||||
</div>
|
||||
|
@ -2324,11 +2404,15 @@
|
|||
<span class="fa-solid fa-circle-question note-link-span"></span>
|
||||
</a>
|
||||
</h4>
|
||||
<div>
|
||||
<label for="instruct_enabled" class="checkbox_label">
|
||||
<div class="flex-container">
|
||||
<label for="instruct_enabled" class="checkbox_label flex1">
|
||||
<input id="instruct_enabled" type="checkbox" />
|
||||
<span data-i18n="Enabled">Enabled</span>
|
||||
</label>
|
||||
<label for="instruct_bind_to_context" class="checkbox_label flex1" title="If enabled, Context templates will be automatically selected based on selected Instruct template name or by preference.">
|
||||
<input id="instruct_bind_to_context" type="checkbox" />
|
||||
<span data-i18n="Bind to Context">Bind to Context</span>
|
||||
</label>
|
||||
</div>
|
||||
<label for="instruct_presets">
|
||||
<span data-i18n="Presets">Presets</span>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
"system_sequence_prefix": "[INST] <<SYS>>\n",
|
||||
"system_sequence_suffix": "\n<</SYS>>\n",
|
||||
"stop_sequence": "",
|
||||
"separator_sequence": "\n",
|
||||
"separator_sequence": " ",
|
||||
"wrap": false,
|
||||
"macro": true,
|
||||
"names": false,
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,765 @@
|
|||
|
||||
function $parcel$defineInteropFlag(a) {
|
||||
Object.defineProperty(a, '__esModule', {value: true, configurable: true});
|
||||
}
|
||||
|
||||
function $parcel$export(e, n, v, s) {
|
||||
Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});
|
||||
}
|
||||
var $009ddb00d3ec72b8$exports = {};
|
||||
|
||||
$parcel$defineInteropFlag($009ddb00d3ec72b8$exports);
|
||||
|
||||
$parcel$export($009ddb00d3ec72b8$exports, "default", () => $009ddb00d3ec72b8$export$2e2bcd8739ae039);
|
||||
class $009ddb00d3ec72b8$export$2e2bcd8739ae039 extends Error {
|
||||
constructor(filename, msg, lineno, column, css){
|
||||
super(filename + ":" + lineno + ":" + column + ": " + msg);
|
||||
this.reason = msg;
|
||||
this.filename = filename;
|
||||
this.line = lineno;
|
||||
this.column = column;
|
||||
this.source = css;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var $0865a9fb4cc365fe$exports = {};
|
||||
|
||||
$parcel$defineInteropFlag($0865a9fb4cc365fe$exports);
|
||||
|
||||
$parcel$export($0865a9fb4cc365fe$exports, "default", () => $0865a9fb4cc365fe$export$2e2bcd8739ae039);
|
||||
/**
|
||||
* Store position information for a node
|
||||
*/ class $0865a9fb4cc365fe$export$2e2bcd8739ae039 {
|
||||
constructor(start, end, source){
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.source = source;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var $b2e137848b48cf4f$exports = {};
|
||||
|
||||
$parcel$export($b2e137848b48cf4f$exports, "CssTypes", () => $b2e137848b48cf4f$export$9be5dd6e61d5d73a);
|
||||
var $b2e137848b48cf4f$export$9be5dd6e61d5d73a;
|
||||
(function(CssTypes) {
|
||||
CssTypes["stylesheet"] = "stylesheet";
|
||||
CssTypes["rule"] = "rule";
|
||||
CssTypes["declaration"] = "declaration";
|
||||
CssTypes["comment"] = "comment";
|
||||
CssTypes["container"] = "container";
|
||||
CssTypes["charset"] = "charset";
|
||||
CssTypes["document"] = "document";
|
||||
CssTypes["customMedia"] = "custom-media";
|
||||
CssTypes["fontFace"] = "font-face";
|
||||
CssTypes["host"] = "host";
|
||||
CssTypes["import"] = "import";
|
||||
CssTypes["keyframes"] = "keyframes";
|
||||
CssTypes["keyframe"] = "keyframe";
|
||||
CssTypes["layer"] = "layer";
|
||||
CssTypes["media"] = "media";
|
||||
CssTypes["namespace"] = "namespace";
|
||||
CssTypes["page"] = "page";
|
||||
CssTypes["supports"] = "supports";
|
||||
})($b2e137848b48cf4f$export$9be5dd6e61d5d73a || ($b2e137848b48cf4f$export$9be5dd6e61d5d73a = {}));
|
||||
|
||||
|
||||
// http://www.w3.org/TR/CSS21/grammar.html
|
||||
// https://github.com/visionmedia/css-parse/pull/49#issuecomment-30088027
|
||||
// New rule => https://www.w3.org/TR/CSS22/syndata.html#comments
|
||||
// [^] is equivalent to [.\n\r]
|
||||
const $d708735ed1303b43$var$commentre = /\/\*[^]*?(?:\*\/|$)/g;
|
||||
const $d708735ed1303b43$export$98e6a39c04603d36 = (css, options)=>{
|
||||
options = options || {};
|
||||
/**
|
||||
* Positional.
|
||||
*/ let lineno = 1;
|
||||
let column = 1;
|
||||
/**
|
||||
* Update lineno and column based on `str`.
|
||||
*/ function updatePosition(str) {
|
||||
const lines = str.match(/\n/g);
|
||||
if (lines) lineno += lines.length;
|
||||
const i = str.lastIndexOf("\n");
|
||||
column = ~i ? str.length - i : column + str.length;
|
||||
}
|
||||
/**
|
||||
* Mark position and patch `node.position`.
|
||||
*/ function position() {
|
||||
const start = {
|
||||
line: lineno,
|
||||
column: column
|
||||
};
|
||||
return function(node) {
|
||||
node.position = new (0, $0865a9fb4cc365fe$export$2e2bcd8739ae039)(start, {
|
||||
line: lineno,
|
||||
column: column
|
||||
}, options?.source || "");
|
||||
whitespace();
|
||||
return node;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Error `msg`.
|
||||
*/ const errorsList = [];
|
||||
function error(msg) {
|
||||
const err = new (0, $009ddb00d3ec72b8$export$2e2bcd8739ae039)(options?.source || "", msg, lineno, column, css);
|
||||
if (options?.silent) errorsList.push(err);
|
||||
else throw err;
|
||||
}
|
||||
/**
|
||||
* Parse stylesheet.
|
||||
*/ function stylesheet() {
|
||||
const rulesList = rules();
|
||||
const result = {
|
||||
type: (0, $b2e137848b48cf4f$export$9be5dd6e61d5d73a).stylesheet,
|
||||
stylesheet: {
|
||||
source: options?.source,
|
||||
rules: rulesList,
|
||||
parsingErrors: errorsList
|
||||
}
|
||||
};
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Opening brace.
|
||||
*/ function open() {
|
||||
return match(/^{\s*/);
|
||||
}
|
||||
/**
|
||||
* Closing brace.
|
||||
*/ function close() {
|
||||
return match(/^}/);
|
||||
}
|
||||
/**
|
||||
* Parse ruleset.
|
||||
*/ function rules() {
|
||||
let node;
|
||||
const rules = [];
|
||||
whitespace();
|
||||
comments(rules);
|
||||
while(css.length && css.charAt(0) !== "}" && (node = atrule() || rule()))if (node) {
|
||||
rules.push(node);
|
||||
comments(rules);
|
||||
}
|
||||
return rules;
|
||||
}
|
||||
/**
|
||||
* Match `re` and return captures.
|
||||
*/ function match(re) {
|
||||
const m = re.exec(css);
|
||||
if (!m) return;
|
||||
const str = m[0];
|
||||
updatePosition(str);
|
||||
css = css.slice(str.length);
|
||||
return m;
|
||||
}
|
||||
/**
|
||||
* Parse whitespace.
|
||||
*/ function whitespace() {
|
||||
match(/^\s*/);
|
||||
}
|
||||
/**
|
||||
* Parse comments;
|
||||
*/ function comments(rules) {
|
||||
let c;
|
||||
rules = rules || [];
|
||||
while(c = comment())if (c) rules.push(c);
|
||||
return rules;
|
||||
}
|
||||
/**
|
||||
* Parse comment.
|
||||
*/ function comment() {
|
||||
const pos = position();
|
||||
if ("/" !== css.charAt(0) || "*" !== css.charAt(1)) return;
|
||||
const m = match(/^\/\*[^]*?\*\//);
|
||||
if (!m) return error("End of comment missing");
|
||||
return pos({
|
||||
type: (0, $b2e137848b48cf4f$export$9be5dd6e61d5d73a).comment,
|
||||
comment: m[0].slice(2, -2)
|
||||
});
|
||||
}
|
||||
function findClosingParenthese(str, start, depth) {
|
||||
let ptr = start + 1;
|
||||
let found = false;
|
||||
let closeParentheses = str.indexOf(")", ptr);
|
||||
while(!found && closeParentheses !== -1){
|
||||
const nextParentheses = str.indexOf("(", ptr);
|
||||
if (nextParentheses !== -1 && nextParentheses < closeParentheses) {
|
||||
const nextSearch = findClosingParenthese(str, nextParentheses + 1, depth + 1);
|
||||
ptr = nextSearch + 1;
|
||||
closeParentheses = str.indexOf(")", ptr);
|
||||
} else found = true;
|
||||
}
|
||||
if (found && closeParentheses !== -1) return closeParentheses;
|
||||
else return -1;
|
||||
}
|
||||
/**
|
||||
* Parse selector.
|
||||
*/ function selector() {
|
||||
const m = match(/^([^{]+)/);
|
||||
if (!m) return;
|
||||
// remove comment in selector;
|
||||
let res = $d708735ed1303b43$var$trim(m[0]).replace($d708735ed1303b43$var$commentre, "");
|
||||
// Optimisation: If there is no ',' no need to split or post-process (this is less costly)
|
||||
if (res.indexOf(",") === -1) return [
|
||||
res
|
||||
];
|
||||
// Replace all the , in the parentheses by \u200C
|
||||
let ptr = 0;
|
||||
let startParentheses = res.indexOf("(", ptr);
|
||||
while(startParentheses !== -1){
|
||||
const closeParentheses = findClosingParenthese(res, startParentheses, 0);
|
||||
if (closeParentheses === -1) break;
|
||||
ptr = closeParentheses + 1;
|
||||
res = res.substring(0, startParentheses) + res.substring(startParentheses, closeParentheses).replace(/,/g, "\u200C") + res.substring(closeParentheses);
|
||||
startParentheses = res.indexOf("(", ptr);
|
||||
}
|
||||
// Replace all the , in ' and " by \u200C
|
||||
res = res/**
|
||||
* replace ',' by \u200C for data selector (div[data-lang="fr,de,us"])
|
||||
*
|
||||
* Examples:
|
||||
* div[data-lang="fr,\"de,us"]
|
||||
* div[data-lang='fr,\'de,us']
|
||||
*
|
||||
* Regex logic:
|
||||
* ("|')(?:\\\1|.)*?\1 => Handle the " and '
|
||||
*
|
||||
* Optimization 1:
|
||||
* No greedy capture (see docs about the difference between .* and .*?)
|
||||
*
|
||||
* Optimization 2:
|
||||
* ("|')(?:\\\1|.)*?\1 this use reference to capture group, it work faster.
|
||||
*/ .replace(/("|')(?:\\\1|.)*?\1/g, (m)=>m.replace(/,/g, "\u200C"));
|
||||
// Split all the left , and replace all the \u200C by ,
|
||||
return res// Split the selector by ','
|
||||
.split(",")// Replace back \u200C by ','
|
||||
.map((s)=>{
|
||||
return $d708735ed1303b43$var$trim(s.replace(/\u200C/g, ","));
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Parse declaration.
|
||||
*/ function declaration() {
|
||||
const pos = position();
|
||||
// prop
|
||||
const propMatch = match(/^(\*?[-#/*\\\w]+(\[[0-9a-z_-]+\])?)\s*/);
|
||||
if (!propMatch) return;
|
||||
const propValue = $d708735ed1303b43$var$trim(propMatch[0]);
|
||||
// :
|
||||
if (!match(/^:\s*/)) return error("property missing ':'");
|
||||
// val
|
||||
const val = match(/^((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^)]*?\)|[^};])+)/);
|
||||
const ret = pos({
|
||||
type: (0, $b2e137848b48cf4f$export$9be5dd6e61d5d73a).declaration,
|
||||
property: propValue.replace($d708735ed1303b43$var$commentre, ""),
|
||||
value: val ? $d708735ed1303b43$var$trim(val[0]).replace($d708735ed1303b43$var$commentre, "") : ""
|
||||
});
|
||||
// ;
|
||||
match(/^[;\s]*/);
|
||||
return ret;
|
||||
}
|
||||
/**
|
||||
* Parse declarations.
|
||||
*/ function declarations() {
|
||||
const decls = [];
|
||||
if (!open()) return error("missing '{'");
|
||||
comments(decls);
|
||||
// declarations
|
||||
let decl;
|
||||
while(decl = declaration())if (decl) {
|
||||
decls.push(decl);
|
||||
comments(decls);
|
||||
}
|
||||
if (!close()) return error("missing '}'");
|
||||
return decls;
|
||||
}
|
||||
/**
|
||||
* Parse keyframe.
|
||||
*/ function keyframe() {
|
||||
let m;
|
||||
const vals = [];
|
||||
const pos = position();
|
||||
while(m = match(/^((\d+\.\d+|\.\d+|\d+)%?|[a-z]+)\s*/)){
|
||||
vals.push(m[1]);
|
||||
match(/^,\s*/);
|
||||
}
|
||||
if (!vals.length) return;
|
||||
return pos({
|
||||
type: (0, $b2e137848b48cf4f$export$9be5dd6e61d5d73a).keyframe,
|
||||
values: vals,
|
||||
declarations: declarations() || []
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Parse keyframes.
|
||||
*/ function atkeyframes() {
|
||||
const pos = position();
|
||||
const m1 = match(/^@([-\w]+)?keyframes\s*/);
|
||||
if (!m1) return;
|
||||
const vendor = m1[1];
|
||||
// identifier
|
||||
const m2 = match(/^([-\w]+)\s*/);
|
||||
if (!m2) return error("@keyframes missing name");
|
||||
const name = m2[1];
|
||||
if (!open()) return error("@keyframes missing '{'");
|
||||
let frame;
|
||||
let frames = comments();
|
||||
while(frame = keyframe()){
|
||||
frames.push(frame);
|
||||
frames = frames.concat(comments());
|
||||
}
|
||||
if (!close()) return error("@keyframes missing '}'");
|
||||
return pos({
|
||||
type: (0, $b2e137848b48cf4f$export$9be5dd6e61d5d73a).keyframes,
|
||||
name: name,
|
||||
vendor: vendor,
|
||||
keyframes: frames
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Parse supports.
|
||||
*/ function atsupports() {
|
||||
const pos = position();
|
||||
const m = match(/^@supports *([^{]+)/);
|
||||
if (!m) return;
|
||||
const supports = $d708735ed1303b43$var$trim(m[1]);
|
||||
if (!open()) return error("@supports missing '{'");
|
||||
const style = comments().concat(rules());
|
||||
if (!close()) return error("@supports missing '}'");
|
||||
return pos({
|
||||
type: (0, $b2e137848b48cf4f$export$9be5dd6e61d5d73a).supports,
|
||||
supports: supports,
|
||||
rules: style
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Parse host.
|
||||
*/ function athost() {
|
||||
const pos = position();
|
||||
const m = match(/^@host\s*/);
|
||||
if (!m) return;
|
||||
if (!open()) return error("@host missing '{'");
|
||||
const style = comments().concat(rules());
|
||||
if (!close()) return error("@host missing '}'");
|
||||
return pos({
|
||||
type: (0, $b2e137848b48cf4f$export$9be5dd6e61d5d73a).host,
|
||||
rules: style
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Parse container.
|
||||
*/ function atcontainer() {
|
||||
const pos = position();
|
||||
const m = match(/^@container *([^{]+)/);
|
||||
if (!m) return;
|
||||
const container = $d708735ed1303b43$var$trim(m[1]);
|
||||
if (!open()) return error("@container missing '{'");
|
||||
const style = comments().concat(rules());
|
||||
if (!close()) return error("@container missing '}'");
|
||||
return pos({
|
||||
type: (0, $b2e137848b48cf4f$export$9be5dd6e61d5d73a).container,
|
||||
container: container,
|
||||
rules: style
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Parse container.
|
||||
*/ function atlayer() {
|
||||
const pos = position();
|
||||
const m = match(/^@layer *([^{;@]+)/);
|
||||
if (!m) return;
|
||||
const layer = $d708735ed1303b43$var$trim(m[1]);
|
||||
if (!open()) {
|
||||
match(/^[;\s]*/);
|
||||
return pos({
|
||||
type: (0, $b2e137848b48cf4f$export$9be5dd6e61d5d73a).layer,
|
||||
layer: layer
|
||||
});
|
||||
}
|
||||
const style = comments().concat(rules());
|
||||
if (!close()) return error("@layer missing '}'");
|
||||
return pos({
|
||||
type: (0, $b2e137848b48cf4f$export$9be5dd6e61d5d73a).layer,
|
||||
layer: layer,
|
||||
rules: style
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Parse media.
|
||||
*/ function atmedia() {
|
||||
const pos = position();
|
||||
const m = match(/^@media *([^{]+)/);
|
||||
if (!m) return;
|
||||
const media = $d708735ed1303b43$var$trim(m[1]);
|
||||
if (!open()) return error("@media missing '{'");
|
||||
const style = comments().concat(rules());
|
||||
if (!close()) return error("@media missing '}'");
|
||||
return pos({
|
||||
type: (0, $b2e137848b48cf4f$export$9be5dd6e61d5d73a).media,
|
||||
media: media,
|
||||
rules: style
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Parse custom-media.
|
||||
*/ function atcustommedia() {
|
||||
const pos = position();
|
||||
const m = match(/^@custom-media\s+(--\S+)\s*([^{;\s][^{;]*);/);
|
||||
if (!m) return;
|
||||
return pos({
|
||||
type: (0, $b2e137848b48cf4f$export$9be5dd6e61d5d73a).customMedia,
|
||||
name: $d708735ed1303b43$var$trim(m[1]),
|
||||
media: $d708735ed1303b43$var$trim(m[2])
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Parse paged media.
|
||||
*/ function atpage() {
|
||||
const pos = position();
|
||||
const m = match(/^@page */);
|
||||
if (!m) return;
|
||||
const sel = selector() || [];
|
||||
if (!open()) return error("@page missing '{'");
|
||||
let decls = comments();
|
||||
// declarations
|
||||
let decl;
|
||||
while(decl = declaration()){
|
||||
decls.push(decl);
|
||||
decls = decls.concat(comments());
|
||||
}
|
||||
if (!close()) return error("@page missing '}'");
|
||||
return pos({
|
||||
type: (0, $b2e137848b48cf4f$export$9be5dd6e61d5d73a).page,
|
||||
selectors: sel,
|
||||
declarations: decls
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Parse document.
|
||||
*/ function atdocument() {
|
||||
const pos = position();
|
||||
const m = match(/^@([-\w]+)?document *([^{]+)/);
|
||||
if (!m) return;
|
||||
const vendor = $d708735ed1303b43$var$trim(m[1]);
|
||||
const doc = $d708735ed1303b43$var$trim(m[2]);
|
||||
if (!open()) return error("@document missing '{'");
|
||||
const style = comments().concat(rules());
|
||||
if (!close()) return error("@document missing '}'");
|
||||
return pos({
|
||||
type: (0, $b2e137848b48cf4f$export$9be5dd6e61d5d73a).document,
|
||||
document: doc,
|
||||
vendor: vendor,
|
||||
rules: style
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Parse font-face.
|
||||
*/ function atfontface() {
|
||||
const pos = position();
|
||||
const m = match(/^@font-face\s*/);
|
||||
if (!m) return;
|
||||
if (!open()) return error("@font-face missing '{'");
|
||||
let decls = comments();
|
||||
// declarations
|
||||
let decl;
|
||||
while(decl = declaration()){
|
||||
decls.push(decl);
|
||||
decls = decls.concat(comments());
|
||||
}
|
||||
if (!close()) return error("@font-face missing '}'");
|
||||
return pos({
|
||||
type: (0, $b2e137848b48cf4f$export$9be5dd6e61d5d73a).fontFace,
|
||||
declarations: decls
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Parse import
|
||||
*/ const atimport = _compileAtrule("import");
|
||||
/**
|
||||
* Parse charset
|
||||
*/ const atcharset = _compileAtrule("charset");
|
||||
/**
|
||||
* Parse namespace
|
||||
*/ const atnamespace = _compileAtrule("namespace");
|
||||
/**
|
||||
* Parse non-block at-rules
|
||||
*/ function _compileAtrule(name) {
|
||||
const re = new RegExp("^@" + name + "\\s*((?::?[^;'\"]|\"(?:\\\\\"|[^\"])*?\"|'(?:\\\\'|[^'])*?')+)(?:;|$)");
|
||||
// ^@import\s*([^;"']|("|')(?:\\\2|.)*?\2)+(;|$)
|
||||
return function() {
|
||||
const pos = position();
|
||||
const m = match(re);
|
||||
if (!m) return;
|
||||
const ret = {
|
||||
type: name
|
||||
};
|
||||
ret[name] = m[1].trim();
|
||||
return pos(ret);
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Parse at rule.
|
||||
*/ function atrule() {
|
||||
if (css[0] !== "@") return;
|
||||
return atkeyframes() || atmedia() || atcustommedia() || atsupports() || atimport() || atcharset() || atnamespace() || atdocument() || atpage() || athost() || atfontface() || atcontainer() || atlayer();
|
||||
}
|
||||
/**
|
||||
* Parse rule.
|
||||
*/ function rule() {
|
||||
const pos = position();
|
||||
const sel = selector();
|
||||
if (!sel) return error("selector missing");
|
||||
comments();
|
||||
return pos({
|
||||
type: (0, $b2e137848b48cf4f$export$9be5dd6e61d5d73a).rule,
|
||||
selectors: sel,
|
||||
declarations: declarations() || []
|
||||
});
|
||||
}
|
||||
return $d708735ed1303b43$var$addParent(stylesheet());
|
||||
};
|
||||
/**
|
||||
* Trim `str`.
|
||||
*/ function $d708735ed1303b43$var$trim(str) {
|
||||
return str ? str.trim() : "";
|
||||
}
|
||||
/**
|
||||
* Adds non-enumerable parent node reference to each node.
|
||||
*/ function $d708735ed1303b43$var$addParent(obj, parent) {
|
||||
const isNode = obj && typeof obj.type === "string";
|
||||
const childParent = isNode ? obj : parent;
|
||||
for(const k in obj){
|
||||
const value = obj[k];
|
||||
if (Array.isArray(value)) value.forEach((v)=>{
|
||||
$d708735ed1303b43$var$addParent(v, childParent);
|
||||
});
|
||||
else if (value && typeof value === "object") $d708735ed1303b43$var$addParent(value, childParent);
|
||||
}
|
||||
if (isNode) Object.defineProperty(obj, "parent", {
|
||||
configurable: true,
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
value: parent || null
|
||||
});
|
||||
return obj;
|
||||
}
|
||||
var $d708735ed1303b43$export$2e2bcd8739ae039 = $d708735ed1303b43$export$98e6a39c04603d36;
|
||||
|
||||
|
||||
|
||||
class $de9540138ed1fd01$var$Compiler {
|
||||
constructor(options){
|
||||
this.level = 0;
|
||||
this.indentation = " ";
|
||||
this.compress = false;
|
||||
if (typeof options?.indent === "string") this.indentation = options?.indent;
|
||||
if (options?.compress) this.compress = true;
|
||||
}
|
||||
// We disable no-unused-vars for _position. We keep position for potential reintroduction of source-map
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
emit(str, _position) {
|
||||
return str;
|
||||
}
|
||||
/**
|
||||
* Increase, decrease or return current indentation.
|
||||
*/ indent(level) {
|
||||
this.level = this.level || 1;
|
||||
if (level) {
|
||||
this.level += level;
|
||||
return "";
|
||||
}
|
||||
return Array(this.level).join(this.indentation);
|
||||
}
|
||||
visit(node) {
|
||||
switch(node.type){
|
||||
case (0, $b2e137848b48cf4f$export$9be5dd6e61d5d73a).stylesheet:
|
||||
return this.stylesheet(node);
|
||||
case (0, $b2e137848b48cf4f$export$9be5dd6e61d5d73a).rule:
|
||||
return this.rule(node);
|
||||
case (0, $b2e137848b48cf4f$export$9be5dd6e61d5d73a).declaration:
|
||||
return this.declaration(node);
|
||||
case (0, $b2e137848b48cf4f$export$9be5dd6e61d5d73a).comment:
|
||||
return this.comment(node);
|
||||
case (0, $b2e137848b48cf4f$export$9be5dd6e61d5d73a).container:
|
||||
return this.container(node);
|
||||
case (0, $b2e137848b48cf4f$export$9be5dd6e61d5d73a).charset:
|
||||
return this.charset(node);
|
||||
case (0, $b2e137848b48cf4f$export$9be5dd6e61d5d73a).document:
|
||||
return this.document(node);
|
||||
case (0, $b2e137848b48cf4f$export$9be5dd6e61d5d73a).customMedia:
|
||||
return this.customMedia(node);
|
||||
case (0, $b2e137848b48cf4f$export$9be5dd6e61d5d73a).fontFace:
|
||||
return this.fontFace(node);
|
||||
case (0, $b2e137848b48cf4f$export$9be5dd6e61d5d73a).host:
|
||||
return this.host(node);
|
||||
case (0, $b2e137848b48cf4f$export$9be5dd6e61d5d73a).import:
|
||||
return this.import(node);
|
||||
case (0, $b2e137848b48cf4f$export$9be5dd6e61d5d73a).keyframes:
|
||||
return this.keyframes(node);
|
||||
case (0, $b2e137848b48cf4f$export$9be5dd6e61d5d73a).keyframe:
|
||||
return this.keyframe(node);
|
||||
case (0, $b2e137848b48cf4f$export$9be5dd6e61d5d73a).layer:
|
||||
return this.layer(node);
|
||||
case (0, $b2e137848b48cf4f$export$9be5dd6e61d5d73a).media:
|
||||
return this.media(node);
|
||||
case (0, $b2e137848b48cf4f$export$9be5dd6e61d5d73a).namespace:
|
||||
return this.namespace(node);
|
||||
case (0, $b2e137848b48cf4f$export$9be5dd6e61d5d73a).page:
|
||||
return this.page(node);
|
||||
case (0, $b2e137848b48cf4f$export$9be5dd6e61d5d73a).supports:
|
||||
return this.supports(node);
|
||||
}
|
||||
}
|
||||
mapVisit(nodes, delim) {
|
||||
let buf = "";
|
||||
delim = delim || "";
|
||||
for(let i = 0, length = nodes.length; i < length; i++){
|
||||
buf += this.visit(nodes[i]);
|
||||
if (delim && i < length - 1) buf += this.emit(delim);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
compile(node) {
|
||||
if (this.compress) return node.stylesheet.rules.map(this.visit, this).join("");
|
||||
return this.stylesheet(node);
|
||||
}
|
||||
/**
|
||||
* Visit stylesheet node.
|
||||
*/ stylesheet(node) {
|
||||
return this.mapVisit(node.stylesheet.rules, "\n\n");
|
||||
}
|
||||
/**
|
||||
* Visit comment node.
|
||||
*/ comment(node) {
|
||||
if (this.compress) return this.emit("", node.position);
|
||||
return this.emit(this.indent() + "/*" + node.comment + "*/", node.position);
|
||||
}
|
||||
/**
|
||||
* Visit container node.
|
||||
*/ container(node) {
|
||||
if (this.compress) return this.emit("@container " + node.container, node.position) + this.emit("{") + this.mapVisit(node.rules) + this.emit("}");
|
||||
return this.emit(this.indent() + "@container " + node.container, node.position) + this.emit(" {\n" + this.indent(1)) + this.mapVisit(node.rules, "\n\n") + this.emit("\n" + this.indent(-1) + this.indent() + "}");
|
||||
}
|
||||
/**
|
||||
* Visit container node.
|
||||
*/ layer(node) {
|
||||
if (this.compress) return this.emit("@layer " + node.layer, node.position) + (node.rules ? this.emit("{") + this.mapVisit(node.rules) + this.emit("}") : ";");
|
||||
return this.emit(this.indent() + "@layer " + node.layer, node.position) + (node.rules ? this.emit(" {\n" + this.indent(1)) + this.mapVisit(node.rules, "\n\n") + this.emit("\n" + this.indent(-1) + this.indent() + "}") : ";");
|
||||
}
|
||||
/**
|
||||
* Visit import node.
|
||||
*/ import(node) {
|
||||
return this.emit("@import " + node.import + ";", node.position);
|
||||
}
|
||||
/**
|
||||
* Visit media node.
|
||||
*/ media(node) {
|
||||
if (this.compress) return this.emit("@media " + node.media, node.position) + this.emit("{") + this.mapVisit(node.rules) + this.emit("}");
|
||||
return this.emit(this.indent() + "@media " + node.media, node.position) + this.emit(" {\n" + this.indent(1)) + this.mapVisit(node.rules, "\n\n") + this.emit("\n" + this.indent(-1) + this.indent() + "}");
|
||||
}
|
||||
/**
|
||||
* Visit document node.
|
||||
*/ document(node) {
|
||||
const doc = "@" + (node.vendor || "") + "document " + node.document;
|
||||
if (this.compress) return this.emit(doc, node.position) + this.emit("{") + this.mapVisit(node.rules) + this.emit("}");
|
||||
return this.emit(doc, node.position) + this.emit(" {\n" + this.indent(1)) + this.mapVisit(node.rules, "\n\n") + this.emit(this.indent(-1) + "\n}");
|
||||
}
|
||||
/**
|
||||
* Visit charset node.
|
||||
*/ charset(node) {
|
||||
return this.emit("@charset " + node.charset + ";", node.position);
|
||||
}
|
||||
/**
|
||||
* Visit namespace node.
|
||||
*/ namespace(node) {
|
||||
return this.emit("@namespace " + node.namespace + ";", node.position);
|
||||
}
|
||||
/**
|
||||
* Visit supports node.
|
||||
*/ supports(node) {
|
||||
if (this.compress) return this.emit("@supports " + node.supports, node.position) + this.emit("{") + this.mapVisit(node.rules) + this.emit("}");
|
||||
return this.emit(this.indent() + "@supports " + node.supports, node.position) + this.emit(" {\n" + this.indent(1)) + this.mapVisit(node.rules, "\n\n") + this.emit("\n" + this.indent(-1) + this.indent() + "}");
|
||||
}
|
||||
/**
|
||||
* Visit keyframes node.
|
||||
*/ keyframes(node) {
|
||||
if (this.compress) return this.emit("@" + (node.vendor || "") + "keyframes " + node.name, node.position) + this.emit("{") + this.mapVisit(node.keyframes) + this.emit("}");
|
||||
return this.emit("@" + (node.vendor || "") + "keyframes " + node.name, node.position) + this.emit(" {\n" + this.indent(1)) + this.mapVisit(node.keyframes, "\n") + this.emit(this.indent(-1) + "}");
|
||||
}
|
||||
/**
|
||||
* Visit keyframe node.
|
||||
*/ keyframe(node) {
|
||||
const decls = node.declarations;
|
||||
if (this.compress) return this.emit(node.values.join(","), node.position) + this.emit("{") + this.mapVisit(decls) + this.emit("}");
|
||||
return this.emit(this.indent()) + this.emit(node.values.join(", "), node.position) + this.emit(" {\n" + this.indent(1)) + this.mapVisit(decls, "\n") + this.emit(this.indent(-1) + "\n" + this.indent() + "}\n");
|
||||
}
|
||||
/**
|
||||
* Visit page node.
|
||||
*/ page(node) {
|
||||
if (this.compress) {
|
||||
const sel = node.selectors.length ? node.selectors.join(", ") : "";
|
||||
return this.emit("@page " + sel, node.position) + this.emit("{") + this.mapVisit(node.declarations) + this.emit("}");
|
||||
}
|
||||
const sel = node.selectors.length ? node.selectors.join(", ") + " " : "";
|
||||
return this.emit("@page " + sel, node.position) + this.emit("{\n") + this.emit(this.indent(1)) + this.mapVisit(node.declarations, "\n") + this.emit(this.indent(-1)) + this.emit("\n}");
|
||||
}
|
||||
/**
|
||||
* Visit font-face node.
|
||||
*/ fontFace(node) {
|
||||
if (this.compress) return this.emit("@font-face", node.position) + this.emit("{") + this.mapVisit(node.declarations) + this.emit("}");
|
||||
return this.emit("@font-face ", node.position) + this.emit("{\n") + this.emit(this.indent(1)) + this.mapVisit(node.declarations, "\n") + this.emit(this.indent(-1)) + this.emit("\n}");
|
||||
}
|
||||
/**
|
||||
* Visit host node.
|
||||
*/ host(node) {
|
||||
if (this.compress) return this.emit("@host", node.position) + this.emit("{") + this.mapVisit(node.rules) + this.emit("}");
|
||||
return this.emit("@host", node.position) + this.emit(" {\n" + this.indent(1)) + this.mapVisit(node.rules, "\n\n") + this.emit(this.indent(-1) + "\n}");
|
||||
}
|
||||
/**
|
||||
* Visit custom-media node.
|
||||
*/ customMedia(node) {
|
||||
return this.emit("@custom-media " + node.name + " " + node.media + ";", node.position);
|
||||
}
|
||||
/**
|
||||
* Visit rule node.
|
||||
*/ rule(node) {
|
||||
const decls = node.declarations;
|
||||
if (!decls.length) return "";
|
||||
if (this.compress) return this.emit(node.selectors.join(","), node.position) + this.emit("{") + this.mapVisit(decls) + this.emit("}");
|
||||
const indent = this.indent();
|
||||
return this.emit(node.selectors.map((s)=>{
|
||||
return indent + s;
|
||||
}).join(",\n"), node.position) + this.emit(" {\n") + this.emit(this.indent(1)) + this.mapVisit(decls, "\n") + this.emit(this.indent(-1)) + this.emit("\n" + this.indent() + "}");
|
||||
}
|
||||
/**
|
||||
* Visit declaration node.
|
||||
*/ declaration(node) {
|
||||
if (this.compress) return this.emit(node.property + ":" + node.value, node.position) + this.emit(";");
|
||||
return this.emit(this.indent()) + this.emit(node.property + ": " + node.value, node.position) + this.emit(";");
|
||||
}
|
||||
}
|
||||
var $de9540138ed1fd01$export$2e2bcd8739ae039 = $de9540138ed1fd01$var$Compiler;
|
||||
|
||||
|
||||
var $fdf773ab87e20450$export$2e2bcd8739ae039 = (node, options)=>{
|
||||
const compiler = new (0, $de9540138ed1fd01$export$2e2bcd8739ae039)(options || {});
|
||||
return compiler.compile(node);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const $149c1bd638913645$export$98e6a39c04603d36 = (0, $d708735ed1303b43$export$2e2bcd8739ae039);
|
||||
const $149c1bd638913645$export$fac44ee5b035f737 = (0, $fdf773ab87e20450$export$2e2bcd8739ae039);
|
||||
var $149c1bd638913645$export$2e2bcd8739ae039 = {
|
||||
parse: $149c1bd638913645$export$98e6a39c04603d36,
|
||||
stringify: $149c1bd638913645$export$fac44ee5b035f737
|
||||
};
|
||||
|
||||
|
||||
export {$149c1bd638913645$export$98e6a39c04603d36 as parse, $149c1bd638913645$export$fac44ee5b035f737 as stringify, $149c1bd638913645$export$2e2bcd8739ae039 as default, $b2e137848b48cf4f$export$9be5dd6e61d5d73a as CssTypes};
|
||||
//# sourceMappingURL=index.mjs.map
|
|
@ -69,6 +69,27 @@ EventEmitter.prototype.emit = async function (event) {
|
|||
}
|
||||
};
|
||||
|
||||
EventEmitter.prototype.emitAndWait = function (event) {
|
||||
console.debug('Event emitted: ' + event);
|
||||
|
||||
var i, listeners, length, args = [].slice.call(arguments, 1);
|
||||
|
||||
if (typeof this.events[event] === 'object') {
|
||||
listeners = this.events[event].slice();
|
||||
length = listeners.length;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
try {
|
||||
listeners[i].apply(this, args);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
console.trace('Error in event listener');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
EventEmitter.prototype.once = function (event, listener) {
|
||||
this.on(event, function g () {
|
||||
this.removeListener(event, g);
|
||||
|
|
371
public/script.js
371
public/script.js
|
@ -15,14 +15,13 @@ import {
|
|||
loadTextGenSettings,
|
||||
generateTextGenWithStreaming,
|
||||
getTextGenGenerationData,
|
||||
formatTextGenURL,
|
||||
getTextGenUrlSourceId,
|
||||
textgen_types,
|
||||
textgenerationwebui_banned_in_macros,
|
||||
getTextGenServer,
|
||||
validateTextGenUrl,
|
||||
} from './scripts/textgen-settings.js';
|
||||
|
||||
const { MANCER, TOGETHERAI } = textgen_types;
|
||||
const { MANCER, TOGETHERAI, OOBA, APHRODITE, OLLAMA } = textgen_types;
|
||||
|
||||
import {
|
||||
world_info,
|
||||
|
@ -185,12 +184,12 @@ import {
|
|||
} from './scripts/instruct-mode.js';
|
||||
import { applyLocale, initLocales } from './scripts/i18n.js';
|
||||
import { getFriendlyTokenizerName, getTokenCount, getTokenizerModel, initTokenizers, saveTokenCache } from './scripts/tokenizers.js';
|
||||
import { createPersona, initPersonas, selectCurrentPersona, setPersonaDescription } from './scripts/personas.js';
|
||||
import { createPersona, initPersonas, selectCurrentPersona, setPersonaDescription, updatePersonaNameIfExists } from './scripts/personas.js';
|
||||
import { getBackgrounds, initBackgrounds, loadBackgroundSettings, background_settings } from './scripts/backgrounds.js';
|
||||
import { hideLoader, showLoader } from './scripts/loader.js';
|
||||
import { BulkEditOverlay, CharacterContextMenu } from './scripts/BulkEditOverlay.js';
|
||||
import { loadMancerModels, loadTogetherAIModels } from './scripts/textgen-models.js';
|
||||
import { appendFileContent, hasPendingFileAttachment, populateFileAttachment } from './scripts/chats.js';
|
||||
import { loadMancerModels, loadOllamaModels, loadTogetherAIModels } from './scripts/textgen-models.js';
|
||||
import { appendFileContent, hasPendingFileAttachment, populateFileAttachment, decodeStyleTags, encodeStyleTags } from './scripts/chats.js';
|
||||
import { replaceVariableMacros } from './scripts/variables.js';
|
||||
import { initPresetManager } from './scripts/preset-manager.js';
|
||||
|
||||
|
@ -250,7 +249,6 @@ export {
|
|||
name1,
|
||||
name2,
|
||||
is_send_press,
|
||||
api_server_textgenerationwebui,
|
||||
max_context,
|
||||
chat_metadata,
|
||||
streamingProcessor,
|
||||
|
@ -277,6 +275,26 @@ DOMPurify.addHook('afterSanitizeAttributes', function (node) {
|
|||
}
|
||||
});
|
||||
|
||||
DOMPurify.addHook("uponSanitizeAttribute", (_, data, config) => {
|
||||
if (!config['MESSAGE_SANITIZE']) {
|
||||
return;
|
||||
}
|
||||
switch (data.attrName) {
|
||||
case 'class': {
|
||||
if (data.attrValue) {
|
||||
data.attrValue = data.attrValue.split(' ').map((v) => {
|
||||
if (v.startsWith('fa-') || v.startsWith('note-') || v === 'monospace') {
|
||||
return v;
|
||||
}
|
||||
|
||||
return "custom-" + v;
|
||||
}).join(' ');
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// API OBJECT FOR EXTERNAL WIRING
|
||||
window['SillyTavern'] = {};
|
||||
|
||||
|
@ -315,6 +333,7 @@ export const event_types = {
|
|||
FORCE_SET_BACKGROUND: 'force_set_background',
|
||||
CHAT_DELETED: 'chat_deleted',
|
||||
GROUP_CHAT_DELETED: 'group_chat_deleted',
|
||||
GENERATE_BEFORE_COMBINE_PROMPTS: 'generate_before_combine_prompts',
|
||||
};
|
||||
|
||||
export const eventSource = new EventEmitter();
|
||||
|
@ -662,7 +681,6 @@ let chat_file_for_del = '';
|
|||
let online_status = 'no_connection';
|
||||
|
||||
let api_server = '';
|
||||
let api_server_textgenerationwebui = '';
|
||||
|
||||
let is_send_press = false; //Send generation
|
||||
|
||||
|
@ -888,7 +906,8 @@ async function getStatusKobold() {
|
|||
|
||||
if (!endpoint) {
|
||||
console.warn('No endpoint for status check');
|
||||
return;
|
||||
online_status = 'no_connection';
|
||||
return resultCheckStatus();
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -931,11 +950,12 @@ async function getStatusKobold() {
|
|||
async function getStatusTextgen() {
|
||||
const url = '/api/backends/text-completions/status';
|
||||
|
||||
let endpoint = getTextGenServer();
|
||||
const endpoint = getTextGenServer();
|
||||
|
||||
if (!endpoint) {
|
||||
console.warn('No endpoint for status check');
|
||||
return;
|
||||
online_status = 'no_connection';
|
||||
return resultCheckStatus();
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -945,10 +965,7 @@ async function getStatusTextgen() {
|
|||
body: JSON.stringify({
|
||||
api_server: endpoint,
|
||||
api_type: textgen_settings.type,
|
||||
legacy_api:
|
||||
textgen_settings.legacy_api &&
|
||||
textgen_settings.type !== MANCER &&
|
||||
textgen_settings.type !== TOGETHERAI,
|
||||
legacy_api: textgen_settings.legacy_api && (textgen_settings.type === OOBA || textgen_settings.type === APHRODITE),
|
||||
}),
|
||||
signal: abortStatusCheck.signal,
|
||||
});
|
||||
|
@ -956,11 +973,14 @@ async function getStatusTextgen() {
|
|||
const data = await response.json();
|
||||
|
||||
if (textgen_settings.type === MANCER) {
|
||||
online_status = textgen_settings.mancer_model;
|
||||
loadMancerModels(data?.data);
|
||||
online_status = textgen_settings.mancer_model;
|
||||
} else if (textgen_settings.type === TOGETHERAI) {
|
||||
online_status = textgen_settings.togetherai_model;
|
||||
loadTogetherAIModels(data?.data);
|
||||
online_status = textgen_settings.togetherai_model;
|
||||
} else if (textgen_settings.type === OLLAMA) {
|
||||
loadOllamaModels(data?.data);
|
||||
online_status = textgen_settings.ollama_model || 'Connected';
|
||||
} else {
|
||||
online_status = data?.result;
|
||||
}
|
||||
|
@ -1550,7 +1570,11 @@ function messageFormatting(mes, ch_name, isSystem, isUser) {
|
|||
mes = mes.replace(new RegExp(`(^|\n)${ch_name}:`, 'g'), '$1');
|
||||
}
|
||||
|
||||
mes = DOMPurify.sanitize(mes, { FORBID_TAGS: ['style'] });
|
||||
/** @type {any} */
|
||||
const config = { MESSAGE_SANITIZE: true, ADD_TAGS: ['custom-style'] };
|
||||
mes = encodeStyleTags(mes);
|
||||
mes = DOMPurify.sanitize(mes, config);
|
||||
mes = decodeStyleTags(mes);
|
||||
|
||||
return mes;
|
||||
}
|
||||
|
@ -2960,9 +2984,8 @@ async function Generate(type, { automatic_trigger, force_name2, quiet_prompt, qu
|
|||
if (main_api === 'textgenerationwebui' &&
|
||||
textgen_settings.streaming &&
|
||||
textgen_settings.legacy_api &&
|
||||
textgen_settings.type !== MANCER &&
|
||||
textgen_settings.type !== TOGETHERAI) {
|
||||
toastr.error('Streaming is not supported for the Legacy API. Update Ooba and use --extensions openai to enable streaming.', undefined, { timeOut: 10000, preventDuplicates: true });
|
||||
(textgen_settings.type === OOBA || textgen_settings.type === APHRODITE)) {
|
||||
toastr.error('Streaming is not supported for the Legacy API. Update Ooba and use new API to enable streaming.', undefined, { timeOut: 10000, preventDuplicates: true });
|
||||
unblockGeneration();
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
@ -3229,6 +3252,7 @@ async function Generate(type, { automatic_trigger, force_name2, quiet_prompt, qu
|
|||
if (skipWIAN !== true) {
|
||||
console.log('skipWIAN not active, adding WIAN');
|
||||
// Add all depth WI entries to prompt
|
||||
flushWIDepthInjections();
|
||||
if (Array.isArray(worldInfoDepth)) {
|
||||
worldInfoDepth.forEach((e) => {
|
||||
const joinedEntries = e.entries.join('\n');
|
||||
|
@ -3623,30 +3647,57 @@ async function Generate(type, { automatic_trigger, force_name2, quiet_prompt, qu
|
|||
generatedPromptCache = cleanupPromptCache(generatedPromptCache);
|
||||
}
|
||||
|
||||
// Right now, everything is suffixed with a newline
|
||||
mesSendString = finalMesSend.map((e) => `${e.extensionPrompts.join('')}${e.message}`).join('');
|
||||
// Flattens the multiple prompt objects to a string.
|
||||
const combine = () => {
|
||||
// Right now, everything is suffixed with a newline
|
||||
mesSendString = finalMesSend.map((e) => `${e.extensionPrompts.join('')}${e.message}`).join('');
|
||||
|
||||
// add chat preamble
|
||||
mesSendString = addChatsPreamble(mesSendString);
|
||||
// add a custom dingus (if defined)
|
||||
mesSendString = addChatsSeparator(mesSendString);
|
||||
|
||||
// add a custom dingus (if defined)
|
||||
mesSendString = addChatsSeparator(mesSendString);
|
||||
// add chat preamble
|
||||
mesSendString = addChatsPreamble(mesSendString);
|
||||
|
||||
let combinedPrompt =
|
||||
beforeScenarioAnchor +
|
||||
storyString +
|
||||
afterScenarioAnchor +
|
||||
mesExmString +
|
||||
mesSendString +
|
||||
generatedPromptCache;
|
||||
let combinedPrompt = beforeScenarioAnchor +
|
||||
storyString +
|
||||
afterScenarioAnchor +
|
||||
mesExmString +
|
||||
mesSendString +
|
||||
generatedPromptCache;
|
||||
|
||||
combinedPrompt = combinedPrompt.replace(/\r/gm, '');
|
||||
combinedPrompt = combinedPrompt.replace(/\r/gm, '');
|
||||
|
||||
if (power_user.collapse_newlines) {
|
||||
combinedPrompt = collapseNewlines(combinedPrompt);
|
||||
}
|
||||
if (power_user.collapse_newlines) {
|
||||
combinedPrompt = collapseNewlines(combinedPrompt);
|
||||
}
|
||||
|
||||
return combinedPrompt;
|
||||
return combinedPrompt;
|
||||
};
|
||||
|
||||
let data = {
|
||||
api: main_api,
|
||||
combinedPrompt: null,
|
||||
description,
|
||||
personality,
|
||||
persona,
|
||||
scenario,
|
||||
char: name2,
|
||||
user: name1,
|
||||
beforeScenarioAnchor,
|
||||
afterScenarioAnchor,
|
||||
mesExmString,
|
||||
finalMesSend,
|
||||
generatedPromptCache,
|
||||
main: system,
|
||||
jailbreak,
|
||||
naiPreamble: nai_settings.preamble,
|
||||
};
|
||||
|
||||
// Before returning the combined prompt, give available context related information to all subscribers.
|
||||
eventSource.emitAndWait(event_types.GENERATE_BEFORE_COMBINE_PROMPTS, data);
|
||||
|
||||
// If one or multiple subscribers return a value, forfeit the responsibillity of flattening the context.
|
||||
return !data.combinedPrompt ? combine() : data.combinedPrompt;
|
||||
}
|
||||
|
||||
// Get the negative prompt first since it has the unmodified mesSend array
|
||||
|
@ -3888,7 +3939,6 @@ async function Generate(type, { automatic_trigger, force_name2, quiet_prompt, qu
|
|||
({ type, getMessage } = await saveReply('appendFinal', getMessage, false, title, swipes));
|
||||
}
|
||||
}
|
||||
activateSendButtons();
|
||||
|
||||
if (type !== 'quiet') {
|
||||
playMessageSound();
|
||||
|
@ -3945,23 +3995,16 @@ async function Generate(type, { automatic_trigger, force_name2, quiet_prompt, qu
|
|||
}
|
||||
} else {
|
||||
generatedPromptCache = '';
|
||||
activateSendButtons();
|
||||
//console.log('runGenerate calling showSwipeBtns');
|
||||
showSwipeButtons();
|
||||
|
||||
if (data?.response) {
|
||||
toastr.error(data.response, 'API Error');
|
||||
}
|
||||
reject(data.response);
|
||||
}
|
||||
console.debug('/api/chats/save called by /Generate');
|
||||
|
||||
console.debug('/api/chats/save called by /Generate');
|
||||
await saveChatConditional();
|
||||
is_send_press = false;
|
||||
hideStopButton();
|
||||
activateSendButtons();
|
||||
showSwipeButtons();
|
||||
setGenerationProgress(0);
|
||||
unblockGeneration();
|
||||
streamingProcessor = null;
|
||||
|
||||
if (type !== 'quiet') {
|
||||
|
@ -3990,14 +4033,17 @@ async function Generate(type, { automatic_trigger, force_name2, quiet_prompt, qu
|
|||
is_send_press = false;
|
||||
}
|
||||
|
||||
//console.log('generate ending');
|
||||
} //generate ends
|
||||
|
||||
function flushWIDepthInjections() {
|
||||
//prevent custom depth WI entries (which have unique random key names) from duplicating
|
||||
for (let key in extension_prompts) {
|
||||
if (key.includes('customDepthWI')) {
|
||||
for (const key of Object.keys(extension_prompts)) {
|
||||
if (key.startsWith('customDepthWI')) {
|
||||
delete extension_prompts[key];
|
||||
}
|
||||
}
|
||||
//console.log('generate ending');
|
||||
} //generate ends
|
||||
}
|
||||
|
||||
function unblockGeneration() {
|
||||
is_send_press = false;
|
||||
|
@ -4005,6 +4051,7 @@ function unblockGeneration() {
|
|||
showSwipeButtons();
|
||||
setGenerationProgress(0);
|
||||
flushEphemeralStoppingStrings();
|
||||
flushWIDepthInjections();
|
||||
$('#send_textarea').removeAttr('disabled');
|
||||
}
|
||||
|
||||
|
@ -4460,6 +4507,11 @@ function extractTitleFromData(data) {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the message from the response data.
|
||||
* @param {object} data Response data
|
||||
* @returns {string} Extracted message
|
||||
*/
|
||||
function extractMessageFromData(data) {
|
||||
switch (main_api) {
|
||||
case 'kobold':
|
||||
|
@ -4467,7 +4519,7 @@ function extractMessageFromData(data) {
|
|||
case 'koboldhorde':
|
||||
return data.text;
|
||||
case 'textgenerationwebui':
|
||||
return data.choices[0].text;
|
||||
return data.choices?.[0]?.text ?? data.content ?? data.response;
|
||||
case 'novel':
|
||||
return data.output;
|
||||
case 'openai':
|
||||
|
@ -5402,6 +5454,7 @@ function changeMainAPI() {
|
|||
case chat_completion_sources.AI21:
|
||||
case chat_completion_sources.MAKERSUITE:
|
||||
case chat_completion_sources.MISTRALAI:
|
||||
case chat_completion_sources.CUSTOM:
|
||||
default:
|
||||
setupChatCompletionPromptManager(oai_settings);
|
||||
break;
|
||||
|
@ -5734,12 +5787,6 @@ async function getSettings() {
|
|||
|
||||
setWorldInfoSettings(settings.world_info_settings ?? settings, data);
|
||||
|
||||
api_server_textgenerationwebui = settings.api_server_textgenerationwebui;
|
||||
$('#textgenerationwebui_api_url_text').val(api_server_textgenerationwebui);
|
||||
$('#aphrodite_api_url_text').val(api_server_textgenerationwebui);
|
||||
$('#tabby_api_url_text').val(api_server_textgenerationwebui);
|
||||
$('#koboldcpp_api_url_text').val(api_server_textgenerationwebui);
|
||||
|
||||
selected_button = settings.selected_button;
|
||||
|
||||
if (data.enable_extensions) {
|
||||
|
@ -5779,7 +5826,6 @@ async function saveSettings(type) {
|
|||
active_character: active_character,
|
||||
active_group: active_group,
|
||||
api_server: api_server,
|
||||
api_server_textgenerationwebui: api_server_textgenerationwebui,
|
||||
preset_settings: preset_settings,
|
||||
user_avatar: user_avatar,
|
||||
amount_gen: amount_gen,
|
||||
|
@ -7476,95 +7522,110 @@ const swipe_right = () => {
|
|||
}
|
||||
};
|
||||
|
||||
const CONNECT_API_MAP = {
|
||||
'kobold': {
|
||||
button: '#api_button',
|
||||
},
|
||||
'horde': {
|
||||
selected: 'koboldhorde',
|
||||
},
|
||||
'novel': {
|
||||
button: '#api_button_novel',
|
||||
},
|
||||
'ooba': {
|
||||
selected: 'textgenerationwebui',
|
||||
button: '#api_button_textgenerationwebui',
|
||||
type: textgen_types.OOBA,
|
||||
},
|
||||
'tabby': {
|
||||
selected: 'textgenerationwebui',
|
||||
button: '#api_button_textgenerationwebui',
|
||||
type: textgen_types.TABBY,
|
||||
},
|
||||
'llamacpp': {
|
||||
selected: 'textgenerationwebui',
|
||||
button: '#api_button_textgenerationwebui',
|
||||
type: textgen_types.LLAMACPP,
|
||||
},
|
||||
'ollama': {
|
||||
selected: 'textgenerationwebui',
|
||||
button: '#api_button_textgenerationwebui',
|
||||
type: textgen_types.OLLAMA,
|
||||
},
|
||||
'mancer': {
|
||||
selected: 'textgenerationwebui',
|
||||
button: '#api_button_textgenerationwebui',
|
||||
type: textgen_types.MANCER,
|
||||
},
|
||||
'aphrodite': {
|
||||
selected: 'textgenerationwebui',
|
||||
button: '#api_button_textgenerationwebui',
|
||||
type: textgen_types.APHRODITE,
|
||||
},
|
||||
'kcpp': {
|
||||
selected: 'textgenerationwebui',
|
||||
button: '#api_button_textgenerationwebui',
|
||||
type: textgen_types.KOBOLDCPP,
|
||||
},
|
||||
'togetherai': {
|
||||
selected: 'textgenerationwebui',
|
||||
button: '#api_button_textgenerationwebui',
|
||||
type: textgen_types.TOGETHERAI,
|
||||
},
|
||||
'oai': {
|
||||
selected: 'openai',
|
||||
button: '#api_button_openai',
|
||||
source: chat_completion_sources.OPENAI,
|
||||
},
|
||||
'claude': {
|
||||
selected: 'openai',
|
||||
button: '#api_button_openai',
|
||||
source: chat_completion_sources.CLAUDE,
|
||||
},
|
||||
'windowai': {
|
||||
selected: 'openai',
|
||||
button: '#api_button_openai',
|
||||
source: chat_completion_sources.WINDOWAI,
|
||||
},
|
||||
'openrouter': {
|
||||
selected: 'openai',
|
||||
button: '#api_button_openai',
|
||||
source: chat_completion_sources.OPENROUTER,
|
||||
},
|
||||
'scale': {
|
||||
selected: 'openai',
|
||||
button: '#api_button_openai',
|
||||
source: chat_completion_sources.SCALE,
|
||||
},
|
||||
'ai21': {
|
||||
selected: 'openai',
|
||||
button: '#api_button_openai',
|
||||
source: chat_completion_sources.AI21,
|
||||
},
|
||||
'makersuite': {
|
||||
selected: 'openai',
|
||||
button: '#api_button_openai',
|
||||
source: chat_completion_sources.MAKERSUITE,
|
||||
},
|
||||
'mistralai': {
|
||||
selected: 'openai',
|
||||
button: '#api_button_openai',
|
||||
source: chat_completion_sources.MISTRALAI,
|
||||
},
|
||||
'custom': {
|
||||
selected: 'openai',
|
||||
button: '#api_button_openai',
|
||||
source: chat_completion_sources.CUSTOM,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} text API name
|
||||
*/
|
||||
async function connectAPISlash(_, text) {
|
||||
if (!text) return;
|
||||
|
||||
const apiMap = {
|
||||
'kobold': {
|
||||
button: '#api_button',
|
||||
},
|
||||
'horde': {
|
||||
selected: 'koboldhorde',
|
||||
},
|
||||
'novel': {
|
||||
button: '#api_button_novel',
|
||||
},
|
||||
'ooba': {
|
||||
selected: 'textgenerationwebui',
|
||||
button: '#api_button_textgenerationwebui',
|
||||
type: textgen_types.OOBA,
|
||||
},
|
||||
'tabby': {
|
||||
selected: 'textgenerationwebui',
|
||||
button: '#api_button_textgenerationwebui',
|
||||
type: textgen_types.TABBY,
|
||||
},
|
||||
'mancer': {
|
||||
selected: 'textgenerationwebui',
|
||||
button: '#api_button_textgenerationwebui',
|
||||
type: textgen_types.MANCER,
|
||||
},
|
||||
'aphrodite': {
|
||||
selected: 'textgenerationwebui',
|
||||
button: '#api_button_textgenerationwebui',
|
||||
type: textgen_types.APHRODITE,
|
||||
},
|
||||
'kcpp': {
|
||||
selected: 'textgenerationwebui',
|
||||
button: '#api_button_textgenerationwebui',
|
||||
type: textgen_types.KOBOLDCPP,
|
||||
},
|
||||
'togetherai': {
|
||||
selected: 'textgenerationwebui',
|
||||
button: '#api_button_textgenerationwebui',
|
||||
type: textgen_types.TOGETHERAI,
|
||||
},
|
||||
'oai': {
|
||||
selected: 'openai',
|
||||
source: 'openai',
|
||||
button: '#api_button_openai',
|
||||
},
|
||||
'claude': {
|
||||
selected: 'openai',
|
||||
source: 'claude',
|
||||
button: '#api_button_openai',
|
||||
},
|
||||
'windowai': {
|
||||
selected: 'openai',
|
||||
source: 'windowai',
|
||||
button: '#api_button_openai',
|
||||
},
|
||||
'openrouter': {
|
||||
selected: 'openai',
|
||||
source: 'openrouter',
|
||||
button: '#api_button_openai',
|
||||
},
|
||||
'scale': {
|
||||
selected: 'openai',
|
||||
source: 'scale',
|
||||
button: '#api_button_openai',
|
||||
},
|
||||
'ai21': {
|
||||
selected: 'openai',
|
||||
source: 'ai21',
|
||||
button: '#api_button_openai',
|
||||
},
|
||||
'makersuite': {
|
||||
selected: 'openai',
|
||||
source: 'makersuite',
|
||||
button: '#api_button_openai',
|
||||
},
|
||||
'mistralai': {
|
||||
selected: 'openai',
|
||||
source: 'mistralai',
|
||||
button: '#api_button_openai',
|
||||
},
|
||||
};
|
||||
|
||||
const apiConfig = apiMap[text.toLowerCase()];
|
||||
const apiConfig = CONNECT_API_MAP[text.toLowerCase()];
|
||||
if (!apiConfig) {
|
||||
toastr.error(`Error: ${text} is not a valid API`);
|
||||
return;
|
||||
|
@ -7848,7 +7909,7 @@ jQuery(async function () {
|
|||
}
|
||||
|
||||
registerSlashCommand('dupe', DupeChar, [], '– duplicates the currently selected character', true, true);
|
||||
registerSlashCommand('api', connectAPISlash, [], '<span class="monospace">(kobold, horde, novel, ooba, tabby, mancer, aphrodite, kcpp, oai, claude, windowai, openrouter, scale, ai21, makersuite, mistralai, togetherai)</span> – connect to an API', true, true);
|
||||
registerSlashCommand('api', connectAPISlash, [], `<span class="monospace">(${Object.keys(CONNECT_API_MAP).join(', ')})</span> – connect to an API`, true, true);
|
||||
registerSlashCommand('impersonate', doImpersonate, ['imp'], '– calls an impersonation response', true, true);
|
||||
registerSlashCommand('delchat', doDeleteChat, [], '– deletes the current chat', true, true);
|
||||
registerSlashCommand('closechat', doCloseChat, [], '– closes the current chat', true, true);
|
||||
|
@ -8407,19 +8468,7 @@ jQuery(async function () {
|
|||
await writeSecret(SECRET_KEYS.TOGETHERAI, togetherKey);
|
||||
}
|
||||
|
||||
const urlSourceId = getTextGenUrlSourceId();
|
||||
|
||||
if (urlSourceId && $(urlSourceId).val() !== '') {
|
||||
let value = formatTextGenURL(String($(urlSourceId).val()).trim());
|
||||
if (!value) {
|
||||
callPopup('Please enter a valid URL.', 'text');
|
||||
return;
|
||||
}
|
||||
|
||||
$(urlSourceId).val(value);
|
||||
api_server_textgenerationwebui = value;
|
||||
}
|
||||
|
||||
validateTextGenUrl();
|
||||
startStatusLoading();
|
||||
main_api = 'textgenerationwebui';
|
||||
saveSettingsDebounced();
|
||||
|
@ -9107,8 +9156,10 @@ jQuery(async function () {
|
|||
await messageEditDone($(this));
|
||||
});
|
||||
|
||||
$('#your_name_button').click(function () {
|
||||
setUserName($('#your_name').val());
|
||||
$('#your_name_button').click(async function () {
|
||||
const userName = String($('#your_name').val()).trim();
|
||||
setUserName(userName);
|
||||
await updatePersonaNameIfExists(user_avatar, userName);
|
||||
});
|
||||
|
||||
$('#sync_name_button').on('click', async function () {
|
||||
|
|
|
@ -4,7 +4,6 @@ import {
|
|||
online_status,
|
||||
main_api,
|
||||
api_server,
|
||||
api_server_textgenerationwebui,
|
||||
is_send_press,
|
||||
max_context,
|
||||
saveSettingsDebounced,
|
||||
|
@ -35,7 +34,7 @@ import {
|
|||
import { debounce, delay, getStringHash, isValidUrl } from './utils.js';
|
||||
import { chat_completion_sources, oai_settings } from './openai.js';
|
||||
import { getTokenCount } from './tokenizers.js';
|
||||
import { textgen_types, textgenerationwebui_settings as textgen_settings } from './textgen-settings.js';
|
||||
import { textgen_types, textgenerationwebui_settings as textgen_settings, getTextGenServer } from './textgen-settings.js';
|
||||
|
||||
import Bowser from '../lib/bowser.min.js';
|
||||
|
||||
|
@ -387,7 +386,7 @@ function RA_autoconnect(PrevApi) {
|
|||
) {
|
||||
$('#api_button_textgenerationwebui').trigger('click');
|
||||
}
|
||||
else if (api_server_textgenerationwebui && isValidUrl(api_server_textgenerationwebui)) {
|
||||
else if (isValidUrl(getTextGenServer())) {
|
||||
$('#api_button_textgenerationwebui').trigger('click');
|
||||
}
|
||||
break;
|
||||
|
@ -400,6 +399,7 @@ function RA_autoconnect(PrevApi) {
|
|||
|| (secret_state[SECRET_KEYS.AI21] && oai_settings.chat_completion_source == chat_completion_sources.AI21)
|
||||
|| (secret_state[SECRET_KEYS.MAKERSUITE] && oai_settings.chat_completion_source == chat_completion_sources.MAKERSUITE)
|
||||
|| (secret_state[SECRET_KEYS.MISTRALAI] && oai_settings.chat_completion_source == chat_completion_sources.MISTRALAI)
|
||||
|| (isValidUrl(oai_settings.custom_url) && oai_settings.chat_completion_source == chat_completion_sources.CUSTOM)
|
||||
) {
|
||||
$('#api_button_openai').trigger('click');
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// Move chat functions here from script.js (eventually)
|
||||
|
||||
import css from '../lib/css-parser.mjs';
|
||||
import {
|
||||
addCopyToCodeBlocks,
|
||||
appendMediaToMessage,
|
||||
|
@ -360,6 +361,61 @@ export async function appendFileContent(message, messageText) {
|
|||
return messageText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces style tags in the message text with custom tags with encoded content.
|
||||
* @param {string} text
|
||||
* @returns {string} Encoded message text
|
||||
* @copyright https://github.com/kwaroran/risuAI
|
||||
*/
|
||||
export function encodeStyleTags(text) {
|
||||
const styleRegex = /<style>(.+?)<\/style>/gms;
|
||||
return text.replaceAll(styleRegex, (_, match) => {
|
||||
return `<custom-style>${escape(match)}</custom-style>`;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes custom style tags in the message text to prevent DOM pollution.
|
||||
* @param {string} text Message text
|
||||
* @returns {string} Sanitized message text
|
||||
* @copyright https://github.com/kwaroran/risuAI
|
||||
*/
|
||||
export function decodeStyleTags(text) {
|
||||
const styleDecodeRegex = /<custom-style>(.+?)<\/custom-style>/gms;
|
||||
|
||||
return text.replaceAll(styleDecodeRegex, (_, style) => {
|
||||
try {
|
||||
const ast = css.parse(unescape(style));
|
||||
const rules = ast?.stylesheet?.rules;
|
||||
if (rules) {
|
||||
for (const rule of rules) {
|
||||
|
||||
if (rule.type === 'rule') {
|
||||
if (rule.selectors) {
|
||||
for (let i = 0; i < rule.selectors.length; i++) {
|
||||
let selector = rule.selectors[i];
|
||||
if (selector) {
|
||||
let selectors = (selector.split(' ') ?? []).map((v) => {
|
||||
if (v.startsWith('.')) {
|
||||
return '.custom-' + v.substring(1);
|
||||
}
|
||||
return v;
|
||||
}).join(' ');
|
||||
|
||||
rule.selectors[i] = '.mes_text ' + selectors;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return `<style>${css.stringify(ast)}</style>`;
|
||||
} catch (error) {
|
||||
return `CSS ERROR: ${error}`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
jQuery(function () {
|
||||
$(document).on('click', '.mes_hide', async function () {
|
||||
const messageBlock = $(this).closest('.mes');
|
||||
|
|
|
@ -4,6 +4,7 @@ import { callPopup, getRequestHeaders, saveSettingsDebounced, substituteParams }
|
|||
import { getMessageTimeStamp } from '../../RossAscends-mods.js';
|
||||
import { SECRET_KEYS, secret_state } from '../../secrets.js';
|
||||
import { getMultimodalCaption } from '../shared.js';
|
||||
import { textgen_types, textgenerationwebui_settings } from '../../textgen-settings.js';
|
||||
export { MODULE_NAME };
|
||||
|
||||
const MODULE_NAME = 'caption';
|
||||
|
@ -134,7 +135,7 @@ async function doCaptionRequest(base64Img, fileData) {
|
|||
case 'horde':
|
||||
return await captionHorde(base64Img);
|
||||
case 'multimodal':
|
||||
return await captionMultimodal(extension_settings.caption.multimodal_api === 'google' ? base64Img : fileData);
|
||||
return await captionMultimodal(fileData);
|
||||
default:
|
||||
throw new Error('Unknown caption source.');
|
||||
}
|
||||
|
@ -216,7 +217,16 @@ async function captionHorde(base64Img) {
|
|||
* @returns {Promise<{caption: string}>} Generated caption
|
||||
*/
|
||||
async function captionMultimodal(base64Img) {
|
||||
const prompt = extension_settings.caption.prompt || PROMPT_DEFAULT;
|
||||
let prompt = extension_settings.caption.prompt || PROMPT_DEFAULT;
|
||||
|
||||
if (extension_settings.caption.prompt_ask) {
|
||||
const customPrompt = await callPopup('<h3>Enter a comment or question:</h3>', 'input', prompt, { rows: 2 });
|
||||
if (!customPrompt) {
|
||||
throw new Error('User aborted the caption sending.');
|
||||
}
|
||||
prompt = String(customPrompt).trim();
|
||||
}
|
||||
|
||||
const caption = await getMultimodalCaption(base64Img, prompt);
|
||||
return { caption };
|
||||
}
|
||||
|
@ -271,9 +281,12 @@ jQuery(function () {
|
|||
$(sendButton).on('click', () => {
|
||||
const hasCaptionModule =
|
||||
(modules.includes('caption') && extension_settings.caption.source === 'extras') ||
|
||||
(extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'openai' && secret_state[SECRET_KEYS.OPENAI]) ||
|
||||
(extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'openai' && (secret_state[SECRET_KEYS.OPENAI] || extension_settings.caption.allow_reverse_proxy)) ||
|
||||
(extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'openrouter' && secret_state[SECRET_KEYS.OPENROUTER]) ||
|
||||
(extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'google' && secret_state[SECRET_KEYS.MAKERSUITE]) ||
|
||||
(extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'ollama' && textgenerationwebui_settings.server_urls[textgen_types.OLLAMA]) ||
|
||||
(extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'llamacpp' && textgenerationwebui_settings.server_urls[textgen_types.LLAMACPP]) ||
|
||||
(extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'custom') ||
|
||||
extension_settings.caption.source === 'local' ||
|
||||
extension_settings.caption.source === 'horde';
|
||||
|
||||
|
@ -329,7 +342,7 @@ jQuery(function () {
|
|||
<label for="caption_source">Source</label>
|
||||
<select id="caption_source" class="text_pole">
|
||||
<option value="local">Local</option>
|
||||
<option value="multimodal">Multimodal (OpenAI / OpenRouter / Google)</option>
|
||||
<option value="multimodal">Multimodal (OpenAI / llama / Google)</option>
|
||||
<option value="extras">Extras</option>
|
||||
<option value="horde">Horde</option>
|
||||
</select>
|
||||
|
@ -337,9 +350,12 @@ jQuery(function () {
|
|||
<div class="flex1 flex-container flexFlowColumn flexNoGap">
|
||||
<label for="caption_multimodal_api">API</label>
|
||||
<select id="caption_multimodal_api" class="flex1 text_pole">
|
||||
<option value="llamacpp">llama.cpp</option>
|
||||
<option value="ollama">Ollama</option>
|
||||
<option value="openai">OpenAI</option>
|
||||
<option value="openrouter">OpenRouter</option>
|
||||
<option value="google">Google</option>
|
||||
<option value="google">Google MakerSuite</option>
|
||||
<option value="custom">Custom (OpenAI-compatible)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="flex1 flex-container flexFlowColumn flexNoGap">
|
||||
|
@ -349,16 +365,28 @@ jQuery(function () {
|
|||
<option data-type="google" value="gemini-pro-vision">gemini-pro-vision</option>
|
||||
<option data-type="openrouter" value="openai/gpt-4-vision-preview">openai/gpt-4-vision-preview</option>
|
||||
<option data-type="openrouter" value="haotian-liu/llava-13b">haotian-liu/llava-13b</option>
|
||||
<option data-type="ollama" value="ollama_current">[Currently selected]</option>
|
||||
<option data-type="ollama" value="bakllava:latest">bakllava:latest</option>
|
||||
<option data-type="ollama" value="llava:latest">llava:latest</option>
|
||||
<option data-type="llamacpp" value="llamacpp_current">[Currently loaded]</option>
|
||||
<option data-type="custom" value="custom_current">[Currently selected]</option>
|
||||
</select>
|
||||
</div>
|
||||
<label data-type="openai" class="checkbox_label flexBasis100p" for="caption_allow_reverse_proxy" title="Allow using reverse proxy if defined and valid.">
|
||||
<input id="caption_allow_reverse_proxy" type="checkbox" class="checkbox">
|
||||
Allow reverse proxy
|
||||
</label>
|
||||
<div class="flexBasis100p m-b-1">
|
||||
<small><b>Hint:</b> Set your API keys and endpoints in the 'API Connections' tab first.</small>
|
||||
</div>
|
||||
</div>
|
||||
<div id="caption_prompt_block">
|
||||
<label for="caption_prompt">Caption Prompt</label>
|
||||
<textarea id="caption_prompt" class="text_pole" rows="1" placeholder="< Use default >">${PROMPT_DEFAULT}</textarea>
|
||||
<label class="checkbox_label margin-bot-10px" for="caption_prompt_ask" title="Ask for a custom prompt every time an image is captioned.">
|
||||
<input id="caption_prompt_ask" type="checkbox" class="checkbox">
|
||||
Ask every time
|
||||
</label>
|
||||
</div>
|
||||
<label for="caption_template">Message Template <small>(use <code>{{caption}}</code> macro)</small></label>
|
||||
<textarea id="caption_template" class="text_pole" rows="2" placeholder="< Use default >">${TEMPLATE_DEFAULT}</textarea>
|
||||
|
@ -382,6 +410,7 @@ jQuery(function () {
|
|||
|
||||
$('#caption_refine_mode').prop('checked', !!(extension_settings.caption.refine_mode));
|
||||
$('#caption_allow_reverse_proxy').prop('checked', !!(extension_settings.caption.allow_reverse_proxy));
|
||||
$('#caption_prompt_ask').prop('checked', !!(extension_settings.caption.prompt_ask));
|
||||
$('#caption_source').val(extension_settings.caption.source);
|
||||
$('#caption_prompt').val(extension_settings.caption.prompt);
|
||||
$('#caption_template').val(extension_settings.caption.template);
|
||||
|
@ -403,4 +432,8 @@ jQuery(function () {
|
|||
extension_settings.caption.allow_reverse_proxy = $('#caption_allow_reverse_proxy').prop('checked');
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
$('#caption_prompt_ask').on('input', () => {
|
||||
extension_settings.caption.prompt_ask = $('#caption_prompt_ask').prop('checked');
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -992,8 +992,7 @@ async function getExpressionsList() {
|
|||
}
|
||||
|
||||
const result = await resolveExpressionsList();
|
||||
result.push(...extension_settings.expressions.custom);
|
||||
return result;
|
||||
return [...result, ...extension_settings.expressions.custom];
|
||||
}
|
||||
|
||||
async function setExpression(character, expression, force) {
|
||||
|
|
|
@ -5,6 +5,7 @@ import { is_group_generating, selected_group } from '../../group-chats.js';
|
|||
import { registerSlashCommand } from '../../slash-commands.js';
|
||||
import { loadMovingUIState } from '../../power-user.js';
|
||||
import { dragElement } from '../../RossAscends-mods.js';
|
||||
import { getTextTokens, tokenizers } from '../../tokenizers.js';
|
||||
export { MODULE_NAME };
|
||||
|
||||
const MODULE_NAME = '1_memory';
|
||||
|
@ -42,26 +43,6 @@ const defaultPrompt = '[Pause your roleplay. Summarize the most important facts
|
|||
const defaultTemplate = '[Summary: {{summary}}]';
|
||||
|
||||
const defaultSettings = {
|
||||
minLongMemory: 16,
|
||||
maxLongMemory: 1024,
|
||||
longMemoryLength: 128,
|
||||
shortMemoryLength: 512,
|
||||
minShortMemory: 128,
|
||||
maxShortMemory: 1024,
|
||||
shortMemoryStep: 16,
|
||||
longMemoryStep: 8,
|
||||
repetitionPenaltyStep: 0.05,
|
||||
repetitionPenalty: 1.2,
|
||||
maxRepetitionPenalty: 2.0,
|
||||
minRepetitionPenalty: 1.0,
|
||||
temperature: 1.0,
|
||||
minTemperature: 0.1,
|
||||
maxTemperature: 2.0,
|
||||
temperatureStep: 0.05,
|
||||
lengthPenalty: 1,
|
||||
minLengthPenalty: -4,
|
||||
maxLengthPenalty: 4,
|
||||
lengthPenaltyStep: 0.1,
|
||||
memoryFrozen: false,
|
||||
SkipWIAN: false,
|
||||
source: summary_sources.extras,
|
||||
|
@ -95,11 +76,6 @@ function loadSettings() {
|
|||
}
|
||||
|
||||
$('#summary_source').val(extension_settings.memory.source).trigger('change');
|
||||
$('#memory_long_length').val(extension_settings.memory.longMemoryLength).trigger('input');
|
||||
$('#memory_short_length').val(extension_settings.memory.shortMemoryLength).trigger('input');
|
||||
$('#memory_repetition_penalty').val(extension_settings.memory.repetitionPenalty).trigger('input');
|
||||
$('#memory_temperature').val(extension_settings.memory.temperature).trigger('input');
|
||||
$('#memory_length_penalty').val(extension_settings.memory.lengthPenalty).trigger('input');
|
||||
$('#memory_frozen').prop('checked', extension_settings.memory.memoryFrozen).trigger('input');
|
||||
$('#memory_skipWIAN').prop('checked', extension_settings.memory.SkipWIAN).trigger('input');
|
||||
$('#memory_prompt').val(extension_settings.memory.prompt).trigger('input');
|
||||
|
@ -126,51 +102,6 @@ function switchSourceControls(value) {
|
|||
});
|
||||
}
|
||||
|
||||
function onMemoryShortInput() {
|
||||
const value = $(this).val();
|
||||
extension_settings.memory.shortMemoryLength = Number(value);
|
||||
$('#memory_short_length_tokens').text(value);
|
||||
saveSettingsDebounced();
|
||||
|
||||
// Don't let long buffer be bigger than short
|
||||
if (extension_settings.memory.longMemoryLength > extension_settings.memory.shortMemoryLength) {
|
||||
$('#memory_long_length').val(extension_settings.memory.shortMemoryLength).trigger('input');
|
||||
}
|
||||
}
|
||||
|
||||
function onMemoryLongInput() {
|
||||
const value = $(this).val();
|
||||
extension_settings.memory.longMemoryLength = Number(value);
|
||||
$('#memory_long_length_tokens').text(value);
|
||||
saveSettingsDebounced();
|
||||
|
||||
// Don't let long buffer be bigger than short
|
||||
if (extension_settings.memory.longMemoryLength > extension_settings.memory.shortMemoryLength) {
|
||||
$('#memory_short_length').val(extension_settings.memory.longMemoryLength).trigger('input');
|
||||
}
|
||||
}
|
||||
|
||||
function onMemoryRepetitionPenaltyInput() {
|
||||
const value = $(this).val();
|
||||
extension_settings.memory.repetitionPenalty = Number(value);
|
||||
$('#memory_repetition_penalty_value').text(extension_settings.memory.repetitionPenalty.toFixed(2));
|
||||
saveSettingsDebounced();
|
||||
}
|
||||
|
||||
function onMemoryTemperatureInput() {
|
||||
const value = $(this).val();
|
||||
extension_settings.memory.temperature = Number(value);
|
||||
$('#memory_temperature_value').text(extension_settings.memory.temperature.toFixed(2));
|
||||
saveSettingsDebounced();
|
||||
}
|
||||
|
||||
function onMemoryLengthPenaltyInput() {
|
||||
const value = $(this).val();
|
||||
extension_settings.memory.lengthPenalty = Number(value);
|
||||
$('#memory_length_penalty_value').text(extension_settings.memory.lengthPenalty.toFixed(2));
|
||||
saveSettingsDebounced();
|
||||
}
|
||||
|
||||
function onMemoryFrozenInput() {
|
||||
const value = Boolean($(this).prop('checked'));
|
||||
extension_settings.memory.memoryFrozen = value;
|
||||
|
@ -444,33 +375,36 @@ async function summarizeChatExtras(context) {
|
|||
const longMemory = getLatestMemoryFromChat(chat);
|
||||
const reversedChat = chat.slice().reverse();
|
||||
reversedChat.shift();
|
||||
let memoryBuffer = [];
|
||||
const memoryBuffer = [];
|
||||
const CONTEXT_SIZE = 1024 - 64;
|
||||
|
||||
for (let mes of reversedChat) {
|
||||
for (const message of reversedChat) {
|
||||
// we reached the point of latest memory
|
||||
if (longMemory && mes.extra && mes.extra.memory == longMemory) {
|
||||
if (longMemory && message.extra && message.extra.memory == longMemory) {
|
||||
break;
|
||||
}
|
||||
|
||||
// don't care about system
|
||||
if (mes.is_system) {
|
||||
if (message.is_system) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// determine the sender's name
|
||||
const name = mes.is_user ? (context.name1 ?? 'You') : (mes.force_avatar ? mes.name : context.name2);
|
||||
const entry = `${name}:\n${mes['mes']}`;
|
||||
const entry = `${message.name}:\n${message.mes}`;
|
||||
memoryBuffer.push(entry);
|
||||
|
||||
// check if token limit was reached
|
||||
if (context.getTokenCount(getMemoryString()) >= extension_settings.memory.shortMemoryLength) {
|
||||
const tokens = getTextTokens(tokenizers.GPT2, getMemoryString()).length;
|
||||
if (tokens >= CONTEXT_SIZE) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const resultingString = getMemoryString();
|
||||
const resultingTokens = getTextTokens(tokenizers.GPT2, resultingString).length;
|
||||
|
||||
if (context.getTokenCount(resultingString) < extension_settings.memory.shortMemoryLength) {
|
||||
if (!resultingString || resultingTokens < CONTEXT_SIZE) {
|
||||
console.debug('Not enough context to summarize');
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -488,13 +422,7 @@ async function summarizeChatExtras(context) {
|
|||
},
|
||||
body: JSON.stringify({
|
||||
text: resultingString,
|
||||
params: {
|
||||
min_length: extension_settings.memory.longMemoryLength * 0, // testing how it behaves 0 min length
|
||||
max_length: extension_settings.memory.longMemoryLength,
|
||||
repetition_penalty: extension_settings.memory.repetitionPenalty,
|
||||
temperature: extension_settings.memory.temperature,
|
||||
length_penalty: extension_settings.memory.lengthPenalty,
|
||||
},
|
||||
params: {},
|
||||
}),
|
||||
});
|
||||
|
||||
|
@ -623,11 +551,6 @@ function setupListeners() {
|
|||
//setup shared listeners for popout and regular ext menu
|
||||
$('#memory_restore').off('click').on('click', onMemoryRestoreClick);
|
||||
$('#memory_contents').off('click').on('input', onMemoryContentInput);
|
||||
$('#memory_long_length').off('click').on('input', onMemoryLongInput);
|
||||
$('#memory_short_length').off('click').on('input', onMemoryShortInput);
|
||||
$('#memory_repetition_penalty').off('click').on('input', onMemoryRepetitionPenaltyInput);
|
||||
$('#memory_temperature').off('click').on('input', onMemoryTemperatureInput);
|
||||
$('#memory_length_penalty').off('click').on('input', onMemoryLengthPenaltyInput);
|
||||
$('#memory_frozen').off('click').on('input', onMemoryFrozenInput);
|
||||
$('#memory_skipWIAN').off('click').on('input', onMemorySkipWIANInput);
|
||||
$('#summary_source').off('click').on('change', onSummarySourceChange);
|
||||
|
@ -720,18 +643,6 @@ jQuery(function () {
|
|||
<input id="memory_prompt_words_force" type="range" value="${defaultSettings.promptForceWords}" min="${defaultSettings.promptMinForceWords}" max="${defaultSettings.promptMaxForceWords}" step="${defaultSettings.promptForceWordsStep}" />
|
||||
<small>If both sliders are non-zero, then both will trigger summary updates a their respective intervals.</small>
|
||||
</div>
|
||||
<div data-source="extras">
|
||||
<label for="memory_short_length">Chat to Summarize buffer length (<span id="memory_short_length_tokens"></span> tokens)</label>
|
||||
<input id="memory_short_length" type="range" value="${defaultSettings.shortMemoryLength}" min="${defaultSettings.minShortMemory}" max="${defaultSettings.maxShortMemory}" step="${defaultSettings.shortMemoryStep}" />
|
||||
<label for="memory_long_length">Summary output length (<span id="memory_long_length_tokens"></span> tokens)</label>
|
||||
<input id="memory_long_length" type="range" value="${defaultSettings.longMemoryLength}" min="${defaultSettings.minLongMemory}" max="${defaultSettings.maxLongMemory}" step="${defaultSettings.longMemoryStep}" />
|
||||
<label for="memory_temperature">Temperature (<span id="memory_temperature_value"></span>)</label>
|
||||
<input id="memory_temperature" type="range" value="${defaultSettings.temperature}" min="${defaultSettings.minTemperature}" max="${defaultSettings.maxTemperature}" step="${defaultSettings.temperatureStep}" />
|
||||
<label for="memory_repetition_penalty">Repetition penalty (<span id="memory_repetition_penalty_value"></span>)</label>
|
||||
<input id="memory_repetition_penalty" type="range" value="${defaultSettings.repetitionPenalty}" min="${defaultSettings.minRepetitionPenalty}" max="${defaultSettings.maxRepetitionPenalty}" step="${defaultSettings.repetitionPenaltyStep}" />
|
||||
<label for="memory_length_penalty">Length preference <small>[higher = longer summaries]</small> (<span id="memory_length_penalty_value"></span>)</label>
|
||||
<input id="memory_length_penalty" type="range" value="${defaultSettings.lengthPenalty}" min="${defaultSettings.minLengthPenalty}" max="${defaultSettings.maxLengthPenalty}" step="${defaultSettings.lengthPenaltyStep}" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -2,6 +2,7 @@ import { getRequestHeaders } from '../../script.js';
|
|||
import { extension_settings } from '../extensions.js';
|
||||
import { oai_settings } from '../openai.js';
|
||||
import { SECRET_KEYS, secret_state } from '../secrets.js';
|
||||
import { textgen_types, textgenerationwebui_settings } from '../textgen-settings.js';
|
||||
import { createThumbnail, isValidUrl } from '../utils.js';
|
||||
|
||||
/**
|
||||
|
@ -11,20 +12,19 @@ import { createThumbnail, isValidUrl } from '../utils.js';
|
|||
* @returns {Promise<string>} Generated caption
|
||||
*/
|
||||
export async function getMultimodalCaption(base64Img, prompt) {
|
||||
if (extension_settings.caption.multimodal_api === 'openai' && !secret_state[SECRET_KEYS.OPENAI]) {
|
||||
throw new Error('OpenAI API key is not set.');
|
||||
}
|
||||
throwIfInvalidModel();
|
||||
|
||||
if (extension_settings.caption.multimodal_api === 'openrouter' && !secret_state[SECRET_KEYS.OPENROUTER]) {
|
||||
throw new Error('OpenRouter API key is not set.');
|
||||
}
|
||||
const noPrefix = ['google', 'ollama', 'llamacpp'].includes(extension_settings.caption.multimodal_api);
|
||||
|
||||
if (extension_settings.caption.multimodal_api === 'google' && !secret_state[SECRET_KEYS.MAKERSUITE]) {
|
||||
throw new Error('MakerSuite API key is not set.');
|
||||
if (noPrefix && base64Img.startsWith('data:image/')) {
|
||||
base64Img = base64Img.split(',')[1];
|
||||
}
|
||||
|
||||
// OpenRouter has a payload limit of ~2MB. Google is 4MB, but we love democracy.
|
||||
const isGoogle = extension_settings.caption.multimodal_api === 'google';
|
||||
const isOllama = extension_settings.caption.multimodal_api === 'ollama';
|
||||
const isLlamaCpp = extension_settings.caption.multimodal_api === 'llamacpp';
|
||||
const isCustom = extension_settings.caption.multimodal_api === 'custom';
|
||||
const base64Bytes = base64Img.length * 0.75;
|
||||
const compressionLimit = 2 * 1024 * 1024;
|
||||
if (['google', 'openrouter'].includes(extension_settings.caption.multimodal_api) && base64Bytes > compressionLimit) {
|
||||
|
@ -45,27 +45,91 @@ export async function getMultimodalCaption(base64Img, prompt) {
|
|||
const proxyUrl = useReverseProxy ? oai_settings.reverse_proxy : '';
|
||||
const proxyPassword = useReverseProxy ? oai_settings.proxy_password : '';
|
||||
|
||||
const apiResult = await fetch(`/api/${isGoogle ? 'google' : 'openai'}/caption-image`, {
|
||||
const requestBody = {
|
||||
image: base64Img,
|
||||
prompt: prompt,
|
||||
};
|
||||
|
||||
if (!isGoogle) {
|
||||
requestBody.api = extension_settings.caption.multimodal_api || 'openai';
|
||||
requestBody.model = extension_settings.caption.multimodal_model || 'gpt-4-vision-preview';
|
||||
requestBody.reverse_proxy = proxyUrl;
|
||||
requestBody.proxy_password = proxyPassword;
|
||||
}
|
||||
|
||||
if (isOllama) {
|
||||
if (extension_settings.caption.multimodal_model === 'ollama_current') {
|
||||
requestBody.model = textgenerationwebui_settings.ollama_model;
|
||||
}
|
||||
|
||||
requestBody.server_url = textgenerationwebui_settings.server_urls[textgen_types.OLLAMA];
|
||||
}
|
||||
|
||||
if (isLlamaCpp) {
|
||||
requestBody.server_url = textgenerationwebui_settings.server_urls[textgen_types.LLAMACPP];
|
||||
}
|
||||
|
||||
if (isCustom) {
|
||||
requestBody.server_url = oai_settings.custom_url;
|
||||
requestBody.model = oai_settings.custom_model || 'gpt-4-vision-preview';
|
||||
requestBody.custom_include_headers = oai_settings.custom_include_headers;
|
||||
requestBody.custom_include_body = oai_settings.custom_include_body;
|
||||
requestBody.custom_exclude_body = oai_settings.custom_exclude_body;
|
||||
}
|
||||
|
||||
function getEndpointUrl() {
|
||||
switch (extension_settings.caption.multimodal_api) {
|
||||
case 'google':
|
||||
return '/api/google/caption-image';
|
||||
case 'llamacpp':
|
||||
return '/api/backends/text-completions/llamacpp/caption-image';
|
||||
case 'ollama':
|
||||
return '/api/backends/text-completions/ollama/caption-image';
|
||||
default:
|
||||
return '/api/openai/caption-image';
|
||||
}
|
||||
}
|
||||
|
||||
const apiResult = await fetch(getEndpointUrl(), {
|
||||
method: 'POST',
|
||||
headers: getRequestHeaders(),
|
||||
body: JSON.stringify({
|
||||
image: base64Img,
|
||||
prompt: prompt,
|
||||
...(isGoogle
|
||||
? {}
|
||||
: {
|
||||
api: extension_settings.caption.multimodal_api || 'openai',
|
||||
model: extension_settings.caption.multimodal_model || 'gpt-4-vision-preview',
|
||||
reverse_proxy: proxyUrl,
|
||||
proxy_password: proxyPassword,
|
||||
}),
|
||||
}),
|
||||
body: JSON.stringify(requestBody),
|
||||
});
|
||||
|
||||
if (!apiResult.ok) {
|
||||
throw new Error('Failed to caption image via OpenAI.');
|
||||
throw new Error('Failed to caption image via Multimodal API.');
|
||||
}
|
||||
|
||||
const { caption } = await apiResult.json();
|
||||
return caption;
|
||||
return String(caption).trim();
|
||||
}
|
||||
|
||||
function throwIfInvalidModel() {
|
||||
if (extension_settings.caption.multimodal_api === 'openai' && !secret_state[SECRET_KEYS.OPENAI]) {
|
||||
throw new Error('OpenAI API key is not set.');
|
||||
}
|
||||
|
||||
if (extension_settings.caption.multimodal_api === 'openrouter' && !secret_state[SECRET_KEYS.OPENROUTER]) {
|
||||
throw new Error('OpenRouter API key is not set.');
|
||||
}
|
||||
|
||||
if (extension_settings.caption.multimodal_api === 'google' && !secret_state[SECRET_KEYS.MAKERSUITE]) {
|
||||
throw new Error('MakerSuite API key is not set.');
|
||||
}
|
||||
|
||||
if (extension_settings.caption.multimodal_api === 'ollama' && !textgenerationwebui_settings.server_urls[textgen_types.OLLAMA]) {
|
||||
throw new Error('Ollama server URL is not set.');
|
||||
}
|
||||
|
||||
if (extension_settings.caption.multimodal_api === 'ollama' && extension_settings.caption.multimodal_model === 'ollama_current' && !textgenerationwebui_settings.ollama_model) {
|
||||
throw new Error('Ollama model is not set.');
|
||||
}
|
||||
|
||||
if (extension_settings.caption.multimodal_api === 'llamacpp' && !textgenerationwebui_settings.server_urls[textgen_types.LLAMACPP]) {
|
||||
throw new Error('LlamaCPP server URL is not set.');
|
||||
}
|
||||
|
||||
if (extension_settings.caption.multimodal_api === 'custom' && !oai_settings.custom_url) {
|
||||
throw new Error('Custom API URL is not set.');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ const controls = [
|
|||
{ id: 'instruct_first_output_sequence', property: 'first_output_sequence', isCheckbox: false },
|
||||
{ id: 'instruct_last_output_sequence', property: 'last_output_sequence', isCheckbox: false },
|
||||
{ id: 'instruct_activation_regex', property: 'activation_regex', isCheckbox: false },
|
||||
{ id: 'instruct_bind_to_context', property: 'bind_to_context', isCheckbox: true },
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -409,6 +410,10 @@ jQuery(() => {
|
|||
});
|
||||
|
||||
$('#instruct_enabled').on('change', function () {
|
||||
if (!power_user.instruct.bind_to_context) {
|
||||
return;
|
||||
}
|
||||
|
||||
// When instruct mode gets enabled, select context template matching selected instruct preset
|
||||
if (power_user.instruct.enabled) {
|
||||
selectMatchingContextTemplate(power_user.instruct.preset);
|
||||
|
@ -440,8 +445,10 @@ jQuery(() => {
|
|||
}
|
||||
});
|
||||
|
||||
// Select matching context template
|
||||
selectMatchingContextTemplate(name);
|
||||
if (power_user.instruct.bind_to_context) {
|
||||
// Select matching context template
|
||||
selectMatchingContextTemplate(name);
|
||||
}
|
||||
|
||||
highlightDefaultPreset();
|
||||
});
|
||||
|
|
|
@ -8,7 +8,7 @@ import {
|
|||
substituteParams,
|
||||
} from '../script.js';
|
||||
import { getCfgPrompt } from './cfg-scale.js';
|
||||
import { MAX_CONTEXT_DEFAULT, MAX_RESPONSE_DEFAULT } from './power-user.js';
|
||||
import { MAX_CONTEXT_DEFAULT, MAX_RESPONSE_DEFAULT, power_user } from './power-user.js';
|
||||
import { getTextTokens, tokenizers } from './tokenizers.js';
|
||||
import EventSourceStream from './sse-stream.js';
|
||||
import {
|
||||
|
@ -437,6 +437,10 @@ export function getNovelGenerationData(finalPrompt, settings, maxLength, isImper
|
|||
BIAS_CACHE.set(BIAS_KEY, logitBias);
|
||||
}
|
||||
|
||||
if (power_user.console_log_prompts) {
|
||||
console.log(finalPrompt);
|
||||
}
|
||||
|
||||
return {
|
||||
'input': finalPrompt,
|
||||
'model': nai_settings.model_novel,
|
||||
|
|
|
@ -166,6 +166,7 @@ export const chat_completion_sources = {
|
|||
AI21: 'ai21',
|
||||
MAKERSUITE: 'makersuite',
|
||||
MISTRALAI: 'mistralai',
|
||||
CUSTOM: 'custom',
|
||||
};
|
||||
|
||||
const prefixMap = selected_group ? {
|
||||
|
@ -211,6 +212,11 @@ const default_settings = {
|
|||
google_model: 'gemini-pro',
|
||||
ai21_model: 'j2-ultra',
|
||||
mistralai_model: 'mistral-medium',
|
||||
custom_model: '',
|
||||
custom_url: '',
|
||||
custom_include_body: '',
|
||||
custom_exclude_body: '',
|
||||
custom_include_headers: '',
|
||||
windowai_model: '',
|
||||
openrouter_model: openrouter_website_model,
|
||||
openrouter_use_fallback: false,
|
||||
|
@ -269,6 +275,11 @@ const oai_settings = {
|
|||
google_model: 'gemini-pro',
|
||||
ai21_model: 'j2-ultra',
|
||||
mistralai_model: 'mistral-medium',
|
||||
custom_model: '',
|
||||
custom_url: '',
|
||||
custom_include_body: '',
|
||||
custom_exclude_body: '',
|
||||
custom_include_headers: '',
|
||||
windowai_model: '',
|
||||
openrouter_model: openrouter_website_model,
|
||||
openrouter_use_fallback: false,
|
||||
|
@ -1271,6 +1282,8 @@ function getChatCompletionModel() {
|
|||
return oai_settings.ai21_model;
|
||||
case chat_completion_sources.MISTRALAI:
|
||||
return oai_settings.mistralai_model;
|
||||
case chat_completion_sources.CUSTOM:
|
||||
return oai_settings.custom_model;
|
||||
default:
|
||||
throw new Error(`Unknown chat completion source: ${oai_settings.chat_completion_source}`);
|
||||
}
|
||||
|
@ -1331,6 +1344,23 @@ function saveModelList(data) {
|
|||
$('#model_openai_select').val(model).trigger('change');
|
||||
}
|
||||
}
|
||||
|
||||
if (oai_settings.chat_completion_source == chat_completion_sources.CUSTOM) {
|
||||
$('#model_custom_select').empty();
|
||||
$('#model_custom_select').append('<option value="">None</option>');
|
||||
model_list.forEach((model) => {
|
||||
$('#model_custom_select').append(
|
||||
$('<option>', {
|
||||
value: model.id,
|
||||
text: model.id,
|
||||
selected: model.id == oai_settings.custom_model,
|
||||
}));
|
||||
});
|
||||
|
||||
if (!oai_settings.custom_model && model_list.length > 0) {
|
||||
$('#model_custom_select').val(model_list[0].id).trigger('change');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function appendOpenRouterOptions(model_list, groupModels = false, sort = false) {
|
||||
|
@ -1459,6 +1489,7 @@ async function sendOpenAIRequest(type, messages, signal) {
|
|||
const isGoogle = oai_settings.chat_completion_source == chat_completion_sources.MAKERSUITE;
|
||||
const isOAI = oai_settings.chat_completion_source == chat_completion_sources.OPENAI;
|
||||
const isMistral = oai_settings.chat_completion_source == chat_completion_sources.MISTRALAI;
|
||||
const isCustom = oai_settings.chat_completion_source == chat_completion_sources.CUSTOM;
|
||||
const isTextCompletion = (isOAI && textCompletionModels.includes(oai_settings.openai_model)) || (isOpenRouter && oai_settings.openrouter_force_instruct && power_user.instruct.enabled);
|
||||
const isQuiet = type === 'quiet';
|
||||
const isImpersonate = type === 'impersonate';
|
||||
|
@ -1485,7 +1516,7 @@ async function sendOpenAIRequest(type, messages, signal) {
|
|||
return sendWindowAIRequest(messages, signal, stream);
|
||||
}
|
||||
|
||||
const logitBiasSources = [chat_completion_sources.OPENAI, chat_completion_sources.OPENROUTER, chat_completion_sources.SCALE];
|
||||
const logitBiasSources = [chat_completion_sources.OPENAI, chat_completion_sources.OPENROUTER, chat_completion_sources.SCALE, chat_completion_sources.CUSTOM];
|
||||
if (oai_settings.bias_preset_selected
|
||||
&& logitBiasSources.includes(oai_settings.chat_completion_source)
|
||||
&& Array.isArray(oai_settings.bias_presets[oai_settings.bias_preset_selected])
|
||||
|
@ -1572,7 +1603,14 @@ async function sendOpenAIRequest(type, messages, signal) {
|
|||
generate_data['safe_mode'] = false; // already defaults to false, but just incase they change that in the future.
|
||||
}
|
||||
|
||||
if ((isOAI || isOpenRouter || isMistral) && oai_settings.seed >= 0) {
|
||||
if (isCustom) {
|
||||
generate_data['custom_url'] = oai_settings.custom_url;
|
||||
generate_data['custom_include_body'] = oai_settings.custom_include_body;
|
||||
generate_data['custom_exclude_body'] = oai_settings.custom_exclude_body;
|
||||
generate_data['custom_include_headers'] = oai_settings.custom_include_headers;
|
||||
}
|
||||
|
||||
if ((isOAI || isOpenRouter || isMistral || isCustom) && oai_settings.seed >= 0) {
|
||||
generate_data['seed'] = oai_settings.seed;
|
||||
}
|
||||
|
||||
|
@ -2318,6 +2356,11 @@ function loadOpenAISettings(data, settings) {
|
|||
oai_settings.openrouter_force_instruct = settings.openrouter_force_instruct ?? default_settings.openrouter_force_instruct;
|
||||
oai_settings.ai21_model = settings.ai21_model ?? default_settings.ai21_model;
|
||||
oai_settings.mistralai_model = settings.mistralai_model ?? default_settings.mistralai_model;
|
||||
oai_settings.custom_model = settings.custom_model ?? default_settings.custom_model;
|
||||
oai_settings.custom_url = settings.custom_url ?? default_settings.custom_url;
|
||||
oai_settings.custom_include_body = settings.custom_include_body ?? default_settings.custom_include_body;
|
||||
oai_settings.custom_exclude_body = settings.custom_exclude_body ?? default_settings.custom_exclude_body;
|
||||
oai_settings.custom_include_headers = settings.custom_include_headers ?? default_settings.custom_include_headers;
|
||||
oai_settings.google_model = settings.google_model ?? default_settings.google_model;
|
||||
oai_settings.chat_completion_source = settings.chat_completion_source ?? default_settings.chat_completion_source;
|
||||
oai_settings.api_url_scale = settings.api_url_scale ?? default_settings.api_url_scale;
|
||||
|
@ -2365,6 +2408,8 @@ function loadOpenAISettings(data, settings) {
|
|||
$(`#model_ai21_select option[value="${oai_settings.ai21_model}"`).attr('selected', true);
|
||||
$('#model_mistralai_select').val(oai_settings.mistralai_model);
|
||||
$(`#model_mistralai_select option[value="${oai_settings.mistralai_model}"`).attr('selected', true);
|
||||
$('#custom_model_id').val(oai_settings.custom_model);
|
||||
$('#custom_api_url_text').val(oai_settings.custom_url);
|
||||
$('#openai_max_context').val(oai_settings.openai_max_context);
|
||||
$('#openai_max_context_counter').val(`${oai_settings.openai_max_context}`);
|
||||
$('#model_openrouter_select').val(oai_settings.openrouter_model);
|
||||
|
@ -2477,7 +2522,13 @@ async function getStatusOpen() {
|
|||
validateReverseProxy();
|
||||
}
|
||||
|
||||
const canBypass = oai_settings.chat_completion_source === chat_completion_sources.OPENAI && oai_settings.bypass_status_check;
|
||||
if (oai_settings.chat_completion_source === chat_completion_sources.CUSTOM) {
|
||||
$('#model_custom_select').empty();
|
||||
data.custom_url = oai_settings.custom_url;
|
||||
data.custom_include_headers = oai_settings.custom_include_headers;
|
||||
}
|
||||
|
||||
const canBypass = (oai_settings.chat_completion_source === chat_completion_sources.OPENAI && oai_settings.bypass_status_check) || oai_settings.chat_completion_source === chat_completion_sources.CUSTOM;
|
||||
if (canBypass) {
|
||||
setOnlineStatus('Status check bypassed');
|
||||
}
|
||||
|
@ -2544,6 +2595,7 @@ async function saveOpenAIPreset(name, settings, triggerUi = true) {
|
|||
openrouter_sort_models: settings.openrouter_sort_models,
|
||||
ai21_model: settings.ai21_model,
|
||||
mistralai_model: settings.mistralai_model,
|
||||
custom_model: settings.custom_model,
|
||||
google_model: settings.google_model,
|
||||
temperature: settings.temp_openai,
|
||||
frequency_penalty: settings.freq_pen_openai,
|
||||
|
@ -2918,6 +2970,11 @@ function onSettingsPresetChange() {
|
|||
openrouter_sort_models: ['#openrouter_sort_models', 'openrouter_sort_models', false],
|
||||
ai21_model: ['#model_ai21_select', 'ai21_model', false],
|
||||
mistralai_model: ['#model_mistralai_select', 'mistralai_model', false],
|
||||
custom_model: ['#custom_model_id', 'custom_model', false],
|
||||
custom_url: ['#custom_api_url_text', 'custom_url', false],
|
||||
custom_include_body: ['#custom_include_body', 'custom_include_body', false],
|
||||
custom_exclude_body: ['#custom_exclude_body', 'custom_exclude_body', false],
|
||||
custom_include_headers: ['#custom_include_headers', 'custom_include_headers', false],
|
||||
google_model: ['#model_google_select', 'google_model', false],
|
||||
openai_max_context: ['#openai_max_context', 'openai_max_context', false],
|
||||
openai_max_tokens: ['#openai_max_tokens', 'openai_max_tokens', false],
|
||||
|
@ -3109,6 +3166,12 @@ async function onModelChange() {
|
|||
oai_settings.mistralai_model = value;
|
||||
}
|
||||
|
||||
if (value && $(this).is('#model_custom_select')) {
|
||||
console.log('Custom model changed to', value);
|
||||
oai_settings.custom_model = value;
|
||||
$('#custom_model_id').val(value).trigger('input');
|
||||
}
|
||||
|
||||
if (oai_settings.chat_completion_source == chat_completion_sources.SCALE) {
|
||||
if (oai_settings.max_context_unlocked) {
|
||||
$('#openai_max_context').attr('max', unlocked_max);
|
||||
|
@ -3256,6 +3319,12 @@ async function onModelChange() {
|
|||
$('#top_k_openai').attr('max', 200).val(oai_settings.top_k_openai).trigger('input');
|
||||
}
|
||||
|
||||
if (oai_settings.chat_completion_source == chat_completion_sources.CUSTOM) {
|
||||
$('#openai_max_context').attr('max', unlocked_max);
|
||||
oai_settings.openai_max_context = Math.min(Number($('#openai_max_context').attr('max')), oai_settings.openai_max_context);
|
||||
$('#openai_max_context').val(oai_settings.openai_max_context).trigger('input');
|
||||
}
|
||||
|
||||
$('#openai_max_context_counter').attr('max', Number($('#openai_max_context').attr('max')));
|
||||
|
||||
saveSettingsDebounced();
|
||||
|
@ -3270,7 +3339,7 @@ async function onNewPresetClick() {
|
|||
const popupText = `
|
||||
<h3>Preset name:</h3>
|
||||
<h4>Hint: Use a character/group name to bind preset to a specific chat.</h4>`;
|
||||
const name = await callPopup(popupText, 'input');
|
||||
const name = await callPopup(popupText, 'input', oai_settings.preset_settings_openai);
|
||||
|
||||
if (!name) {
|
||||
return;
|
||||
|
@ -3398,6 +3467,19 @@ async function onConnectButtonClick(e) {
|
|||
}
|
||||
}
|
||||
|
||||
if (oai_settings.chat_completion_source == chat_completion_sources.CUSTOM) {
|
||||
const api_key_custom = String($('#api_key_custom').val()).trim();
|
||||
|
||||
if (api_key_custom.length) {
|
||||
await writeSecret(SECRET_KEYS.CUSTOM, api_key_custom);
|
||||
}
|
||||
|
||||
if (!oai_settings.custom_url) {
|
||||
console.log('No API URL saved for Custom');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
startStatusLoading();
|
||||
saveSettingsDebounced();
|
||||
await getStatusOpen();
|
||||
|
@ -3433,6 +3515,9 @@ function toggleChatCompletionForms() {
|
|||
else if (oai_settings.chat_completion_source == chat_completion_sources.MISTRALAI) {
|
||||
$('#model_mistralai_select').trigger('change');
|
||||
}
|
||||
else if (oai_settings.chat_completion_source == chat_completion_sources.CUSTOM) {
|
||||
$('#model_custom_select').trigger('change');
|
||||
}
|
||||
$('[data-source]').each(function () {
|
||||
const validSources = $(this).data('source').split(',');
|
||||
$(this).toggle(validSources.includes(oai_settings.chat_completion_source));
|
||||
|
@ -3484,6 +3569,42 @@ function updateScaleForm() {
|
|||
}
|
||||
}
|
||||
|
||||
function onCustomizeParametersClick() {
|
||||
const template = $(`
|
||||
<div class="flex-container flexFlowColumn height100p">
|
||||
<h3>Additional Parameters</h3>
|
||||
<div class="flex1 flex-container flexFlowColumn">
|
||||
<h4>Include Body Parameters</h4>
|
||||
<textarea id="custom_include_body" class="flex1" placeholder="Parameters to be included in the Chat Completion request body (YAML object) Example: - top_k: 20 - repetition_penalty: 1.1"></textarea>
|
||||
</div>
|
||||
<div class="flex1 flex-container flexFlowColumn">
|
||||
<h4>Exclude Body Parameters</h4>
|
||||
<textarea id="custom_exclude_body" class="flex1" placeholder="Parameters to be excluded from the Chat Completion request body (YAML array) Example: - frequency_penalty - presence_penalty"></textarea>
|
||||
</div>
|
||||
<div class="flex1 flex-container flexFlowColumn">
|
||||
<h4>Include Request Headers</h4>
|
||||
<textarea id="custom_include_headers" class="flex1" placeholder="Additional headers for Chat Completion requests (YAML object) Example: - CustomHeader: custom-value - AnotherHeader: custom-value"></textarea>
|
||||
</div>
|
||||
</div>`);
|
||||
|
||||
template.find('#custom_include_body').val(oai_settings.custom_include_body).on('input', function() {
|
||||
oai_settings.custom_include_body = String($(this).val());
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
template.find('#custom_exclude_body').val(oai_settings.custom_exclude_body).on('input', function() {
|
||||
oai_settings.custom_exclude_body = String($(this).val());
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
template.find('#custom_include_headers').val(oai_settings.custom_include_headers).on('input', function() {
|
||||
oai_settings.custom_include_headers = String($(this).val());
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
callPopup(template, 'text', '', { wide: true, large: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the model supports image inlining
|
||||
* @returns {boolean} True if the model supports image inlining
|
||||
|
@ -3495,7 +3616,7 @@ export function isImageInliningSupported() {
|
|||
|
||||
const gpt4v = 'gpt-4-vision';
|
||||
const geminiProV = 'gemini-pro-vision';
|
||||
const llava13b = 'llava-13b';
|
||||
const llava = 'llava';
|
||||
|
||||
if (!oai_settings.image_inlining) {
|
||||
return false;
|
||||
|
@ -3507,7 +3628,9 @@ export function isImageInliningSupported() {
|
|||
case chat_completion_sources.MAKERSUITE:
|
||||
return oai_settings.google_model.includes(geminiProV);
|
||||
case chat_completion_sources.OPENROUTER:
|
||||
return oai_settings.openrouter_model.includes(gpt4v) || oai_settings.openrouter_model.includes(llava13b);
|
||||
return !oai_settings.openrouter_force_instruct && (oai_settings.openrouter_model.includes(gpt4v) || oai_settings.openrouter_model.includes(llava));
|
||||
case chat_completion_sources.CUSTOM:
|
||||
return oai_settings.custom_model.includes(gpt4v) || oai_settings.custom_model.includes(llava) || oai_settings.custom_model.includes(geminiProV);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -3813,6 +3936,16 @@ $(document).ready(async function () {
|
|||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$('#custom_api_url_text').on('input', function () {
|
||||
oai_settings.custom_url = String($(this).val());
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$('#custom_model_id').on('input', function () {
|
||||
oai_settings.custom_model = String($(this).val());
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$(document).on('input', '#openai_settings .autoSetHeight', function () {
|
||||
resetScrollHeight($(this));
|
||||
});
|
||||
|
@ -3829,6 +3962,7 @@ $(document).ready(async function () {
|
|||
$('#openrouter_sort_models').on('change', onOpenrouterModelSortChange);
|
||||
$('#model_ai21_select').on('change', onModelChange);
|
||||
$('#model_mistralai_select').on('change', onModelChange);
|
||||
$('#model_custom_select').on('change', onModelChange);
|
||||
$('#settings_preset_openai').on('change', onSettingsPresetChange);
|
||||
$('#new_oai_preset').on('click', onNewPresetClick);
|
||||
$('#delete_oai_preset').on('click', onDeletePresetClick);
|
||||
|
@ -3843,4 +3977,5 @@ $(document).ready(async function () {
|
|||
$('#openai_logit_bias_delete_preset').on('click', onLogitBiasPresetDeleteClick);
|
||||
$('#import_oai_preset').on('click', onImportPresetClick);
|
||||
$('#openai_proxy_password_show').on('click', onProxyPasswordShowClick);
|
||||
$('#customize_additional_parameters').on('click', onCustomizeParametersClick);
|
||||
});
|
||||
|
|
|
@ -193,6 +193,22 @@ export function autoSelectPersona(name) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the name of a persona if it exists.
|
||||
* @param {string} avatarId User avatar id
|
||||
* @param {string} newName New name for the persona
|
||||
*/
|
||||
export async function updatePersonaNameIfExists(avatarId, newName) {
|
||||
if (avatarId in power_user.personas) {
|
||||
power_user.personas[avatarId] = newName;
|
||||
await getUserAvatars();
|
||||
saveSettingsDebounced();
|
||||
console.log(`Updated persona name for ${avatarId} to ${newName}`);
|
||||
} else {
|
||||
console.log(`Persona name ${avatarId} was not updated because it does not exist`);
|
||||
}
|
||||
}
|
||||
|
||||
async function bindUserNameToPersona() {
|
||||
const avatarId = $(this).closest('.avatar-container').find('.avatar').attr('imgfile');
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ import {
|
|||
import { registerSlashCommand } from './slash-commands.js';
|
||||
import { tags } from './tags.js';
|
||||
import { tokenizers } from './tokenizers.js';
|
||||
import { BIAS_CACHE } from './logit-bias.js';
|
||||
|
||||
import { countOccurrences, debounce, delay, isOdd, resetScrollHeight, shuffle, sortMoments, stringToRange, timestampToMoment } from './utils.js';
|
||||
|
||||
|
@ -204,6 +205,7 @@ let power_user = {
|
|||
names: false,
|
||||
names_force_groups: true,
|
||||
activation_regex: '',
|
||||
bind_to_context: false,
|
||||
},
|
||||
|
||||
default_context: 'Default',
|
||||
|
@ -1717,17 +1719,18 @@ function loadContextSettings() {
|
|||
}
|
||||
});
|
||||
|
||||
// Select matching instruct preset
|
||||
for (const instruct_preset of instruct_presets) {
|
||||
// If instruct preset matches the context template
|
||||
if (instruct_preset.name === name) {
|
||||
selectInstructPreset(instruct_preset.name);
|
||||
break;
|
||||
if (power_user.instruct.bind_to_context) {
|
||||
// Select matching instruct preset
|
||||
for (const instruct_preset of instruct_presets) {
|
||||
// If instruct preset matches the context template
|
||||
if (instruct_preset.name === name) {
|
||||
selectInstructPreset(instruct_preset.name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
highlightDefaultContext();
|
||||
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
|
@ -2932,6 +2935,7 @@ $(document).ready(() => {
|
|||
$('#tokenizer').on('change', function () {
|
||||
const value = $(this).find(':selected').val();
|
||||
power_user.tokenizer = Number(value);
|
||||
BIAS_CACHE.clear();
|
||||
saveSettingsDebounced();
|
||||
|
||||
// Trigger character editor re-tokenize
|
||||
|
|
|
@ -303,8 +303,14 @@ class PresetManager {
|
|||
'model_novel',
|
||||
'streaming_kobold',
|
||||
'enabled',
|
||||
'bind_to_context',
|
||||
'seed',
|
||||
'legacy_api',
|
||||
'mancer_model',
|
||||
'togetherai_model',
|
||||
'ollama_model',
|
||||
'server_urls',
|
||||
'type',
|
||||
];
|
||||
const settings = Object.assign({}, getSettingsByApiId(this.apiId));
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ export const SECRET_KEYS = {
|
|||
SERPAPI: 'api_key_serpapi',
|
||||
MISTRALAI: 'api_key_mistralai',
|
||||
TOGETHERAI: 'api_key_togetherai',
|
||||
CUSTOM: 'api_key_custom',
|
||||
};
|
||||
|
||||
const INPUT_MAP = {
|
||||
|
@ -32,6 +33,7 @@ const INPUT_MAP = {
|
|||
[SECRET_KEYS.APHRODITE]: '#api_key_aphrodite',
|
||||
[SECRET_KEYS.TABBY]: '#api_key_tabby',
|
||||
[SECRET_KEYS.MISTRALAI]: '#api_key_mistralai',
|
||||
[SECRET_KEYS.CUSTOM]: '#api_key_custom',
|
||||
[SECRET_KEYS.TOGETHERAI]: '#api_key_togetherai',
|
||||
};
|
||||
|
||||
|
|
|
@ -845,7 +845,7 @@ async function unhideMessageCallback(_, arg) {
|
|||
/**
|
||||
* Copium for running group actions when the member is offscreen.
|
||||
* @param {number} chid - character ID
|
||||
* @param {string} action - one of 'enable', 'disable', 'up', 'down', 'peek', 'remove'
|
||||
* @param {string} action - one of 'enable', 'disable', 'up', 'down', 'view', 'remove'
|
||||
* @returns {void}
|
||||
*/
|
||||
function performGroupMemberAction(chid, action) {
|
||||
|
@ -868,7 +868,9 @@ function performGroupMemberAction(chid, action) {
|
|||
|
||||
if (wasOffscreen) {
|
||||
$(pageSizeSelector).val(paginationValue).trigger('change');
|
||||
$(paginationSelector).pagination('go', pageValue);
|
||||
if ($(paginationSelector).length) {
|
||||
$(paginationSelector).pagination('go', pageValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -958,7 +960,7 @@ async function peekCallback(_, arg) {
|
|||
return '';
|
||||
}
|
||||
|
||||
performGroupMemberAction(chid, 'peek');
|
||||
performGroupMemberAction(chid, 'view');
|
||||
return '';
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<h3>Confused or lost?</h3>
|
||||
<ul>
|
||||
<li>
|
||||
<span class="note-link-span">?</span> - click these icons!
|
||||
<span class="note-link-span"><a class="fa-solid fa-circle-question" target="_blank" href="https://docs.sillytavern.app/"></a></span> - click these icons!
|
||||
</li>
|
||||
<li>
|
||||
Enter <code>/?</code> in the chat bar
|
||||
|
|
|
@ -1,10 +1,30 @@
|
|||
import { setGenerationParamsFromPreset } from '../script.js';
|
||||
import { callPopup, getRequestHeaders, setGenerationParamsFromPreset } from '../script.js';
|
||||
import { isMobile } from './RossAscends-mods.js';
|
||||
import { textgenerationwebui_settings as textgen_settings } from './textgen-settings.js';
|
||||
import { textgenerationwebui_settings as textgen_settings, textgen_types } from './textgen-settings.js';
|
||||
|
||||
let mancerModels = [];
|
||||
let togetherModels = [];
|
||||
|
||||
export async function loadOllamaModels(data) {
|
||||
if (!Array.isArray(data)) {
|
||||
console.error('Invalid Ollama models data', data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!data.find(x => x.id === textgen_settings.ollama_model)) {
|
||||
textgen_settings.ollama_model = data[0]?.id || '';
|
||||
}
|
||||
|
||||
$('#ollama_model').empty();
|
||||
for (const model of data) {
|
||||
const option = document.createElement('option');
|
||||
option.value = model.id;
|
||||
option.text = model.name;
|
||||
option.selected = model.id === textgen_settings.ollama_model;
|
||||
$('#ollama_model').append(option);
|
||||
}
|
||||
}
|
||||
|
||||
export async function loadTogetherAIModels(data) {
|
||||
if (!Array.isArray(data)) {
|
||||
console.error('Invalid Together AI models data', data);
|
||||
|
@ -13,6 +33,10 @@ export async function loadTogetherAIModels(data) {
|
|||
|
||||
togetherModels = data;
|
||||
|
||||
if (!data.find(x => x.name === textgen_settings.togetherai_model)) {
|
||||
textgen_settings.togetherai_model = data[0]?.name || '';
|
||||
}
|
||||
|
||||
$('#model_togetherai_select').empty();
|
||||
for (const model of data) {
|
||||
// Hey buddy, I think you've got the wrong door.
|
||||
|
@ -36,6 +60,10 @@ export async function loadMancerModels(data) {
|
|||
|
||||
mancerModels = data;
|
||||
|
||||
if (!data.find(x => x.id === textgen_settings.mancer_model)) {
|
||||
textgen_settings.mancer_model = data[0]?.id || '';
|
||||
}
|
||||
|
||||
$('#mancer_model').empty();
|
||||
for (const model of data) {
|
||||
const option = document.createElement('option');
|
||||
|
@ -55,7 +83,6 @@ function onMancerModelSelect() {
|
|||
setGenerationParamsFromPreset({ max_length: limits.context, genamt: limits.completion });
|
||||
}
|
||||
|
||||
|
||||
function onTogetherModelSelect() {
|
||||
const modelName = String($('#model_togetherai_select').val());
|
||||
textgen_settings.togetherai_model = modelName;
|
||||
|
@ -64,6 +91,12 @@ function onTogetherModelSelect() {
|
|||
setGenerationParamsFromPreset({ max_length: model.context_length });
|
||||
}
|
||||
|
||||
function onOllamaModelSelect() {
|
||||
const modelId = String($('#ollama_model').val());
|
||||
textgen_settings.ollama_model = modelId;
|
||||
$('#api_button_textgenerationwebui').trigger('click');
|
||||
}
|
||||
|
||||
function getMancerModelTemplate(option) {
|
||||
const model = mancerModels.find(x => x.id === option?.element?.value);
|
||||
|
||||
|
@ -97,9 +130,52 @@ function getTogetherModelTemplate(option) {
|
|||
`));
|
||||
}
|
||||
|
||||
async function downloadOllamaModel() {
|
||||
try {
|
||||
const serverUrl = textgen_settings.server_urls[textgen_types.OLLAMA];
|
||||
|
||||
if (!serverUrl) {
|
||||
toastr.info('Please connect to an Ollama server first.');
|
||||
return;
|
||||
}
|
||||
|
||||
const html = `Enter a model tag, for example <code>llama2:latest</code>.<br>
|
||||
See <a target="_blank" href="https://ollama.ai/library">Library</a> for available models.`;
|
||||
const name = await callPopup(html, 'input', '', { okButton: 'Download' });
|
||||
|
||||
if (!name) {
|
||||
return;
|
||||
}
|
||||
|
||||
toastr.info('Download may take a while, please wait...', 'Working on it');
|
||||
|
||||
const response = await fetch('/api/backends/text-completions/ollama/download', {
|
||||
method: 'POST',
|
||||
headers: getRequestHeaders(),
|
||||
body: JSON.stringify({
|
||||
name: name,
|
||||
api_server: serverUrl,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(response.statusText);
|
||||
}
|
||||
|
||||
// Force refresh the model list
|
||||
toastr.success('Download complete. Please select the model from the dropdown.');
|
||||
$('#api_button_textgenerationwebui').trigger('click');
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
toastr.error('Failed to download Ollama model. Please try again.');
|
||||
}
|
||||
}
|
||||
|
||||
jQuery(function () {
|
||||
$('#mancer_model').on('change', onMancerModelSelect);
|
||||
$('#model_togetherai_select').on('change', onTogetherModelSelect);
|
||||
$('#ollama_model').on('change', onOllamaModelSelect);
|
||||
$('#ollama_download_model').on('click', downloadOllamaModel);
|
||||
|
||||
if (!isMobile()) {
|
||||
$('#mancer_model').select2({
|
||||
|
@ -116,5 +192,11 @@ jQuery(function () {
|
|||
width: '100%',
|
||||
templateResult: getTogetherModelTemplate,
|
||||
});
|
||||
$('#ollama_model').select2({
|
||||
placeholder: 'Select a model',
|
||||
searchInputPlaceholder: 'Search models...',
|
||||
searchInputCssClass: 'text_pole',
|
||||
width: '100%',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import {
|
||||
api_server_textgenerationwebui,
|
||||
getRequestHeaders,
|
||||
getStoppingStrings,
|
||||
max_context,
|
||||
|
@ -33,9 +32,11 @@ export const textgen_types = {
|
|||
TABBY: 'tabby',
|
||||
KOBOLDCPP: 'koboldcpp',
|
||||
TOGETHERAI: 'togetherai',
|
||||
LLAMACPP: 'llamacpp',
|
||||
OLLAMA: 'ollama',
|
||||
};
|
||||
|
||||
const { MANCER, APHRODITE, TOGETHERAI } = textgen_types;
|
||||
const { MANCER, APHRODITE, TOGETHERAI, OOBA, OLLAMA, LLAMACPP } = textgen_types;
|
||||
const BIAS_KEY = '#textgenerationwebui_api-settings';
|
||||
|
||||
// Maybe let it be configurable in the future?
|
||||
|
@ -45,6 +46,15 @@ const MANCER_SERVER_DEFAULT = 'https://neuro.mancer.tech';
|
|||
let MANCER_SERVER = localStorage.getItem(MANCER_SERVER_KEY) ?? MANCER_SERVER_DEFAULT;
|
||||
let TOGETHERAI_SERVER = 'https://api.together.xyz';
|
||||
|
||||
const SERVER_INPUTS = {
|
||||
[textgen_types.OOBA]: '#textgenerationwebui_api_url_text',
|
||||
[textgen_types.APHRODITE]: '#aphrodite_api_url_text',
|
||||
[textgen_types.TABBY]: '#tabby_api_url_text',
|
||||
[textgen_types.KOBOLDCPP]: '#koboldcpp_api_url_text',
|
||||
[textgen_types.LLAMACPP]: '#llamacpp_api_url_text',
|
||||
[textgen_types.OLLAMA]: '#ollama_api_url_text',
|
||||
};
|
||||
|
||||
const KOBOLDCPP_ORDER = [6, 0, 1, 3, 4, 2, 5];
|
||||
const settings = {
|
||||
temp: 0.7,
|
||||
|
@ -94,10 +104,12 @@ const settings = {
|
|||
type: textgen_types.OOBA,
|
||||
mancer_model: 'mytholite',
|
||||
togetherai_model: 'Gryphe/MythoMax-L2-13b',
|
||||
ollama_model: '',
|
||||
legacy_api: false,
|
||||
sampler_order: KOBOLDCPP_ORDER,
|
||||
logit_bias: [],
|
||||
n: 1,
|
||||
server_urls: {},
|
||||
};
|
||||
|
||||
export let textgenerationwebui_banned_in_macros = [];
|
||||
|
@ -153,6 +165,37 @@ const setting_names = [
|
|||
'logit_bias',
|
||||
];
|
||||
|
||||
export function validateTextGenUrl() {
|
||||
const selector = SERVER_INPUTS[settings.type];
|
||||
|
||||
if (!selector) {
|
||||
return;
|
||||
}
|
||||
|
||||
const control = $(selector);
|
||||
const url = String(control.val()).trim();
|
||||
const formattedUrl = formatTextGenURL(url);
|
||||
|
||||
if (!formattedUrl) {
|
||||
toastr.error('Enter a valid API URL', 'Text Completion API');
|
||||
return;
|
||||
}
|
||||
|
||||
control.val(formattedUrl);
|
||||
}
|
||||
|
||||
export function getTextGenServer() {
|
||||
if (settings.type === MANCER) {
|
||||
return MANCER_SERVER;
|
||||
}
|
||||
|
||||
if (settings.type === TOGETHERAI) {
|
||||
return TOGETHERAI_SERVER;
|
||||
}
|
||||
|
||||
return settings.server_urls[settings.type] ?? '';
|
||||
}
|
||||
|
||||
async function selectPreset(name) {
|
||||
const preset = textgenerationwebui_presets[textgenerationwebui_preset_names.indexOf(name)];
|
||||
|
||||
|
@ -166,6 +209,7 @@ async function selectPreset(name) {
|
|||
setSettingByName(name, value, true);
|
||||
}
|
||||
setGenerationParamsFromPreset(preset);
|
||||
BIAS_CACHE.delete(BIAS_KEY);
|
||||
displayLogitBias(preset.logit_bias, BIAS_KEY);
|
||||
saveSettingsDebounced();
|
||||
}
|
||||
|
@ -289,6 +333,21 @@ function loadTextGenSettings(data, loadedSettings) {
|
|||
textgenerationwebui_preset_names = data.textgenerationwebui_preset_names ?? [];
|
||||
Object.assign(settings, loadedSettings.textgenerationwebui_settings ?? {});
|
||||
|
||||
if (loadedSettings.api_server_textgenerationwebui) {
|
||||
for (const type of Object.keys(SERVER_INPUTS)) {
|
||||
settings.server_urls[type] = loadedSettings.api_server_textgenerationwebui;
|
||||
}
|
||||
delete loadedSettings.api_server_textgenerationwebui;
|
||||
}
|
||||
|
||||
for (const [type, selector] of Object.entries(SERVER_INPUTS)) {
|
||||
const control = $(selector);
|
||||
control.val(settings.server_urls[type] ?? '').on('input', function () {
|
||||
settings.server_urls[type] = String($(this).val());
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
}
|
||||
|
||||
if (loadedSettings.api_use_mancer_webui) {
|
||||
settings.type = MANCER;
|
||||
}
|
||||
|
@ -311,6 +370,7 @@ function loadTextGenSettings(data, loadedSettings) {
|
|||
|
||||
$('#textgen_type').val(settings.type);
|
||||
showTypeSpecificControls(settings.type);
|
||||
BIAS_CACHE.delete(BIAS_KEY);
|
||||
displayLogitBias(settings.logit_bias, BIAS_KEY);
|
||||
//this is needed because showTypeSpecificControls() does not handle NOT declarations
|
||||
if (settings.type === textgen_types.APHRODITE) {
|
||||
|
@ -333,19 +393,6 @@ function loadTextGenSettings(data, loadedSettings) {
|
|||
});
|
||||
}
|
||||
|
||||
export function getTextGenUrlSourceId() {
|
||||
switch (settings.type) {
|
||||
case textgen_types.OOBA:
|
||||
return '#textgenerationwebui_api_url_text';
|
||||
case textgen_types.APHRODITE:
|
||||
return '#aphrodite_api_url_text';
|
||||
case textgen_types.TABBY:
|
||||
return '#tabby_api_url_text';
|
||||
case textgen_types.KOBOLDCPP:
|
||||
return '#koboldcpp_api_url_text';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts the sampler items by the given order.
|
||||
* @param {any[]} orderArray Sampler order array.
|
||||
|
@ -415,9 +462,13 @@ jQuery(function () {
|
|||
|
||||
showTypeSpecificControls(type);
|
||||
setOnlineStatus('no_connection');
|
||||
BIAS_CACHE.delete(BIAS_KEY);
|
||||
|
||||
$('#main_api').trigger('change');
|
||||
$('#api_button_textgenerationwebui').trigger('click');
|
||||
|
||||
if (!SERVER_INPUTS[type] || settings.server_urls[type]) {
|
||||
$('#api_button_textgenerationwebui').trigger('click');
|
||||
}
|
||||
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
@ -463,11 +514,14 @@ jQuery(function () {
|
|||
|
||||
function showTypeSpecificControls(type) {
|
||||
$('[data-tg-type]').each(function () {
|
||||
const tgType = $(this).attr('data-tg-type');
|
||||
if (tgType == type) {
|
||||
$(this).show();
|
||||
} else {
|
||||
$(this).hide();
|
||||
const tgTypes = $(this).attr('data-tg-type').split(',');
|
||||
for (const tgType of tgTypes) {
|
||||
if (tgType === type || tgType == 'all') {
|
||||
$(this).show();
|
||||
return;
|
||||
} else {
|
||||
$(this).hide();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -550,11 +604,11 @@ async function generateTextGenWithStreaming(generate_data, signal) {
|
|||
|
||||
let data = JSON.parse(value.data);
|
||||
|
||||
if (data?.choices[0]?.index > 0) {
|
||||
if (data?.choices?.[0]?.index > 0) {
|
||||
const swipeIndex = data.choices[0].index - 1;
|
||||
swipes[swipeIndex] = (swipes[swipeIndex] || '') + data.choices[0].text;
|
||||
} else {
|
||||
text += data?.choices[0]?.text || '';
|
||||
text += data?.choices?.[0]?.text || data?.content || '';
|
||||
}
|
||||
|
||||
yield { text, swipes };
|
||||
|
@ -585,6 +639,11 @@ function tryParseStreamingError(response, decoded) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a string of comma-separated integers to an array of integers.
|
||||
* @param {string} string Input string
|
||||
* @returns {number[]} Array of integers
|
||||
*/
|
||||
function toIntArray(string) {
|
||||
if (!string) {
|
||||
return [];
|
||||
|
@ -606,24 +665,21 @@ function getModel() {
|
|||
return online_status;
|
||||
}
|
||||
|
||||
if (settings.type === OLLAMA) {
|
||||
if (!settings.ollama_model) {
|
||||
toastr.error('No Ollama model selected.', 'Text Completion API');
|
||||
throw new Error('No Ollama model selected');
|
||||
}
|
||||
|
||||
return settings.ollama_model;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function getTextGenServer() {
|
||||
if (settings.type === MANCER) {
|
||||
return MANCER_SERVER;
|
||||
}
|
||||
|
||||
if (settings.type === TOGETHERAI) {
|
||||
return TOGETHERAI_SERVER;
|
||||
}
|
||||
|
||||
return api_server_textgenerationwebui;
|
||||
}
|
||||
|
||||
export function getTextGenGenerationData(finalPrompt, maxTokens, isImpersonate, isContinue, cfgValues, type) {
|
||||
const canMultiSwipe = !isContinue && !isImpersonate && type !== 'quiet';
|
||||
let APIflags = {
|
||||
let params = {
|
||||
'prompt': finalPrompt,
|
||||
'model': getModel(),
|
||||
'max_new_tokens': maxTokens,
|
||||
|
@ -659,12 +715,10 @@ export function getTextGenGenerationData(finalPrompt, maxTokens, isImpersonate,
|
|||
getCustomTokenBans(),
|
||||
'api_type': settings.type,
|
||||
'api_server': getTextGenServer(),
|
||||
'legacy_api': settings.legacy_api && settings.type !== MANCER && settings.type !== TOGETHERAI,
|
||||
'sampler_order': settings.type === textgen_types.KOBOLDCPP ?
|
||||
settings.sampler_order :
|
||||
undefined,
|
||||
'legacy_api': settings.legacy_api && (settings.type === OOBA || settings.type === APHRODITE),
|
||||
'sampler_order': settings.type === textgen_types.KOBOLDCPP ? settings.sampler_order : undefined,
|
||||
};
|
||||
let aphroditeExclusionFlags = {
|
||||
const nonAphroditeParams = {
|
||||
'repetition_penalty_range': settings.rep_pen_range,
|
||||
'encoder_repetition_penalty': settings.encoder_rep_pen,
|
||||
'no_repeat_ngram_size': settings.no_repeat_ngram_size,
|
||||
|
@ -675,8 +729,15 @@ export function getTextGenGenerationData(finalPrompt, maxTokens, isImpersonate,
|
|||
'guidance_scale': cfgValues?.guidanceScale?.value ?? settings.guidance_scale ?? 1,
|
||||
'negative_prompt': cfgValues?.negativePrompt ?? substituteParams(settings.negative_prompt) ?? '',
|
||||
'grammar_string': settings.grammar_string,
|
||||
// llama.cpp aliases. In case someone wants to use LM Studio as Text Completion API
|
||||
'repeat_penalty': settings.rep_pen,
|
||||
'tfs_z': settings.tfs,
|
||||
'repeat_last_n': settings.rep_pen_range,
|
||||
'n_predict': settings.maxTokens,
|
||||
'mirostat': settings.mirostat_mode,
|
||||
'ignore_eos': settings.ban_eos_token,
|
||||
};
|
||||
let aphroditeFlags = {
|
||||
const aphroditeParams = {
|
||||
'n': canMultiSwipe ? settings.n : 1,
|
||||
'best_of': canMultiSwipe ? settings.n : 1,
|
||||
'ignore_eos': settings.ignore_eos_token_aphrodite,
|
||||
|
@ -685,18 +746,33 @@ export function getTextGenGenerationData(finalPrompt, maxTokens, isImpersonate,
|
|||
//'logprobs': settings.log_probs_aphrodite,
|
||||
//'prompt_logprobs': settings.prompt_log_probs_aphrodite,
|
||||
};
|
||||
if (settings.type === textgen_types.APHRODITE) {
|
||||
APIflags = Object.assign(APIflags, aphroditeFlags);
|
||||
if (settings.type === APHRODITE) {
|
||||
params = Object.assign(params, aphroditeParams);
|
||||
} else {
|
||||
APIflags = Object.assign(APIflags, aphroditeExclusionFlags);
|
||||
params = Object.assign(params, nonAphroditeParams);
|
||||
}
|
||||
|
||||
if (Array.isArray(settings.logit_bias) && settings.logit_bias.length) {
|
||||
const logitBias = BIAS_CACHE.get(BIAS_KEY) || calculateLogitBias();
|
||||
BIAS_CACHE.set(BIAS_KEY, logitBias);
|
||||
APIflags.logit_bias = logitBias;
|
||||
params.logit_bias = logitBias;
|
||||
}
|
||||
|
||||
return APIflags;
|
||||
if (settings.type === LLAMACPP || settings.type === OLLAMA) {
|
||||
// Convert bias and token bans to array of arrays
|
||||
const logitBiasArray = (params.logit_bias && typeof params.logit_bias === 'object' && Object.keys(params.logit_bias).length > 0)
|
||||
? Object.entries(params.logit_bias).map(([key, value]) => [Number(key), value])
|
||||
: [];
|
||||
const tokenBans = toIntArray(getCustomTokenBans());
|
||||
logitBiasArray.push(...tokenBans.map(x => [Number(x), false]));
|
||||
const llamaCppParams = {
|
||||
'logit_bias': logitBiasArray,
|
||||
// Conflicts with ooba's grammar_string
|
||||
'grammar': settings.grammar_string,
|
||||
};
|
||||
params = Object.assign(params, llamaCppParams);
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import { characters, main_api, api_server, api_server_textgenerationwebui, nai_settings, online_status, this_chid } from '../script.js';
|
||||
import { characters, main_api, api_server, nai_settings, online_status, this_chid } from '../script.js';
|
||||
import { power_user, registerDebugFunction } from './power-user.js';
|
||||
import { chat_completion_sources, model_list, oai_settings } from './openai.js';
|
||||
import { groups, selected_group } from './group-chats.js';
|
||||
import { getStringHash } from './utils.js';
|
||||
import { kai_flags } from './kai-settings.js';
|
||||
import { textgen_types, textgenerationwebui_settings as textgen_settings } from './textgen-settings.js';
|
||||
import { textgen_types, textgenerationwebui_settings as textgen_settings, getTextGenServer } from './textgen-settings.js';
|
||||
|
||||
const { OOBA, TABBY, KOBOLDCPP, MANCER, TOGETHERAI } = textgen_types;
|
||||
const { OOBA, TABBY, KOBOLDCPP, APHRODITE, LLAMACPP } = textgen_types;
|
||||
|
||||
export const CHARACTERS_PER_TOKEN_RATIO = 3.35;
|
||||
const TOKENIZER_WARNING_KEY = 'tokenizationWarningShown';
|
||||
|
@ -190,7 +190,7 @@ export function getTokenizerBestMatch(forApi) {
|
|||
// - Tokenizer haven't reported an error previously
|
||||
const hasTokenizerError = sessionStorage.getItem(TOKENIZER_WARNING_KEY);
|
||||
const isConnected = online_status !== 'no_connection';
|
||||
const isTokenizerSupported = textgen_settings.type === OOBA || textgen_settings.type === TABBY || textgen_settings.type === KOBOLDCPP;
|
||||
const isTokenizerSupported = [OOBA, TABBY, KOBOLDCPP, LLAMACPP].includes(textgen_settings.type);
|
||||
|
||||
if (!hasTokenizerError && isConnected) {
|
||||
if (forApi === 'kobold' && kai_flags.can_use_tokenization) {
|
||||
|
@ -388,6 +388,10 @@ export function getTokenizerModel() {
|
|||
return mistralTokenizer;
|
||||
}
|
||||
|
||||
if (oai_settings.chat_completion_source == chat_completion_sources.CUSTOM) {
|
||||
return oai_settings.custom_model;
|
||||
}
|
||||
|
||||
// Default to Turbo 3.5
|
||||
return turboTokenizer;
|
||||
}
|
||||
|
@ -537,11 +541,8 @@ function getTextgenAPITokenizationParams(str) {
|
|||
return {
|
||||
text: str,
|
||||
api_type: textgen_settings.type,
|
||||
url: api_server_textgenerationwebui,
|
||||
legacy_api:
|
||||
textgen_settings.legacy_api &&
|
||||
textgen_settings.type !== MANCER &&
|
||||
textgen_settings.type !== TOGETHERAI,
|
||||
url: getTextGenServer(),
|
||||
legacy_api: textgen_settings.legacy_api && (textgen_settings.type === OOBA || textgen_settings.type === APHRODITE),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -3531,11 +3531,11 @@ a {
|
|||
display: none;
|
||||
}
|
||||
|
||||
.reverse_proxy_warning {
|
||||
.reverse_proxy_warning:not(small) {
|
||||
color: var(--warning);
|
||||
background-color: var(--black70a);
|
||||
text-shadow: none !important;
|
||||
margin-top: 12px !important;
|
||||
margin-top: 5px !important;
|
||||
border-radius: 5px;
|
||||
padding: 3px;
|
||||
border: 1px solid var(--SmartThemeBorderColor);
|
||||
|
|
|
@ -160,6 +160,7 @@ const CHAT_COMPLETION_SOURCES = {
|
|||
AI21: 'ai21',
|
||||
MAKERSUITE: 'makersuite',
|
||||
MISTRALAI: 'mistralai',
|
||||
CUSTOM: 'custom',
|
||||
};
|
||||
|
||||
const UPLOADS_PATH = './uploads';
|
||||
|
@ -172,6 +173,8 @@ const TEXTGEN_TYPES = {
|
|||
TABBY: 'tabby',
|
||||
KOBOLDCPP: 'koboldcpp',
|
||||
TOGETHERAI: 'togetherai',
|
||||
LLAMACPP: 'llamacpp',
|
||||
OLLAMA: 'ollama',
|
||||
};
|
||||
|
||||
// https://docs.together.ai/reference/completions
|
||||
|
@ -186,6 +189,25 @@ const TOGETHERAI_KEYS = [
|
|||
'stream',
|
||||
];
|
||||
|
||||
// https://github.com/jmorganca/ollama/blob/main/docs/api.md#request-with-options
|
||||
const OLLAMA_KEYS = [
|
||||
'num_predict',
|
||||
'stop',
|
||||
'temperature',
|
||||
'repeat_penalty',
|
||||
'presence_penalty',
|
||||
'frequency_penalty',
|
||||
'top_k',
|
||||
'top_p',
|
||||
'tfs_z',
|
||||
'typical_p',
|
||||
'seed',
|
||||
'repeat_last_n',
|
||||
'mirostat',
|
||||
'mirostat_tau',
|
||||
'mirostat_eta',
|
||||
];
|
||||
|
||||
const AVATAR_WIDTH = 400;
|
||||
const AVATAR_HEIGHT = 600;
|
||||
|
||||
|
@ -200,4 +222,5 @@ module.exports = {
|
|||
AVATAR_WIDTH,
|
||||
AVATAR_HEIGHT,
|
||||
TOGETHERAI_KEYS,
|
||||
OLLAMA_KEYS,
|
||||
};
|
||||
|
|
|
@ -4,7 +4,7 @@ const { Readable } = require('stream');
|
|||
|
||||
const { jsonParser } = require('../../express-common');
|
||||
const { CHAT_COMPLETION_SOURCES, GEMINI_SAFETY, BISON_SAFETY } = require('../../constants');
|
||||
const { forwardFetchResponse, getConfigValue, tryParse, uuidv4, color } = require('../../util');
|
||||
const { forwardFetchResponse, getConfigValue, tryParse, uuidv4, mergeObjectWithYaml, excludeKeysByYaml, color } = require('../../util');
|
||||
const { convertClaudePrompt, convertGooglePrompt, convertTextCompletionPrompt } = require('../prompt-converters');
|
||||
|
||||
const { readSecret, SECRET_KEYS } = require('../secrets');
|
||||
|
@ -469,26 +469,30 @@ async function sendMistralAIRequest(request, response) {
|
|||
controller.abort();
|
||||
});
|
||||
|
||||
const requestBody = {
|
||||
'model': request.body.model,
|
||||
'messages': messages,
|
||||
'temperature': request.body.temperature,
|
||||
'top_p': request.body.top_p,
|
||||
'max_tokens': request.body.max_tokens,
|
||||
'stream': request.body.stream,
|
||||
'safe_mode': request.body.safe_mode,
|
||||
'random_seed': request.body.seed === -1 ? undefined : request.body.seed,
|
||||
};
|
||||
|
||||
const config = {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer ' + apiKey,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
'model': request.body.model,
|
||||
'messages': messages,
|
||||
'temperature': request.body.temperature,
|
||||
'top_p': request.body.top_p,
|
||||
'max_tokens': request.body.max_tokens,
|
||||
'stream': request.body.stream,
|
||||
'safe_mode': request.body.safe_mode,
|
||||
'random_seed': request.body.seed === -1 ? undefined : request.body.seed,
|
||||
}),
|
||||
body: JSON.stringify(requestBody),
|
||||
signal: controller.signal,
|
||||
timeout: 0,
|
||||
};
|
||||
|
||||
console.log('MisralAI request:', requestBody);
|
||||
|
||||
const generateResponse = await fetch('https://api.mistral.ai/v1/chat/completions', config);
|
||||
if (request.body.stream) {
|
||||
forwardFetchResponse(generateResponse, response);
|
||||
|
@ -500,6 +504,7 @@ async function sendMistralAIRequest(request, response) {
|
|||
return response.status(generateResponse.status === 401 ? 500 : generateResponse.status).send({ error: true });
|
||||
}
|
||||
const generateResponseJson = await generateResponse.json();
|
||||
console.log('MistralAI response:', generateResponseJson);
|
||||
return response.send(generateResponseJson);
|
||||
}
|
||||
} catch (error) {
|
||||
|
@ -533,12 +538,17 @@ router.post('/status', jsonParser, async function (request, response_getstatus_o
|
|||
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.MISTRALAI) {
|
||||
api_url = 'https://api.mistral.ai/v1';
|
||||
api_key_openai = readSecret(SECRET_KEYS.MISTRALAI);
|
||||
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.CUSTOM) {
|
||||
api_url = request.body.custom_url;
|
||||
api_key_openai = readSecret(SECRET_KEYS.CUSTOM);
|
||||
headers = {};
|
||||
mergeObjectWithYaml(headers, request.body.custom_include_headers);
|
||||
} else {
|
||||
console.log('This chat completion source is not supported yet.');
|
||||
return response_getstatus_openai.status(400).send({ error: true });
|
||||
}
|
||||
|
||||
if (!api_key_openai && !request.body.reverse_proxy) {
|
||||
if (!api_key_openai && !request.body.reverse_proxy && request.body.chat_completion_source !== CHAT_COMPLETION_SOURCES.CUSTOM) {
|
||||
console.log('OpenAI API key is missing.');
|
||||
return response_getstatus_openai.status(400).send({ error: true });
|
||||
}
|
||||
|
@ -688,7 +698,7 @@ router.post('/generate', jsonParser, function (request, response) {
|
|||
let headers;
|
||||
let bodyParams;
|
||||
|
||||
if (request.body.chat_completion_source !== CHAT_COMPLETION_SOURCES.OPENROUTER) {
|
||||
if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.OPENAI) {
|
||||
apiUrl = new URL(request.body.reverse_proxy || API_OPENAI).toString();
|
||||
apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(SECRET_KEYS.OPENAI);
|
||||
headers = {};
|
||||
|
@ -697,7 +707,7 @@ router.post('/generate', jsonParser, function (request, response) {
|
|||
if (getConfigValue('openai.randomizeUserId', false)) {
|
||||
bodyParams['user'] = uuidv4();
|
||||
}
|
||||
} else {
|
||||
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.OPENROUTER) {
|
||||
apiUrl = 'https://openrouter.ai/api/v1';
|
||||
apiKey = readSecret(SECRET_KEYS.OPENROUTER);
|
||||
// OpenRouter needs to pass the referer: https://openrouter.ai/docs
|
||||
|
@ -707,9 +717,19 @@ router.post('/generate', jsonParser, function (request, response) {
|
|||
if (request.body.use_fallback) {
|
||||
bodyParams['route'] = 'fallback';
|
||||
}
|
||||
} else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.CUSTOM) {
|
||||
apiUrl = request.body.custom_url;
|
||||
apiKey = readSecret(SECRET_KEYS.CUSTOM);
|
||||
headers = {};
|
||||
bodyParams = {};
|
||||
mergeObjectWithYaml(bodyParams, request.body.custom_include_body);
|
||||
mergeObjectWithYaml(headers, request.body.custom_include_headers);
|
||||
} else {
|
||||
console.log('This chat completion source is not supported yet.');
|
||||
return response.status(400).send({ error: true });
|
||||
}
|
||||
|
||||
if (!apiKey && !request.body.reverse_proxy) {
|
||||
if (!apiKey && !request.body.reverse_proxy && request.body.chat_completion_source !== CHAT_COMPLETION_SOURCES.CUSTOM) {
|
||||
console.log('OpenAI API key is missing.');
|
||||
return response.status(400).send({ error: true });
|
||||
}
|
||||
|
@ -731,6 +751,27 @@ router.post('/generate', jsonParser, function (request, response) {
|
|||
controller.abort();
|
||||
});
|
||||
|
||||
const requestBody = {
|
||||
'messages': isTextCompletion === false ? request.body.messages : undefined,
|
||||
'prompt': isTextCompletion === true ? textPrompt : undefined,
|
||||
'model': request.body.model,
|
||||
'temperature': request.body.temperature,
|
||||
'max_tokens': request.body.max_tokens,
|
||||
'stream': request.body.stream,
|
||||
'presence_penalty': request.body.presence_penalty,
|
||||
'frequency_penalty': request.body.frequency_penalty,
|
||||
'top_p': request.body.top_p,
|
||||
'top_k': request.body.top_k,
|
||||
'stop': isTextCompletion === false ? request.body.stop : undefined,
|
||||
'logit_bias': request.body.logit_bias,
|
||||
'seed': request.body.seed,
|
||||
...bodyParams,
|
||||
};
|
||||
|
||||
if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.CUSTOM) {
|
||||
excludeKeysByYaml(requestBody, request.body.custom_exclude_body);
|
||||
}
|
||||
|
||||
/** @type {import('node-fetch').RequestInit} */
|
||||
const config = {
|
||||
method: 'post',
|
||||
|
@ -739,27 +780,12 @@ router.post('/generate', jsonParser, function (request, response) {
|
|||
'Authorization': 'Bearer ' + apiKey,
|
||||
...headers,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
'messages': isTextCompletion === false ? request.body.messages : undefined,
|
||||
'prompt': isTextCompletion === true ? textPrompt : undefined,
|
||||
'model': request.body.model,
|
||||
'temperature': request.body.temperature,
|
||||
'max_tokens': request.body.max_tokens,
|
||||
'stream': request.body.stream,
|
||||
'presence_penalty': request.body.presence_penalty,
|
||||
'frequency_penalty': request.body.frequency_penalty,
|
||||
'top_p': request.body.top_p,
|
||||
'top_k': request.body.top_k,
|
||||
'stop': isTextCompletion === false ? request.body.stop : undefined,
|
||||
'logit_bias': request.body.logit_bias,
|
||||
'seed': request.body.seed,
|
||||
...bodyParams,
|
||||
}),
|
||||
body: JSON.stringify(requestBody),
|
||||
signal: controller.signal,
|
||||
timeout: 0,
|
||||
};
|
||||
|
||||
console.log(JSON.parse(String(config.body)));
|
||||
console.log(requestBody);
|
||||
|
||||
makeRequest(config, response, request);
|
||||
|
||||
|
|
|
@ -1,14 +1,62 @@
|
|||
const express = require('express');
|
||||
const fetch = require('node-fetch').default;
|
||||
const _ = require('lodash');
|
||||
const Readable = require('stream').Readable;
|
||||
|
||||
const { jsonParser } = require('../../express-common');
|
||||
const { TEXTGEN_TYPES, TOGETHERAI_KEYS } = require('../../constants');
|
||||
const { TEXTGEN_TYPES, TOGETHERAI_KEYS, OLLAMA_KEYS } = require('../../constants');
|
||||
const { forwardFetchResponse } = require('../../util');
|
||||
const { setAdditionalHeaders } = require('../../additional-headers');
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
/**
|
||||
* Special boy's steaming routine. Wrap this abomination into proper SSE stream.
|
||||
* @param {import('node-fetch').Response} jsonStream JSON stream
|
||||
* @param {import('express').Request} request Express request
|
||||
* @param {import('express').Response} response Express response
|
||||
* @returns {Promise<any>} Nothing valuable
|
||||
*/
|
||||
async function parseOllamaStream(jsonStream, request, response) {
|
||||
try {
|
||||
let partialData = '';
|
||||
jsonStream.body.on('data', (data) => {
|
||||
const chunk = data.toString();
|
||||
partialData += chunk;
|
||||
while (true) {
|
||||
let json;
|
||||
try {
|
||||
json = JSON.parse(partialData);
|
||||
} catch (e) {
|
||||
break;
|
||||
}
|
||||
const text = json.response || '';
|
||||
const chunk = { choices: [{ text }] };
|
||||
response.write(`data: ${JSON.stringify(chunk)}\n\n`);
|
||||
partialData = '';
|
||||
}
|
||||
});
|
||||
|
||||
request.socket.on('close', function () {
|
||||
if (jsonStream.body instanceof Readable) jsonStream.body.destroy();
|
||||
response.end();
|
||||
});
|
||||
|
||||
jsonStream.body.on('end', () => {
|
||||
console.log('Streaming request finished');
|
||||
response.write('data: [DONE]\n\n');
|
||||
response.end();
|
||||
});
|
||||
} catch (error) {
|
||||
console.log('Error forwarding streaming response:', error);
|
||||
if (!response.headersSent) {
|
||||
return response.status(500).send({ error: true });
|
||||
} else {
|
||||
return response.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//************** Ooba/OpenAI text completions API
|
||||
router.post('/status', jsonParser, async function (request, response) {
|
||||
if (!request.body) return response.sendStatus(400);
|
||||
|
@ -39,6 +87,7 @@ router.post('/status', jsonParser, async function (request, response) {
|
|||
case TEXTGEN_TYPES.OOBA:
|
||||
case TEXTGEN_TYPES.APHRODITE:
|
||||
case TEXTGEN_TYPES.KOBOLDCPP:
|
||||
case TEXTGEN_TYPES.LLAMACPP:
|
||||
url += '/v1/models';
|
||||
break;
|
||||
case TEXTGEN_TYPES.MANCER:
|
||||
|
@ -50,6 +99,9 @@ router.post('/status', jsonParser, async function (request, response) {
|
|||
case TEXTGEN_TYPES.TOGETHERAI:
|
||||
url += '/api/models?&info';
|
||||
break;
|
||||
case TEXTGEN_TYPES.OLLAMA:
|
||||
url += '/api/tags';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,6 +124,10 @@ router.post('/status', jsonParser, async function (request, response) {
|
|||
data = { data: data.map(x => ({ id: x.name, ...x })) };
|
||||
}
|
||||
|
||||
if (request.body.api_type === TEXTGEN_TYPES.OLLAMA && Array.isArray(data.models)) {
|
||||
data = { data: data.models.map(x => ({ id: x.name, ...x })) };
|
||||
}
|
||||
|
||||
if (!Array.isArray(data.data)) {
|
||||
console.log('Models response is not an array.');
|
||||
return response.status(400);
|
||||
|
@ -126,8 +182,8 @@ router.post('/status', jsonParser, async function (request, response) {
|
|||
}
|
||||
});
|
||||
|
||||
router.post('/generate', jsonParser, async function (request, response_generate) {
|
||||
if (!request.body) return response_generate.sendStatus(400);
|
||||
router.post('/generate', jsonParser, async function (request, response) {
|
||||
if (!request.body) return response.sendStatus(400);
|
||||
|
||||
try {
|
||||
if (request.body.api_server.indexOf('localhost') !== -1) {
|
||||
|
@ -160,6 +216,12 @@ router.post('/generate', jsonParser, async function (request, response_generate)
|
|||
case TEXTGEN_TYPES.MANCER:
|
||||
url += '/oai/v1/completions';
|
||||
break;
|
||||
case TEXTGEN_TYPES.LLAMACPP:
|
||||
url += '/completion';
|
||||
break;
|
||||
case TEXTGEN_TYPES.OLLAMA:
|
||||
url += '/api/generate';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -182,10 +244,23 @@ router.post('/generate', jsonParser, async function (request, response_generate)
|
|||
args.body = JSON.stringify(request.body);
|
||||
}
|
||||
|
||||
if (request.body.stream) {
|
||||
if (request.body.api_type === TEXTGEN_TYPES.OLLAMA) {
|
||||
args.body = JSON.stringify({
|
||||
model: request.body.model,
|
||||
prompt: request.body.prompt,
|
||||
stream: request.body.stream ?? false,
|
||||
raw: true,
|
||||
options: _.pickBy(request.body, (_, key) => OLLAMA_KEYS.includes(key)),
|
||||
});
|
||||
}
|
||||
|
||||
if (request.body.api_type === TEXTGEN_TYPES.OLLAMA && request.body.stream) {
|
||||
const stream = await fetch(url, args);
|
||||
parseOllamaStream(stream, request, response);
|
||||
} else if (request.body.stream) {
|
||||
const completionsStream = await fetch(url, args);
|
||||
// Pipe remote SSE stream to Express response
|
||||
forwardFetchResponse(completionsStream, response_generate);
|
||||
forwardFetchResponse(completionsStream, response);
|
||||
}
|
||||
else {
|
||||
const completionsReply = await fetch(url, args);
|
||||
|
@ -200,28 +275,154 @@ router.post('/generate', jsonParser, async function (request, response_generate)
|
|||
data['choices'] = [{ text }];
|
||||
}
|
||||
|
||||
return response_generate.send(data);
|
||||
return response.send(data);
|
||||
} else {
|
||||
const text = await completionsReply.text();
|
||||
const errorBody = { error: true, status: completionsReply.status, response: text };
|
||||
|
||||
if (!response_generate.headersSent) {
|
||||
return response_generate.send(errorBody);
|
||||
if (!response.headersSent) {
|
||||
return response.send(errorBody);
|
||||
}
|
||||
|
||||
return response_generate.end();
|
||||
return response.end();
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
let value = { error: true, status: error?.status, response: error?.statusText };
|
||||
console.log('Endpoint error:', error);
|
||||
|
||||
if (!response_generate.headersSent) {
|
||||
return response_generate.send(value);
|
||||
if (!response.headersSent) {
|
||||
return response.send(value);
|
||||
}
|
||||
|
||||
return response_generate.end();
|
||||
return response.end();
|
||||
}
|
||||
});
|
||||
|
||||
const ollama = express.Router();
|
||||
|
||||
ollama.post('/download', jsonParser, async function (request, response) {
|
||||
try {
|
||||
if (!request.body.name || !request.body.api_server) return response.sendStatus(400);
|
||||
|
||||
const name = request.body.name;
|
||||
const url = String(request.body.api_server).replace(/\/$/, '');
|
||||
|
||||
const fetchResponse = await fetch(`${url}/api/pull`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
name: name,
|
||||
stream: false,
|
||||
}),
|
||||
timeout: 0,
|
||||
});
|
||||
|
||||
if (!fetchResponse.ok) {
|
||||
console.log('Download error:', fetchResponse.status, fetchResponse.statusText);
|
||||
return response.status(fetchResponse.status).send({ error: true });
|
||||
}
|
||||
|
||||
return response.send({ ok: true });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return response.status(500);
|
||||
}
|
||||
});
|
||||
|
||||
ollama.post('/caption-image', jsonParser, async function (request, response) {
|
||||
try {
|
||||
if (!request.body.server_url || !request.body.model) {
|
||||
return response.sendStatus(400);
|
||||
}
|
||||
|
||||
console.log('Ollama caption request:', request.body);
|
||||
// Convert to string + remove trailing slash + /v1 suffix
|
||||
const baseUrl = String(request.body.server_url).replace(/\/$/, '').replace(/\/v1$/, '');
|
||||
|
||||
const fetchResponse = await fetch(`${baseUrl}/api/generate`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
model: request.body.model,
|
||||
prompt: request.body.prompt,
|
||||
images: [request.body.image],
|
||||
stream: false,
|
||||
}),
|
||||
timeout: 0,
|
||||
});
|
||||
|
||||
if (!fetchResponse.ok) {
|
||||
console.log('Ollama caption error:', fetchResponse.status, fetchResponse.statusText);
|
||||
return response.status(500).send({ error: true });
|
||||
}
|
||||
|
||||
const data = await fetchResponse.json();
|
||||
console.log('Ollama caption response:', data);
|
||||
|
||||
const caption = data?.response || '';
|
||||
|
||||
if (!caption) {
|
||||
console.log('Ollama caption is empty.');
|
||||
return response.status(500).send({ error: true });
|
||||
}
|
||||
|
||||
return response.send({ caption });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return response.status(500);
|
||||
}
|
||||
});
|
||||
|
||||
const llamacpp = express.Router();
|
||||
|
||||
llamacpp.post('/caption-image', jsonParser, async function (request, response) {
|
||||
try {
|
||||
if (!request.body.server_url) {
|
||||
return response.sendStatus(400);
|
||||
}
|
||||
|
||||
console.log('LlamaCpp caption request:', request.body);
|
||||
// Convert to string + remove trailing slash + /v1 suffix
|
||||
const baseUrl = String(request.body.server_url).replace(/\/$/, '').replace(/\/v1$/, '');
|
||||
|
||||
const fetchResponse = await fetch(`${baseUrl}/completion`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
timeout: 0,
|
||||
body: JSON.stringify({
|
||||
prompt: `USER:[img-1]${String(request.body.prompt).trim()}\nASSISTANT:`,
|
||||
image_data: [{ data: request.body.image, id: 1 }],
|
||||
temperature: 0.1,
|
||||
stream: false,
|
||||
stop: ['USER:', '</s>'],
|
||||
}),
|
||||
});
|
||||
|
||||
if (!fetchResponse.ok) {
|
||||
console.log('LlamaCpp caption error:', fetchResponse.status, fetchResponse.statusText);
|
||||
return response.status(500).send({ error: true });
|
||||
}
|
||||
|
||||
const data = await fetchResponse.json();
|
||||
console.log('LlamaCpp caption response:', data);
|
||||
|
||||
const caption = data?.content || '';
|
||||
|
||||
if (!caption) {
|
||||
console.log('LlamaCpp caption is empty.');
|
||||
return response.status(500).send({ error: true });
|
||||
}
|
||||
|
||||
return response.send({ caption });
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return response.status(500);
|
||||
}
|
||||
});
|
||||
|
||||
router.use('/ollama', ollama);
|
||||
router.use('/llamacpp', llamacpp);
|
||||
|
||||
module.exports = { router };
|
||||
|
|
|
@ -4,13 +4,15 @@ const express = require('express');
|
|||
const FormData = require('form-data');
|
||||
const fs = require('fs');
|
||||
const { jsonParser, urlencodedParser } = require('../express-common');
|
||||
const { getConfigValue } = require('../util');
|
||||
const { getConfigValue, mergeObjectWithYaml, excludeKeysByYaml } = require('../util');
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.post('/caption-image', jsonParser, async (request, response) => {
|
||||
try {
|
||||
let key = '';
|
||||
let headers = {};
|
||||
let bodyParams = {};
|
||||
|
||||
if (request.body.api === 'openai' && !request.body.reverse_proxy) {
|
||||
key = readSecret(SECRET_KEYS.OPENAI);
|
||||
|
@ -24,7 +26,13 @@ router.post('/caption-image', jsonParser, async (request, response) => {
|
|||
key = request.body.proxy_password;
|
||||
}
|
||||
|
||||
if (!key && !request.body.reverse_proxy) {
|
||||
if (request.body.api === 'custom') {
|
||||
key = readSecret(SECRET_KEYS.CUSTOM);
|
||||
mergeObjectWithYaml(bodyParams, request.body.custom_include_body);
|
||||
mergeObjectWithYaml(headers, request.body.custom_include_headers);
|
||||
}
|
||||
|
||||
if (!key && !request.body.reverse_proxy && request.body.api !== 'custom') {
|
||||
console.log('No key found for API', request.body.api);
|
||||
return response.sendStatus(400);
|
||||
}
|
||||
|
@ -41,6 +49,7 @@ router.post('/caption-image', jsonParser, async (request, response) => {
|
|||
},
|
||||
],
|
||||
max_tokens: 500,
|
||||
...bodyParams,
|
||||
};
|
||||
|
||||
const captionSystemPrompt = getConfigValue('openai.captionSystemPrompt');
|
||||
|
@ -51,10 +60,13 @@ router.post('/caption-image', jsonParser, async (request, response) => {
|
|||
});
|
||||
}
|
||||
|
||||
if (request.body.api === 'custom') {
|
||||
excludeKeysByYaml(body, request.body.custom_exclude_body);
|
||||
}
|
||||
|
||||
console.log('Multimodal captioning request', body);
|
||||
|
||||
let apiUrl = '';
|
||||
let headers = {};
|
||||
|
||||
if (request.body.api === 'openrouter') {
|
||||
apiUrl = 'https://openrouter.ai/api/v1/chat/completions';
|
||||
|
@ -69,6 +81,10 @@ router.post('/caption-image', jsonParser, async (request, response) => {
|
|||
apiUrl = `${request.body.reverse_proxy}/chat/completions`;
|
||||
}
|
||||
|
||||
if (request.body.api === 'custom') {
|
||||
apiUrl = `${request.body.server_url}/chat/completions`;
|
||||
}
|
||||
|
||||
const result = await fetch(apiUrl, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
|
|
|
@ -27,6 +27,7 @@ const SECRET_KEYS = {
|
|||
SERPAPI: 'api_key_serpapi',
|
||||
TOGETHERAI: 'api_key_togetherai',
|
||||
MISTRALAI: 'api_key_mistralai',
|
||||
CUSTOM: 'api_key_custom',
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -622,6 +622,10 @@ router.post('/remote/textgenerationwebui/encode', jsonParser, async function (re
|
|||
url += '/api/extra/tokencount';
|
||||
args.body = JSON.stringify({ 'prompt': text });
|
||||
break;
|
||||
case TEXTGEN_TYPES.LLAMACPP:
|
||||
url += '/tokenize';
|
||||
args.body = JSON.stringify({ 'content': text });
|
||||
break;
|
||||
default:
|
||||
url += '/v1/internal/encode';
|
||||
args.body = JSON.stringify({ 'text': text });
|
||||
|
@ -637,7 +641,7 @@ router.post('/remote/textgenerationwebui/encode', jsonParser, async function (re
|
|||
}
|
||||
|
||||
const data = await result.json();
|
||||
const count = legacyApi ? data?.results[0]?.tokens : (data?.length ?? data?.value);
|
||||
const count = legacyApi ? data?.results[0]?.tokens : (data?.length ?? data?.value ?? data?.tokens?.length);
|
||||
const ids = legacyApi ? [] : (data?.tokens ?? data?.ids ?? []);
|
||||
|
||||
return response.send({ count, ids });
|
||||
|
|
61
src/util.js
61
src/util.js
|
@ -399,6 +399,65 @@ function forwardFetchResponse(from, to) {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds YAML-serialized object to the object.
|
||||
* @param {object} obj Object
|
||||
* @param {string} yamlString YAML-serialized object
|
||||
* @returns
|
||||
*/
|
||||
function mergeObjectWithYaml(obj, yamlString) {
|
||||
if (!yamlString) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const parsedObject = yaml.parse(yamlString);
|
||||
|
||||
if (Array.isArray(parsedObject)) {
|
||||
for (const item of parsedObject) {
|
||||
if (typeof item === 'object' && item && !Array.isArray(item)) {
|
||||
Object.assign(obj, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (parsedObject && typeof parsedObject === 'object') {
|
||||
Object.assign(obj, parsedObject);
|
||||
}
|
||||
} catch {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes keys from the object by YAML-serialized array.
|
||||
* @param {object} obj Object
|
||||
* @param {string} yamlString YAML-serialized array
|
||||
* @returns {void} Nothing
|
||||
*/
|
||||
function excludeKeysByYaml(obj, yamlString) {
|
||||
if (!yamlString) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const parsedObject = yaml.parse(yamlString);
|
||||
|
||||
if (Array.isArray(parsedObject)) {
|
||||
parsedObject.forEach(key => {
|
||||
delete obj[key];
|
||||
});
|
||||
} else if (typeof parsedObject === 'object') {
|
||||
Object.keys(parsedObject).forEach(key => {
|
||||
delete obj[key];
|
||||
});
|
||||
} else if (typeof parsedObject === 'string') {
|
||||
delete obj[parsedObject];
|
||||
}
|
||||
} catch {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getConfig,
|
||||
getConfigValue,
|
||||
|
@ -420,4 +479,6 @@ module.exports = {
|
|||
getImages,
|
||||
forwardFetchResponse,
|
||||
getHexString,
|
||||
mergeObjectWithYaml,
|
||||
excludeKeysByYaml,
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue