Skip to content

Commit 0912bff

Browse files
authored
135.0.0 (#636)
# PR Checklist - [ ] Did you check if it works normally in all models? *ignore this when it dosen't uses models* - [ ] Did you check if it works normally in all of web, local and node hosted versions? if it dosen't, did you blocked it in those versions? - [ ] Did you added a type def? # Description
2 parents 1a8ce87 + 92e4aa3 commit 0912bff

19 files changed

+200
-83
lines changed

src-tauri/tauri.conf.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
},
99
"package": {
1010
"productName": "RisuAI",
11-
"version": "134.0.1"
11+
"version": "135.0.0"
1212
},
1313
"tauri": {
1414
"allowlist": {

src/lang/en.ts

+7
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,9 @@ export const languageEnglish = {
161161
,
162162
strictJsonSchema: "If enabled, it will strictly follow the Provided Schema for JSON on some models. if it is disabled, it may ignore the JSON Schema.",
163163
extractJson: "If it is not blank, it will extract specific JSON data from the response. for example, if you want to extract `response.text[0]` in response `{\"response\": {\"text\": [\"hello\"]}}`, you can put `response.text.0`.",
164+
translatorNote: "Here, you can add a unique translation prompt for each character. This option only applies when using the Ax. model for translation. To apply it, include `{{slot::tnote}}` in the language settings. It doesn't work in group chats.",
165+
groupInnerFormat: "This defines a format that is used in group chat for characters that isn't speaker. if it is not blank, it will use this format instead of the default format. if `Group Other Bot Role` is `assistant`, it will also be applied to the speaker.",
166+
groupOtherBotRole: "This defines a role that is used in group chat for characters that isn't speaker.",
164167
},
165168
setup: {
166169
chooseProvider: "Choose AI Provider",
@@ -741,4 +744,8 @@ export const languageEnglish = {
741744
leadingDoubleQuote: "Leading Double Quote",
742745
trailingSingleQuote: "Trailing Single Quote",
743746
trailingDoubleQuote: "Trailing Double Quote",
747+
translatorNote: "Translator's Note",
748+
formatGroupInSingle: "Format Group in Single",
749+
groupInnerFormat: "Non-Speaker Inner Format",
750+
groupOtherBotRole: "Non-Speaker Role in Group",
744751
}

src/lang/ko.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ export const languageKorean = {
9595
"emotionPrompt": "이 옵션은 감정을 감지하는 데 사용되는 프롬프트를 설정하는 데 사용됩니다. 비어 있으면 기본 프롬프트를 사용합니다.",
9696
"removePunctuationHypa": "활성화되면 HypaMemory를 실행하기 전에 구두점을 제거합니다.",
9797
"defaultVariables": "여기에서는 기본 변수를 정의할 수 있습니다. `<변수 이름>=<변수 값>` 형식으로 작성하고 개행으로 구분합니다. 예를 들어, `name=RisuAI`는 트리거 스크립트 및 변수 CBS와 함께 `{{getvar::A}}`, `{{setvar::A::B}}` 또는 `{{? $A + 1}}`과 같이 사용할 수 있습니다. 프롬프트 템플릿의 기본 변수와 캐릭터의 기본 변수가 동일한 이름을 가진 경우 캐릭터의 기본 변수가 사용됩니다.",
98-
"combineTranslation": "활성화된 경우, 한 문장이지만 HTML 태그로 분리된 텍스트를 모두 합쳐서 번역한 후, 번역된 결과에 다시 디스플레이 수정 스크립트를 적용합니다.\n이를 통해 번역기가 올바른 번역을 하도록 도와줍니다.\n이 옵션을 활성화하고 UI가 이상해지면 옵션을 끄고 제보해 주세요."
98+
"combineTranslation": "활성화된 경우, 한 문장이지만 HTML 태그로 분리된 텍스트를 모두 합쳐서 번역한 후, 번역된 결과에 다시 디스플레이 수정 스크립트를 적용합니다.\n이를 통해 번역기가 올바른 번역을 하도록 도와줍니다.\n이 옵션을 활성화하고 UI가 이상해지면 옵션을 끄고 제보해 주세요.",
99+
"translatorNote": "여기에서 캐릭터마다 별도의 번역 프롬프트를 넣을 수 있습니다. 해당 옵션은 Ax. model 번역을 사용할 때만 적용됩니다. 언어 설정에서 `{{slot::tnote}}`를 넣으세요. 그룹챗에서는 작동하지 않습니다.",
99100
},
100101
"setup": {
101102
"chooseProvider": "AI 제공자를 선택해 주세요",
@@ -587,5 +588,6 @@ export const languageKorean = {
587588
"supaDesc": "수파메모리는 요약을 사용하는 장기기억 시스템입니다.",
588589
"hanuraiDesc": "하느라이메모리는 벡터 검색을 사용하는 장기기억 시스템입니다.",
589590
"v2Warning": "주의: V2 카드는 더 이상 지원되지 않습니다. 일부 데이터가 누락될 수 있습니다.",
590-
591+
"translatorNote": "번역가의 노트",
592+
591593
}

src/lib/Setting/Pages/PromptSettings.svelte

+11-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
import NumberInput from "src/lib/UI/GUI/NumberInput.svelte";
1111
import Help from "src/lib/Others/Help.svelte";
1212
import TextAreaInput from "src/lib/UI/GUI/TextAreaInput.svelte";
13+
import SelectInput from "src/lib/UI/GUI/SelectInput.svelte";
14+
import OptionInput from "src/lib/UI/GUI/OptionInput.svelte";
1315
1416
let sorted = 0
1517
let opened = 0
@@ -112,7 +114,7 @@
112114
<TextInput bind:value={$DataBase.promptSettings.postEndInnerFormat}/>
113115

114116
<Check bind:check={$DataBase.promptSettings.sendChatAsSystem} name={language.sendChatAsSystem} className="mt-4"/>
115-
<Check bind:check={$DataBase.promptSettings.sendName} name={language.sendName} className="mt-4"/>
117+
<Check bind:check={$DataBase.promptSettings.sendName} name={language.formatGroupInSingle} className="mt-4"/>
116118
<Check bind:check={$DataBase.promptSettings.utilOverride} name={language.utilOverride} className="mt-4"/>
117119
<Check bind:check={$DataBase.jsonSchemaEnabled} name={language.enableJsonSchema} className="mt-4"/>
118120
<Check bind:check={$DataBase.strictJsonSchema} name={language.strictJsonSchema} className="mt-4"/>
@@ -124,10 +126,18 @@
124126
{/if}
125127
<span class="text-textcolor mt-4">{language.maxThoughtTagDepth}</span>
126128
<NumberInput bind:value={$DataBase.promptSettings.maxThoughtTagDepth}/>
129+
<span class="text-textcolor mt-4">{language.groupOtherBotRole} <Help key="groupOtherBotRole"/></span>
130+
<SelectInput bind:value={$DataBase.groupOtherBotRole}>
131+
<OptionInput value="user">User</OptionInput>
132+
<OptionInput value="system">System</OptionInput>
133+
<OptionInput value="assistant">assistant</OptionInput>
134+
</SelectInput>
127135
<span class="text-textcolor mt-4">{language.customPromptTemplateToggle} <Help key='customPromptTemplateToggle' /></span>
128136
<TextAreaInput bind:value={$DataBase.customPromptTemplateToggle}/>
129137
<span class="text-textcolor mt-4">{language.defaultVariables} <Help key='defaultVariables' /></span>
130138
<TextAreaInput bind:value={$DataBase.templateDefaultVariables}/>
139+
<span class="text-textcolor mt-4">{language.groupInnerFormat} <Help key='groupInnerFormat' /></span>
140+
<TextAreaInput placeholder={`<{{char}}\'s Message>\n{{slot}}\n</{{char}}\'s Message>`} bind:value={$DataBase.groupTemplate}/>
131141
{#if $DataBase.jsonSchemaEnabled}
132142
<span class="text-textcolor mt-4">{language.jsonSchema} <Help key='jsonSchema' /></span>
133143
<TextAreaInput bind:value={$DataBase.jsonSchema}/>

src/lib/SideBars/CharConfig.svelte

+3
Original file line numberDiff line numberDiff line change
@@ -921,6 +921,9 @@
921921
<span class="text-textcolor mt-2">{language.defaultVariables} <Help key="defaultVariables" /></span>
922922
<TextAreaInput margin="both" autocomplete="off" bind:value={currentChar.data.defaultVariables}></TextAreaInput>
923923

924+
<span class="text-textcolor mt-2">{language.translatorNote} <Help key="translatorNote" /></span>
925+
<TextAreaInput margin="both" autocomplete="off" bind:value={currentChar.data.translatorNote}></TextAreaInput>
926+
924927
<span class="text-textcolor">{language.creator}</span>
925928
<TextInput size="sm" autocomplete="off" bind:value={currentChar.data.additionalData.creator} />
926929

src/lib/UI/GUI/NumberInput.svelte

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
export let marginBottom = false
3535
export let fullwidth = false
3636
export let fullh = false
37-
export let onChange:ChangeEventHandler<HTMLInputElement>
37+
export let onChange:ChangeEventHandler<HTMLInputElement> = () => {}
3838
export let className = ''
3939
export let disabled = false
4040
</script>

src/lib/UI/GUI/TextAreaInput.svelte

+9-10
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
>
4141
{#if !highlight}
4242
<textarea
43-
class="w-full h-full bg-transparent focus-within:outline-none resize-none absolute top-0 left-0 z-10 overflow-y-auto"
43+
class="w-full h-full bg-transparent focus-within:outline-none resize-none absolute top-0 left-0 z-50 overflow-y-auto"
4444
class:px-4={padding}
4545
class:py-2={padding}
4646
{autocomplete}
@@ -69,7 +69,7 @@
6969
/>
7070
{:else if isFirefox}
7171
<div
72-
class="w-full h-full bg-transparent focus-within:outline-none resize-none absolute top-0 left-0 z-10 overflow-y-auto px-4 py-2 break-words whitespace-pre-wrap"
72+
class="w-full h-full bg-transparent focus-within:outline-none resize-none absolute top-0 left-0 z-50 overflow-y-auto px-4 py-2 break-words whitespace-pre-wrap"
7373
contenteditable="true"
7474
bind:textContent={value}
7575
on:keydown={(e) => {
@@ -91,9 +91,9 @@
9191
>{value ?? ''}</div>
9292
{:else}
9393
<div
94-
class="w-full h-full bg-transparent focus-within:outline-none resize-none absolute top-0 left-0 z-10 overflow-y-auto px-4 py-2 break-words whitespace-pre-wrap"
94+
class="w-full h-full bg-transparent focus-within:outline-none resize-none absolute top-0 left-0 z-50 overflow-y-auto px-4 py-2 break-words whitespace-pre-wrap"
9595
contenteditable="plaintext-only"
96-
bind:textContent={value}
96+
bind:innerText={value}
9797
on:keydown={(e) => {
9898
handleKeyDown(e)
9999
onInput()
@@ -132,7 +132,7 @@
132132
export let className = ''
133133
export let optimaizedInput = true
134134
export let highlight = false
135-
let selectingAutoComplete = -1
135+
let selectingAutoComplete = 0
136136
let highlightId = highlight ? getNewHighlightId() : 0
137137
let inpa = 0
138138
let highlightDom: HTMLDivElement
@@ -146,7 +146,7 @@
146146
return
147147
}
148148
//autocomplete
149-
selectingAutoComplete = -1
149+
selectingAutoComplete = 0
150150
const sel = window.getSelection()
151151
if(!sel){
152152
return
@@ -185,6 +185,7 @@
185185
}
186186
187187
const insertContent = (insertContent:string, type:'autoComplete'|'paste' = 'autoComplete') => {
188+
console.log(insertContent)
188189
const sel = window.getSelection()
189190
if(sel){
190191
const range = sel.getRangeAt(0)
@@ -222,7 +223,7 @@
222223
223224
const hideAutoComplete = () => {
224225
autoCompleteDom.style.display = 'none'
225-
selectingAutoComplete = -1
226+
selectingAutoComplete = 0
226227
autocompleteContents = []
227228
}
228229
@@ -253,9 +254,7 @@
253254
case 'Enter':
254255
case 'Tab':
255256
e.preventDefault()
256-
if(selectingAutoComplete !== -1){
257-
insertContent(autocompleteContents[selectingAutoComplete])
258-
}
257+
insertContent(autocompleteContents[selectingAutoComplete])
259258
return
260259
case 'Escape':
261260
hideAutoComplete()

src/lib/UI/ModelList.svelte

+1
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@
107107
</Arcodion>
108108
<Arcodion name="Google Gemini">
109109
<button class="hover:bg-selected px-6 py-2 text-lg" on:click={() => {changeModel('gemini-1.5-pro-exp-0827')}}>Gemini Pro 1.5 0827</button>
110+
<button class="hover:bg-selected px-6 py-2 text-lg" on:click={() => {changeModel('gemini-1.5-pro-002')}}>Gemini Pro 1.5 002</button>
110111
<button class="hover:bg-selected px-6 py-2 text-lg" on:click={() => {changeModel('gemini-1.5-pro-latest')}}>Gemini Pro 1.5</button>
111112
<button class="hover:bg-selected px-6 py-2 text-lg" on:click={() => {changeModel('gemini-1.5-flash')}}>Gemini Flash 1.5</button>
112113
<button class="hover:bg-selected px-6 py-2 text-lg" on:click={() => {changeModel('gemini-pro')}}>Gemini Pro</button>

src/ts/characterCards.ts

+42-2
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,43 @@ export async function characterURLImport() {
415415
function convertOffSpecCards(charaData:OldTavernChar|CharacterCardV2Risu, imgp:string|undefined = undefined):character{
416416
const data = charaData.spec_version === '2.0' ? charaData.data : charaData
417417
console.log("Off spec detected, converting")
418+
const charbook = charaData.spec_version === '2.0' ? charaData.data.character_book : null
419+
let lorebook:loreBook[] = []
420+
let loresettings:undefined|loreSettings = undefined
421+
let loreExt:undefined|any = undefined
422+
if(charbook){
423+
if((!checkNullish(charbook.recursive_scanning)) &&
424+
(!checkNullish(charbook.scan_depth)) &&
425+
(!checkNullish(charbook.token_budget))){
426+
loresettings = {
427+
tokenBudget:charbook.token_budget,
428+
scanDepth:charbook.scan_depth,
429+
recursiveScanning: charbook.recursive_scanning,
430+
fullWordMatching: charbook?.extensions?.risu_fullWordMatching ?? false,
431+
}
432+
}
433+
434+
loreExt = charbook.extensions
435+
436+
for(const book of charbook.entries){
437+
lorebook.push({
438+
key: book.keys.join(', '),
439+
secondkey: book.secondary_keys?.join(', ') ?? '',
440+
insertorder: book.insertion_order,
441+
comment: book.name ?? book.comment ?? "",
442+
content: book.content,
443+
mode: "normal",
444+
alwaysActive: book.constant ?? false,
445+
selective: book.selective ?? false,
446+
extentions: {...book.extensions, risu_case_sensitive: book.case_sensitive},
447+
activationPercent: book.extensions?.risu_activationPercent,
448+
loreCache: book.extensions?.risu_loreCache ?? null,
449+
//@ts-ignore
450+
useRegex: book.use_regex ?? false
451+
})
452+
}
453+
}
454+
418455
return {
419456
name: data.name ?? 'unknown name',
420457
firstMessage: data.first_mes ?? 'unknown first message',
@@ -430,7 +467,7 @@ function convertOffSpecCards(charaData:OldTavernChar|CharacterCardV2Risu, imgp:s
430467
image: imgp,
431468
emotionImages: [],
432469
bias: [],
433-
globalLore: [],
470+
globalLore: lorebook,
434471
viewScreen: 'none',
435472
chaId: uuidv4(),
436473
sdData: defaultSdDataFunc(),
@@ -449,7 +486,10 @@ function convertOffSpecCards(charaData:OldTavernChar|CharacterCardV2Risu, imgp:s
449486
firstMsgIndex: -1,
450487
replaceGlobalNote: "",
451488
triggerscript: [],
452-
additionalText: ''
489+
additionalText: '',
490+
loreExt: loreExt,
491+
loreSettings: loresettings,
492+
453493
}
454494
}
455495

src/ts/characters.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,8 @@ export async function importChat(){
343343
message: [],
344344
note: "",
345345
name: "Imported Chat",
346-
localLore: []
346+
localLore: [],
347+
fmIndex: -1
347348
}
348349

349350
let isFirst = true
@@ -376,6 +377,7 @@ export async function importChat(){
376377
if(json.type === 'risuChat' && json.ver === 1){
377378
const das:Chat = json.data
378379
if(!(checkNullish(das.message) || checkNullish(das.note) || checkNullish(das.name) || checkNullish(das.localLore))){
380+
das.fmIndex ??= -1
379381
db.characters[selectedID].chats.unshift(das)
380382
setDatabase(db)
381383
alertNormal(language.successImport)

src/ts/gui/highlight.ts

+48-43
Original file line numberDiff line numberDiff line change
@@ -5,48 +5,53 @@ type HighlightInt = [Range, HighlightType]
55
let highLights = new Map<number, HighlightInt[]>();
66

77
export const highlighter = (highlightDom:HTMLElement, id:number) => {
8-
if(highlightDom){
9-
if(!CSS.highlights){
10-
return
11-
}
12-
13-
const walker = document.createTreeWalker(highlightDom, NodeFilter.SHOW_TEXT)
14-
const nodes:Node[] = []
15-
let currentNode = walker.nextNode();
16-
while (currentNode) {
17-
nodes.push(currentNode);
18-
currentNode = walker.nextNode();
19-
}
20-
const str = "{{char}}"
21-
if (!str) {
22-
return;
23-
}
24-
25-
const ranges:HighlightInt[] = []
26-
27-
nodes.map((el) => {
28-
const text = el.textContent.toLowerCase()
29-
30-
const cbsParsed = simpleCBSHighlightParser(el,text)
31-
ranges.push(...cbsParsed)
32-
33-
for(const syntax of highlighterSyntax){
34-
const regex = syntax.regex
35-
let match:RegExpExecArray | null;
36-
while ((match = regex.exec(text)) !== null) {
37-
const length = match[0].length;
38-
const index = match.index;
39-
const range = new Range();
40-
range.setStart(el, index);
41-
range.setEnd(el, index + length);
42-
ranges.push([range, syntax.type])
43-
}
8+
try {
9+
10+
if(highlightDom){
11+
if(!CSS.highlights){
12+
return
4413
}
45-
});
46-
47-
highLights.set(id, ranges)
48-
49-
runHighlight()
14+
15+
const walker = document.createTreeWalker(highlightDom, NodeFilter.SHOW_TEXT)
16+
const nodes:Node[] = []
17+
let currentNode = walker.nextNode();
18+
while (currentNode) {
19+
nodes.push(currentNode);
20+
currentNode = walker.nextNode();
21+
}
22+
const str = "{{char}}"
23+
if (!str) {
24+
return;
25+
}
26+
27+
const ranges:HighlightInt[] = []
28+
29+
nodes.map((el) => {
30+
const text = el.textContent.toLowerCase()
31+
32+
const cbsParsed = simpleCBSHighlightParser(el,text)
33+
ranges.push(...cbsParsed)
34+
35+
for(const syntax of highlighterSyntax){
36+
const regex = syntax.regex
37+
let match:RegExpExecArray | null;
38+
while ((match = regex.exec(text)) !== null) {
39+
const length = match[0].length;
40+
const index = match.index;
41+
const range = new Range();
42+
range.setStart(el, index);
43+
range.setEnd(el, index + length);
44+
ranges.push([range, syntax.type])
45+
}
46+
}
47+
});
48+
49+
highLights.set(id, ranges)
50+
51+
runHighlight()
52+
}
53+
} catch (error) {
54+
5055
}
5156
}
5257

@@ -131,9 +136,9 @@ const deprecatedDecorators = [
131136
'end', 'assistant', 'user', 'system'
132137
]
133138

134-
export const AllCBS = [...normalCBS, ...(normalCBSwithParams.map((v) => {
139+
export const AllCBS = [...normalCBS, ...(normalCBSwithParams.concat(displayRelatedCBS).map((v) => {
135140
return v + ':'
136-
})), ...displayRelatedCBS, ...nestedCBS]
141+
})), ...nestedCBS]
137142

138143
const highlighterSyntax = [
139144
{

0 commit comments

Comments
 (0)