feat: add doNotSummarizeUserMessage option for HypaV3 and improve HypaV3 modal (#750)
# PR Checklist - [x] Have you checked if it works normally in all models? *Ignore this if it doesn't use models.* - [x] Have you checked if it works normally in all web, local, and node hosted versions? If it doesn't, have you blocked it in those versions? - [x] Have you added type definitions? # Description This PR introduces following: - Add doNotSummarizeUserMessage option to exclude user messages from summarization - Add early return logic to prevent unnecessary similarity checks when summaries are empty - Add length check before summarization - Set to default settings when selecting HypaV3 on OtherBotSettings - Add localization for HypaV3 settings and modal - Change HypaV3 modal title - Add import summary filtering and improve search in HypaV3
This commit is contained in:
@@ -770,5 +770,50 @@ export const languageChinese = {
|
|||||||
"translatorPrompt": "翻译提示词",
|
"translatorPrompt": "翻译提示词",
|
||||||
"translateBeforeHTMLFormatting": "於 HTML 格式化前翻译",
|
"translateBeforeHTMLFormatting": "於 HTML 格式化前翻译",
|
||||||
"retranslate": "重新翻译",
|
"retranslate": "重新翻译",
|
||||||
"loading": "加载中"
|
"loading": "加载中",
|
||||||
}
|
"hypaV3Settings": {
|
||||||
|
"descriptionLabel": "HypaMemory V3 是一个使用总结和向量搜索的长期记忆系统。",
|
||||||
|
"supaMemoryPromptPlaceHolder": "留空以使用默认值",
|
||||||
|
"maxMemoryTokensRatioLabel": "最大记忆令牌比率(估计)",
|
||||||
|
"maxMemoryTokensRatioError": "无法计算最大记忆令牌比率",
|
||||||
|
"memoryTokensRatioLabel": "记忆令牌比率",
|
||||||
|
"extraSummarizationRatioLabel": "额外总结比率",
|
||||||
|
"maxChatsPerSummaryLabel": "每个总结的最大消息数",
|
||||||
|
"recentMemoryRatioLabel": "最近记忆比率",
|
||||||
|
"similarMemoryRatioLabel": "相似记忆比率",
|
||||||
|
"randomMemoryRatioLabel": "随机记忆比率",
|
||||||
|
"enableSimilarityCorrectionLabel": "启用相似度校正",
|
||||||
|
"preserveOrphanedMemoryLabel": "保留孤立记忆",
|
||||||
|
"applyRegexScriptWhenRerollingLabel": "重新生成时应用正则脚本",
|
||||||
|
"doNotSummarizeUserMessageLabel": "不要总结用户消息",
|
||||||
|
},
|
||||||
|
"hypaV3Modal": {
|
||||||
|
"titleLabel": "HypaV3",
|
||||||
|
"resetConfirmMessage": "此操作无法撤销。您要重置 HypaV3 数据吗?",
|
||||||
|
"resetConfirmSecondMessage": "此操作不可逆。您确实要重置 HypaV3 数据吗?",
|
||||||
|
"convertLabel": "尚无总结,但您可以将 HypaV2 数据转换为 V3。",
|
||||||
|
"convertButton": "转换为 V3",
|
||||||
|
"convertSuccessMessage": "成功将 HypaV2 数据转换为 V3",
|
||||||
|
"convertErrorMessage": "将 HypaV2 数据转换为 V3 失败:{0}",
|
||||||
|
"noSummariesLabel": "尚无总结",
|
||||||
|
"searchPlaceholder": "输入 #N、ID 或搜索关键词",
|
||||||
|
"summaryNumberLabel": "总结 #{0}",
|
||||||
|
"deleteAfterConfirmMessage": "删除此后的所有总结?",
|
||||||
|
"deleteAfterConfirmSecondMessage": "此操作无法撤销。您确定吗?",
|
||||||
|
"translationLabel": "翻译",
|
||||||
|
"rerolledSummaryLabel": "重新生成的总结",
|
||||||
|
"rerolledTranslationLabel": "重新生成的总结翻译",
|
||||||
|
"connectedMessageCountLabel": "关联消息 ({0})",
|
||||||
|
"connectedFirstMessageLabel": "第一条消息",
|
||||||
|
"connectedMessageRoleLabel": "{0} 的消息",
|
||||||
|
"connectedMessageNotFoundLabel": "未找到消息",
|
||||||
|
"connectedMessageLoadingError": "加载关联消息时出错:{0}",
|
||||||
|
"connectedMessageTranslationLabel": "翻译",
|
||||||
|
"nextSummarizationFirstMessageLabel": "第一条消息",
|
||||||
|
"nextSummarizationNoMessageIdLabel": "无消息 ID",
|
||||||
|
"nextSummarizationLabel": "HypaV3 将总结 [{0}]",
|
||||||
|
"nextSummarizationNoMessagesFoundLabel": "警告:未找到消息",
|
||||||
|
"nextSummarizationLoadingError": "加载下一个总结目标时出错:{0}",
|
||||||
|
"emptySelectedFirstMessageLabel": "警告:所选的第一条消息为空"
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|||||||
@@ -435,4 +435,49 @@ export const languageGerman = {
|
|||||||
appendNameNAI: "Namen an NAI anhängen",
|
appendNameNAI: "Namen an NAI anhängen",
|
||||||
customStopWords: "Benutzerdefinierte Stoppwörter",
|
customStopWords: "Benutzerdefinierte Stoppwörter",
|
||||||
useAdvancedEditor: "Erweiterten Editor verwenden",
|
useAdvancedEditor: "Erweiterten Editor verwenden",
|
||||||
|
"hypaV3Settings": {
|
||||||
|
"descriptionLabel": "HypaMemory V3 ist ein Langzeitgedächtnissystem, das sowohl Zusammenfassung als auch Vektorsuche verwendet.",
|
||||||
|
"supaMemoryPromptPlaceHolder": "Leer lassen für Standardeinstellung",
|
||||||
|
"maxMemoryTokensRatioLabel": "Maximales Gedächtnis-Token-Verhältnis (Geschätzt)",
|
||||||
|
"maxMemoryTokensRatioError": "Maximales Gedächtnis-Token-Verhältnis kann nicht berechnet werden",
|
||||||
|
"memoryTokensRatioLabel": "Gedächtnis-Token-Verhältnis",
|
||||||
|
"extraSummarizationRatioLabel": "Zusätzliches Zusammenfassungsverhältnis",
|
||||||
|
"maxChatsPerSummaryLabel": "Maximale Nachrichten pro Zusammenfassung",
|
||||||
|
"recentMemoryRatioLabel": "Verhältnis der jüngsten Erinnerungen",
|
||||||
|
"similarMemoryRatioLabel": "Verhältnis ähnlicher Erinnerungen",
|
||||||
|
"randomMemoryRatioLabel": "Verhältnis zufälliger Erinnerungen",
|
||||||
|
"enableSimilarityCorrectionLabel": "Ähnlichkeitskorrektur aktivieren",
|
||||||
|
"preserveOrphanedMemoryLabel": "Verwaiste Erinnerungen bewahren",
|
||||||
|
"applyRegexScriptWhenRerollingLabel": "Regex-Skript beim Neugenerieren anwenden",
|
||||||
|
"doNotSummarizeUserMessageLabel": "Benutzernachrichten nicht zusammenfassen",
|
||||||
|
},
|
||||||
|
"hypaV3Modal": {
|
||||||
|
"titleLabel": "HypaV3",
|
||||||
|
"resetConfirmMessage": "Diese Aktion kann nicht rückgängig gemacht werden. Möchten Sie die HypaV3-Daten zurücksetzen?",
|
||||||
|
"resetConfirmSecondMessage": "Diese Aktion ist unwiderruflich. Möchten Sie die HypaV3-Daten wirklich zurücksetzen?",
|
||||||
|
"convertLabel": "Noch keine Zusammenfassungen, aber Sie können HypaV2-Daten zu V3 konvertieren.",
|
||||||
|
"convertButton": "Zu V3 konvertieren",
|
||||||
|
"convertSuccessMessage": "HypaV2-Daten erfolgreich zu V3 konvertiert",
|
||||||
|
"convertErrorMessage": "Konvertierung von HypaV2 zu V3 fehlgeschlagen: {0}",
|
||||||
|
"noSummariesLabel": "Noch keine Zusammenfassungen",
|
||||||
|
"searchPlaceholder": "Geben Sie #N, ID oder Suchanfrage ein",
|
||||||
|
"summaryNumberLabel": "Zusammenfassung #{0}",
|
||||||
|
"deleteAfterConfirmMessage": "Alle Zusammenfassungen nach dieser löschen?",
|
||||||
|
"deleteAfterConfirmSecondMessage": "Diese Aktion kann nicht rückgängig gemacht werden. Sind Sie wirklich sicher?",
|
||||||
|
"translationLabel": "Übersetzung",
|
||||||
|
"rerolledSummaryLabel": "Neu generierte Zusammenfassung",
|
||||||
|
"rerolledTranslationLabel": "Übersetzung der neu generierten Zusammenfassung",
|
||||||
|
"connectedMessageCountLabel": "Verbundene Nachrichten ({0})",
|
||||||
|
"connectedFirstMessageLabel": "Erste Nachricht",
|
||||||
|
"connectedMessageRoleLabel": "Nachricht von {0}",
|
||||||
|
"connectedMessageNotFoundLabel": "Nachricht nicht gefunden",
|
||||||
|
"connectedMessageLoadingError": "Fehler beim Laden der verbundenen Nachricht: {0}",
|
||||||
|
"connectedMessageTranslationLabel": "Übersetzung",
|
||||||
|
"nextSummarizationFirstMessageLabel": "Erste Nachricht",
|
||||||
|
"nextSummarizationNoMessageIdLabel": "Keine Nachrichten-ID",
|
||||||
|
"nextSummarizationLabel": "HypaV3 wird [{0}] zusammenfassen",
|
||||||
|
"nextSummarizationNoMessagesFoundLabel": "WARNUNG: Keine Nachrichten gefunden",
|
||||||
|
"nextSummarizationLoadingError": "Fehler beim Laden des nächsten Zusammenfassungsziels: {0}",
|
||||||
|
"emptySelectedFirstMessageLabel": "WARNUNG: Ausgewählte erste Nachricht ist leer"
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -841,6 +841,50 @@ export const languageEnglish = {
|
|||||||
banCharacterset: 'Auto Regenerate On Characterset',
|
banCharacterset: 'Auto Regenerate On Characterset',
|
||||||
checkCorruption: "Check Corruption",
|
checkCorruption: "Check Corruption",
|
||||||
showPromptComparison: "Show Prompt Comparison",
|
showPromptComparison: "Show Prompt Comparison",
|
||||||
hypaV3Desc: "HypaMemory V3 is a long-term memory system that use both summarized data and vector search.",
|
|
||||||
inlayErrorResponse: "Inlay Error Response",
|
inlayErrorResponse: "Inlay Error Response",
|
||||||
|
hypaV3Settings: {
|
||||||
|
descriptionLabel: "HypaMemory V3 is a long-term memory system that uses both summarization and vector search.",
|
||||||
|
supaMemoryPromptPlaceHolder: "Leave it blank to use default",
|
||||||
|
maxMemoryTokensRatioLabel: "Max Memory Tokens Ratio (Estimated)",
|
||||||
|
maxMemoryTokensRatioError: "Unable to calculate Max Memory Tokens Ratio",
|
||||||
|
memoryTokensRatioLabel: "Memory Tokens Ratio",
|
||||||
|
extraSummarizationRatioLabel: "Extra Summarization Ratio",
|
||||||
|
maxChatsPerSummaryLabel: "Max Messages Per Summary",
|
||||||
|
recentMemoryRatioLabel: "Recent Memory Ratio",
|
||||||
|
similarMemoryRatioLabel: "Similar Memory Ratio",
|
||||||
|
randomMemoryRatioLabel: "Random Memory Ratio",
|
||||||
|
enableSimilarityCorrectionLabel: "Enable Similarity Correction",
|
||||||
|
preserveOrphanedMemoryLabel: "Preserve Orphaned Memory",
|
||||||
|
applyRegexScriptWhenRerollingLabel: "Apply Regex Script When Rerolling",
|
||||||
|
doNotSummarizeUserMessageLabel: "Do Not Summarize User Message",
|
||||||
|
},
|
||||||
|
hypaV3Modal: {
|
||||||
|
titleLabel: "HypaV3",
|
||||||
|
resetConfirmMessage: "This action cannot be undone. Do you want to reset HypaV3 data?",
|
||||||
|
resetConfirmSecondMessage: "This action is irreversible. Do you really, really want to reset HypaV3 data?",
|
||||||
|
convertLabel: "No summaries yet, but you may convert HypaV2 data to V3.",
|
||||||
|
convertButton: "Convert to V3",
|
||||||
|
convertSuccessMessage: "Successfully converted HypaV2 data to V3",
|
||||||
|
convertErrorMessage: "Failed to convert HypaV2 data to V3: {0}",
|
||||||
|
noSummariesLabel: "No summaries yet",
|
||||||
|
searchPlaceholder: "Enter #N, ID, or query",
|
||||||
|
summaryNumberLabel: "Summary #{0}",
|
||||||
|
deleteAfterConfirmMessage: "Delete all summaries after this one?",
|
||||||
|
deleteAfterConfirmSecondMessage: "This action cannot be undone. Are you really sure?",
|
||||||
|
translationLabel: "Translation",
|
||||||
|
rerolledSummaryLabel: "Rerolled Summary",
|
||||||
|
rerolledTranslationLabel: "Rerolled Summary Translation",
|
||||||
|
connectedMessageCountLabel: "Connected Messages ({0})",
|
||||||
|
connectedFirstMessageLabel: "First Message",
|
||||||
|
connectedMessageRoleLabel: "{0}'s Message",
|
||||||
|
connectedMessageNotFoundLabel: "Message not found",
|
||||||
|
connectedMessageLoadingError: "Error loading connected message: {0}",
|
||||||
|
connectedMessageTranslationLabel: "Translation",
|
||||||
|
nextSummarizationFirstMessageLabel: "First Message",
|
||||||
|
nextSummarizationNoMessageIdLabel: "No Message ID",
|
||||||
|
nextSummarizationLabel: "HypaV3 will summarize [{0}]",
|
||||||
|
nextSummarizationNoMessagesFoundLabel: "WARN: No messages found",
|
||||||
|
nextSummarizationLoadingError: "Error loading next summarization target: {0}",
|
||||||
|
emptySelectedFirstMessageLabel: "WARN: Selected first message is empty",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
@@ -680,4 +680,49 @@ export const languageSpanish = {
|
|||||||
parameters: "Parámetros",
|
parameters: "Parámetros",
|
||||||
sizeAndSpeed: "Tamaño y Velocidad",
|
sizeAndSpeed: "Tamaño y Velocidad",
|
||||||
useLegacyGUI: "Usar Interfaz Legacy",
|
useLegacyGUI: "Usar Interfaz Legacy",
|
||||||
|
"hypaV3Settings": {
|
||||||
|
"descriptionLabel": "HypaMemory V3 es un sistema de memoria a largo plazo que utiliza tanto resúmenes como búsqueda vectorial.",
|
||||||
|
"supaMemoryPromptPlaceHolder": "Dejar en blanco para usar el valor predeterminado",
|
||||||
|
"maxMemoryTokensRatioLabel": "Ratio Máximo de Tokens de Memoria (Estimado)",
|
||||||
|
"maxMemoryTokensRatioError": "No se puede calcular el ratio máximo de tokens de memoria",
|
||||||
|
"memoryTokensRatioLabel": "Ratio de Tokens de Memoria",
|
||||||
|
"extraSummarizationRatioLabel": "Ratio de Resumen Adicional",
|
||||||
|
"maxChatsPerSummaryLabel": "Mensajes Máximos por Resumen",
|
||||||
|
"recentMemoryRatioLabel": "Ratio de Memoria Reciente",
|
||||||
|
"similarMemoryRatioLabel": "Ratio de Memoria Similar",
|
||||||
|
"randomMemoryRatioLabel": "Ratio de Memoria Aleatoria",
|
||||||
|
"enableSimilarityCorrectionLabel": "Activar Corrección de Similitud",
|
||||||
|
"preserveOrphanedMemoryLabel": "Preservar Memoria Huérfana",
|
||||||
|
"applyRegexScriptWhenRerollingLabel": "Aplicar Script Regex al Regenerar",
|
||||||
|
"doNotSummarizeUserMessageLabel": "No Resumir Mensajes del Usuario",
|
||||||
|
},
|
||||||
|
"hypaV3Modal": {
|
||||||
|
"titleLabel": "HypaV3",
|
||||||
|
"resetConfirmMessage": "Esta acción no se puede deshacer. ¿Desea restablecer los datos de HypaV3?",
|
||||||
|
"resetConfirmSecondMessage": "Esta acción es irreversible. ¿Está realmente seguro de querer restablecer los datos de HypaV3?",
|
||||||
|
"convertLabel": "Aún no hay resúmenes, pero puede convertir datos de HypaV2 a V3.",
|
||||||
|
"convertButton": "Convertir a V3",
|
||||||
|
"convertSuccessMessage": "Datos de HypaV2 convertidos exitosamente a V3",
|
||||||
|
"convertErrorMessage": "Error al convertir datos de HypaV2 a V3: {0}",
|
||||||
|
"noSummariesLabel": "Aún no hay resúmenes",
|
||||||
|
"searchPlaceholder": "Ingrese #N, ID o búsqueda",
|
||||||
|
"summaryNumberLabel": "Resumen #{0}",
|
||||||
|
"deleteAfterConfirmMessage": "¿Eliminar todos los resúmenes después de este?",
|
||||||
|
"deleteAfterConfirmSecondMessage": "Esta acción no se puede deshacer. ¿Está realmente seguro?",
|
||||||
|
"translationLabel": "Traducción",
|
||||||
|
"rerolledSummaryLabel": "Resumen Regenerado",
|
||||||
|
"rerolledTranslationLabel": "Traducción del Resumen Regenerado",
|
||||||
|
"connectedMessageCountLabel": "Mensajes Conectados ({0})",
|
||||||
|
"connectedFirstMessageLabel": "Primer Mensaje",
|
||||||
|
"connectedMessageRoleLabel": "Mensaje de {0}",
|
||||||
|
"connectedMessageNotFoundLabel": "Mensaje no encontrado",
|
||||||
|
"connectedMessageLoadingError": "Error al cargar mensaje conectado: {0}",
|
||||||
|
"connectedMessageTranslationLabel": "Traducción",
|
||||||
|
"nextSummarizationFirstMessageLabel": "Primer Mensaje",
|
||||||
|
"nextSummarizationNoMessageIdLabel": "Sin ID de Mensaje",
|
||||||
|
"nextSummarizationLabel": "HypaV3 resumirá [{0}]",
|
||||||
|
"nextSummarizationNoMessagesFoundLabel": "ADVERTENCIA: No se encontraron mensajes",
|
||||||
|
"nextSummarizationLoadingError": "Error al cargar el siguiente objetivo de resumen: {0}",
|
||||||
|
"emptySelectedFirstMessageLabel": "ADVERTENCIA: El primer mensaje seleccionado está vacío"
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -767,4 +767,49 @@ export const languageKorean = {
|
|||||||
"translateBeforeHTMLFormatting": "HTML 포맷 전 번역",
|
"translateBeforeHTMLFormatting": "HTML 포맷 전 번역",
|
||||||
"retranslate": "다시 번역",
|
"retranslate": "다시 번역",
|
||||||
"loading": "로딩중",
|
"loading": "로딩중",
|
||||||
|
"hypaV3Settings": {
|
||||||
|
"descriptionLabel": "HypaMemory V3는 요약과 벡터 검색을 모두 사용하는 장기 기억 시스템입니다.",
|
||||||
|
"supaMemoryPromptPlaceHolder": "기본값을 사용하려면 비워두세요",
|
||||||
|
"maxMemoryTokensRatioLabel": "최대 메모리 토큰 비율 (추정)",
|
||||||
|
"maxMemoryTokensRatioError": "최대 메모리 토큰 비율을 계산할 수 없습니다",
|
||||||
|
"memoryTokensRatioLabel": "메모리 토큰 비율",
|
||||||
|
"extraSummarizationRatioLabel": "추가 요약 비율",
|
||||||
|
"maxChatsPerSummaryLabel": "요약당 최대 메시지 수",
|
||||||
|
"recentMemoryRatioLabel": "최근 메모리 비율",
|
||||||
|
"similarMemoryRatioLabel": "유사 메모리 비율",
|
||||||
|
"randomMemoryRatioLabel": "무작위 메모리 비율",
|
||||||
|
"enableSimilarityCorrectionLabel": "유사도 보정 활성화",
|
||||||
|
"preserveOrphanedMemoryLabel": "고아 메모리 보존",
|
||||||
|
"applyRegexScriptWhenRerollingLabel": "재생성 시 정규식 스크립트 적용",
|
||||||
|
"doNotSummarizeUserMessageLabel": "유저 메시지 요약하지 않기",
|
||||||
|
},
|
||||||
|
"hypaV3Modal": {
|
||||||
|
"titleLabel": "HypaV3",
|
||||||
|
"resetConfirmMessage": "이 작업은 되돌릴 수 없습니다. HypaV3 데이터를 초기화하시겠습니까?",
|
||||||
|
"resetConfirmSecondMessage": "이 작업은 복구할 수 없습니다. 정말로, 정말로 HypaV3 데이터를 초기화하시겠습니까?",
|
||||||
|
"convertLabel": "아직 요약이 없지만, HypaV2 데이터를 V3로 변환할 수 있습니다.",
|
||||||
|
"convertButton": "V3로 변환",
|
||||||
|
"convertSuccessMessage": "HypaV2 데이터를 V3로 성공적으로 변환했습니다",
|
||||||
|
"convertErrorMessage": "HypaV2 데이터를 V3로 변환하는데 실패했습니다: {0}",
|
||||||
|
"noSummariesLabel": "아직 요약이 없습니다",
|
||||||
|
"searchPlaceholder": "#N, ID 또는 검색어 입력",
|
||||||
|
"summaryNumberLabel": "요약 #{0}",
|
||||||
|
"deleteAfterConfirmMessage": "이 요약 이후의 모든 요약을 삭제하시겠습니까?",
|
||||||
|
"deleteAfterConfirmSecondMessage": "이 작업은 되돌릴 수 없습니다. 정말 삭제하시겠습니까?",
|
||||||
|
"translationLabel": "번역",
|
||||||
|
"rerolledSummaryLabel": "재생성된 요약",
|
||||||
|
"rerolledTranslationLabel": "재생성된 요약 번역",
|
||||||
|
"connectedMessageCountLabel": "연결된 메시지 ({0})",
|
||||||
|
"connectedFirstMessageLabel": "첫 메시지",
|
||||||
|
"connectedMessageRoleLabel": "{0}의 메시지",
|
||||||
|
"connectedMessageNotFoundLabel": "메시지를 찾을 수 없습니다",
|
||||||
|
"connectedMessageLoadingError": "연결된 메시지를 불러오는 동안 오류 발생: {0}",
|
||||||
|
"connectedMessageTranslationLabel": "번역",
|
||||||
|
"nextSummarizationFirstMessageLabel": "첫 메시지",
|
||||||
|
"nextSummarizationNoMessageIdLabel": "메시지 ID 없음",
|
||||||
|
"nextSummarizationLabel": "HypaV3가 [{0}]를 요약할 예정입니다",
|
||||||
|
"nextSummarizationNoMessagesFoundLabel": "경고: 메시지를 찾을 수 없습니다",
|
||||||
|
"nextSummarizationLoadingError": "다음 요약 대상을 불러오는 동안 오류 발생: {0}",
|
||||||
|
"emptySelectedFirstMessageLabel": "경고: 선택된 첫 메시지가 비어있습니다"
|
||||||
|
},
|
||||||
}
|
}
|
||||||
@@ -409,4 +409,49 @@ export const LanguageVietnamese = {
|
|||||||
module: "Mô-đun",
|
module: "Mô-đun",
|
||||||
modules: "Mô-đun",
|
modules: "Mô-đun",
|
||||||
useAdvancedEditor: "Sử dụng trình biên tập nâng cao",
|
useAdvancedEditor: "Sử dụng trình biên tập nâng cao",
|
||||||
|
"hypaV3Settings": {
|
||||||
|
"descriptionLabel": "HypaMemory V3 là hệ thống bộ nhớ dài hạn sử dụng cả tóm tắt và tìm kiếm vector.",
|
||||||
|
"supaMemoryPromptPlaceHolder": "Để trống để sử dụng giá trị mặc định",
|
||||||
|
"maxMemoryTokensRatioLabel": "Tỷ lệ Token Bộ nhớ Tối đa (Ước tính)",
|
||||||
|
"maxMemoryTokensRatioError": "Không thể tính toán Tỷ lệ Token Bộ nhớ Tối đa",
|
||||||
|
"memoryTokensRatioLabel": "Tỷ lệ Token Bộ nhớ",
|
||||||
|
"extraSummarizationRatioLabel": "Tỷ lệ Tóm tắt Bổ sung",
|
||||||
|
"maxChatsPerSummaryLabel": "Số Tin nhắn Tối đa cho mỗi Tóm tắt",
|
||||||
|
"recentMemoryRatioLabel": "Tỷ lệ Bộ nhớ Gần đây",
|
||||||
|
"similarMemoryRatioLabel": "Tỷ lệ Bộ nhớ Tương tự",
|
||||||
|
"randomMemoryRatioLabel": "Tỷ lệ Bộ nhớ Ngẫu nhiên",
|
||||||
|
"enableSimilarityCorrectionLabel": "Bật Hiệu chỉnh Độ tương tự",
|
||||||
|
"preserveOrphanedMemoryLabel": "Giữ Bộ nhớ Mồ côi",
|
||||||
|
"applyRegexScriptWhenRerollingLabel": "Áp dụng Script Regex khi Tạo lại",
|
||||||
|
"doNotSummarizeUserMessageLabel": "Không Tóm tắt Tin nhắn Người dùng",
|
||||||
|
},
|
||||||
|
"hypaV3Modal": {
|
||||||
|
"titleLabel": "HypaV3",
|
||||||
|
"resetConfirmMessage": "Hành động này không thể hoàn tác. Bạn có muốn đặt lại dữ liệu HypaV3 không?",
|
||||||
|
"resetConfirmSecondMessage": "Hành động này không thể khôi phục. Bạn có thực sự chắc chắn muốn đặt lại dữ liệu HypaV3 không?",
|
||||||
|
"convertLabel": "Chưa có tóm tắt nào, nhưng bạn có thể chuyển đổi dữ liệu HypaV2 sang V3.",
|
||||||
|
"convertButton": "Chuyển đổi sang V3",
|
||||||
|
"convertSuccessMessage": "Đã chuyển đổi thành công dữ liệu HypaV2 sang V3",
|
||||||
|
"convertErrorMessage": "Chuyển đổi dữ liệu HypaV2 sang V3 thất bại: {0}",
|
||||||
|
"noSummariesLabel": "Chưa có tóm tắt nào",
|
||||||
|
"searchPlaceholder": "Nhập #N, ID hoặc từ khóa",
|
||||||
|
"summaryNumberLabel": "Tóm tắt #{0}",
|
||||||
|
"deleteAfterConfirmMessage": "Xóa tất cả các tóm tắt sau tóm tắt này?",
|
||||||
|
"deleteAfterConfirmSecondMessage": "Hành động này không thể hoàn tác. Bạn có chắc chắn không?",
|
||||||
|
"translationLabel": "Bản dịch",
|
||||||
|
"rerolledSummaryLabel": "Tóm tắt đã Tạo lại",
|
||||||
|
"rerolledTranslationLabel": "Bản dịch Tóm tắt đã Tạo lại",
|
||||||
|
"connectedMessageCountLabel": "Tin nhắn Liên kết ({0})",
|
||||||
|
"connectedFirstMessageLabel": "Tin nhắn Đầu tiên",
|
||||||
|
"connectedMessageRoleLabel": "Tin nhắn của {0}",
|
||||||
|
"connectedMessageNotFoundLabel": "Không tìm thấy tin nhắn",
|
||||||
|
"connectedMessageLoadingError": "Lỗi khi tải tin nhắn liên kết: {0}",
|
||||||
|
"connectedMessageTranslationLabel": "Bản dịch",
|
||||||
|
"nextSummarizationFirstMessageLabel": "Tin nhắn Đầu tiên",
|
||||||
|
"nextSummarizationNoMessageIdLabel": "Không có ID Tin nhắn",
|
||||||
|
"nextSummarizationLabel": "HypaV3 sẽ tóm tắt [{0}]",
|
||||||
|
"nextSummarizationNoMessagesFoundLabel": "CẢNH BÁO: Không tìm thấy tin nhắn",
|
||||||
|
"nextSummarizationLoadingError": "Lỗi khi tải mục tiêu tóm tắt tiếp theo: {0}",
|
||||||
|
"emptySelectedFirstMessageLabel": "CẢNH BÁO: Tin nhắn đầu tiên được chọn trống"
|
||||||
|
},
|
||||||
}
|
}
|
||||||
@@ -802,7 +802,51 @@ export const languageChineseTraditional = {
|
|||||||
"banCharacterset": "自動重新生成字符集",
|
"banCharacterset": "自動重新生成字符集",
|
||||||
"checkCorruption": "檢查損壞",
|
"checkCorruption": "檢查損壞",
|
||||||
"showPromptComparison": "顯示提示比較",
|
"showPromptComparison": "顯示提示比較",
|
||||||
"hypaV3Desc": "HypaMemory V3 是一個長期記憶系統,使用摘要資料和向量搜尋。",
|
|
||||||
"inlayErrorResponse": "嵌入錯誤回應",
|
"inlayErrorResponse": "嵌入錯誤回應",
|
||||||
"APIPool": "API 工具"
|
"APIPool": "API 工具",
|
||||||
|
"hypaV3Settings": {
|
||||||
|
"descriptionLabel": "HypaMemory V3 是一個使用摘要和向量搜索的長期記憶系統。",
|
||||||
|
"supaMemoryPromptPlaceHolder": "留空以使用預設值",
|
||||||
|
"maxMemoryTokensRatioLabel": "最大記憶標記比率(估計)",
|
||||||
|
"maxMemoryTokensRatioError": "無法計算最大記憶標記比率",
|
||||||
|
"memoryTokensRatioLabel": "記憶標記比率",
|
||||||
|
"extraSummarizationRatioLabel": "額外摘要比率",
|
||||||
|
"maxChatsPerSummaryLabel": "每個摘要的最大訊息數",
|
||||||
|
"recentMemoryRatioLabel": "最近記憶比率",
|
||||||
|
"similarMemoryRatioLabel": "相似記憶比率",
|
||||||
|
"randomMemoryRatioLabel": "隨機記憶比率",
|
||||||
|
"enableSimilarityCorrectionLabel": "啟用相似度校正",
|
||||||
|
"preserveOrphanedMemoryLabel": "保留孤立記憶",
|
||||||
|
"applyRegexScriptWhenRerollingLabel": "重新生成時應用正則表達式腳本",
|
||||||
|
"doNotSummarizeUserMessageLabel": "不要摘要用戶訊息"
|
||||||
|
},
|
||||||
|
"hypaV3Modal": {
|
||||||
|
"titleLabel": "HypaV3 數據",
|
||||||
|
"resetConfirmMessage": "此操作無法撤銷。您要重置 HypaV3 數據嗎?",
|
||||||
|
"resetConfirmSecondMessage": "此操作不可逆。您真的確定要重置 HypaV3 數據嗎?",
|
||||||
|
"convertLabel": "尚無摘要,但您可以將 HypaV2 數據轉換為 V3。",
|
||||||
|
"convertButton": "轉換為 V3",
|
||||||
|
"convertSuccessMessage": "成功將 HypaV2 數據轉換為 V3",
|
||||||
|
"convertErrorMessage": "無法將 HypaV2 數據轉換為 V3:{0}",
|
||||||
|
"noSummariesLabel": "尚無摘要",
|
||||||
|
"searchPlaceholder": "輸入 #N、ID 或搜尋關鍵字",
|
||||||
|
"summaryNumberLabel": "摘要 #{0}",
|
||||||
|
"deleteAfterConfirmMessage": "刪除此摘要之後的所有摘要?",
|
||||||
|
"deleteAfterConfirmSecondMessage": "此操作無法撤銷。您確定要這樣做嗎?",
|
||||||
|
"translationLabel": "翻譯",
|
||||||
|
"rerolledSummaryLabel": "重新生成的摘要",
|
||||||
|
"rerolledTranslationLabel": "重新生成的摘要翻譯",
|
||||||
|
"connectedMessageCountLabel": "關聯訊息({0})",
|
||||||
|
"connectedFirstMessageLabel": "第一條訊息",
|
||||||
|
"connectedMessageRoleLabel": "{0} 的訊息",
|
||||||
|
"connectedMessageNotFoundLabel": "找不到訊息",
|
||||||
|
"connectedMessageLoadingError": "載入關聯訊息時出錯:{0}",
|
||||||
|
"connectedMessageTranslationLabel": "翻譯",
|
||||||
|
"nextSummarizationFirstMessageLabel": "第一條訊息",
|
||||||
|
"nextSummarizationNoMessageIdLabel": "無訊息 ID",
|
||||||
|
"nextSummarizationLabel": "HypaV3 將摘要 [{0}]",
|
||||||
|
"nextSummarizationNoMessagesFoundLabel": "警告:找不到訊息",
|
||||||
|
"nextSummarizationLoadingError": "載入下一個摘要目標時出錯:{0}",
|
||||||
|
"emptySelectedFirstMessageLabel": "警告:選定的第一條訊息為空"
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
SettingsIcon,
|
SettingsIcon,
|
||||||
Trash2Icon,
|
Trash2Icon,
|
||||||
XIcon,
|
XIcon,
|
||||||
|
ChevronUpIcon,
|
||||||
|
ChevronDownIcon,
|
||||||
LanguagesIcon,
|
LanguagesIcon,
|
||||||
StarIcon,
|
StarIcon,
|
||||||
RefreshCw,
|
RefreshCw,
|
||||||
@@ -28,6 +30,7 @@
|
|||||||
import { summarize } from "../../ts/process/memory/hypav3";
|
import { summarize } from "../../ts/process/memory/hypav3";
|
||||||
import { type Message } from "../../ts/storage/database.svelte";
|
import { type Message } from "../../ts/storage/database.svelte";
|
||||||
import { translateHTML } from "../../ts/translator/translator";
|
import { translateHTML } from "../../ts/translator/translator";
|
||||||
|
import { language } from "../../lang";
|
||||||
|
|
||||||
interface SummaryUI {
|
interface SummaryUI {
|
||||||
originalRef: HTMLTextAreaElement;
|
originalRef: HTMLTextAreaElement;
|
||||||
@@ -50,20 +53,30 @@
|
|||||||
translationRef: HTMLTextAreaElement;
|
translationRef: HTMLTextAreaElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SearchResult {
|
class SummarySearchResult {
|
||||||
element: HTMLElement;
|
constructor(
|
||||||
matchType: "chatMemo" | "summary";
|
public summaryIndex: number,
|
||||||
summaryPosition?: {
|
public start: number,
|
||||||
start: number;
|
public end: number
|
||||||
end: number;
|
) {}
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ChatMemoSearchResult {
|
||||||
|
constructor(
|
||||||
|
public summaryIndex: number,
|
||||||
|
public memoIndex: number
|
||||||
|
) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
type SearchResult = SummarySearchResult | ChatMemoSearchResult;
|
||||||
|
|
||||||
interface SearchUI {
|
interface SearchUI {
|
||||||
ref: HTMLInputElement;
|
ref: HTMLInputElement;
|
||||||
query: string;
|
query: string;
|
||||||
currentIndex: number;
|
|
||||||
results: SearchResult[];
|
results: SearchResult[];
|
||||||
|
currentResultIndex: number;
|
||||||
|
requestedSearchFromIndex: number;
|
||||||
|
isNavigating: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const hypaV3DataState = $derived(
|
const hypaV3DataState = $derived(
|
||||||
@@ -75,6 +88,7 @@
|
|||||||
let summaryUIStates = $state<SummaryUI[]>([]);
|
let summaryUIStates = $state<SummaryUI[]>([]);
|
||||||
let expandedMessageUIState = $state<ExpandedMessageUI>(null);
|
let expandedMessageUIState = $state<ExpandedMessageUI>(null);
|
||||||
let searchUIState = $state<SearchUI>(null);
|
let searchUIState = $state<SearchUI>(null);
|
||||||
|
let showImportantOnly = $state(false);
|
||||||
|
|
||||||
$effect.pre(() => {
|
$effect.pre(() => {
|
||||||
summaryUIStates = hypaV3DataState.summaries.map((summary) => ({
|
summaryUIStates = hypaV3DataState.summaries.map((summary) => ({
|
||||||
@@ -110,8 +124,10 @@
|
|||||||
searchUIState = {
|
searchUIState = {
|
||||||
ref: null,
|
ref: null,
|
||||||
query: "",
|
query: "",
|
||||||
currentIndex: -1,
|
|
||||||
results: [],
|
results: [],
|
||||||
|
currentResultIndex: -1,
|
||||||
|
requestedSearchFromIndex: -1,
|
||||||
|
isNavigating: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Focus on search element after it's rendered
|
// Focus on search element after it's rendered
|
||||||
@@ -134,122 +150,187 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (e.key === "Enter") {
|
if (e.key === "Enter") {
|
||||||
e.preventDefault(); // Prevent event default action
|
e.preventDefault?.(); // Prevent event default action
|
||||||
|
|
||||||
const query = searchUIState.query.trim();
|
const query = searchUIState.query.trim();
|
||||||
|
|
||||||
if (!query) return;
|
if (!query) return;
|
||||||
|
|
||||||
|
// When received a new query
|
||||||
|
if (searchUIState.currentResultIndex === -1) {
|
||||||
|
const results = generateSearchResults(query);
|
||||||
|
|
||||||
|
if (results.length === 0) return;
|
||||||
|
|
||||||
|
searchUIState.results = results;
|
||||||
|
}
|
||||||
|
|
||||||
|
const nextResult = getNextSearchResult(e.shiftKey);
|
||||||
|
|
||||||
|
if (nextResult) {
|
||||||
|
navigateToSearchResult(nextResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateSearchResults(query: string): SearchResult[] {
|
||||||
|
const results: SearchResult[] = [];
|
||||||
|
const normalizedQuery = query.trim().toLowerCase();
|
||||||
|
|
||||||
// Search summary index
|
// Search summary index
|
||||||
if (query.match(/^#\d+$/)) {
|
if (query.match(/^#\d+$/)) {
|
||||||
const summaryNumber = parseInt(query.substring(1)) - 1;
|
const summaryNumber = parseInt(query.substring(1)) - 1;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
summaryNumber >= 0 &&
|
summaryNumber >= 0 &&
|
||||||
summaryNumber < hypaV3DataState.summaries.length
|
summaryNumber < hypaV3DataState.summaries.length &&
|
||||||
|
(!showImportantOnly ||
|
||||||
|
hypaV3DataState.summaries[summaryNumber].isImportant)
|
||||||
) {
|
) {
|
||||||
summaryUIStates[summaryNumber].originalRef.scrollIntoView({
|
results.push(new SummarySearchResult(summaryNumber, 0, 0));
|
||||||
behavior: "instant",
|
|
||||||
block: "center",
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
const normalizedQuery = query.toLowerCase();
|
|
||||||
|
|
||||||
if (searchUIState.currentIndex === -1) {
|
|
||||||
const results: SearchResult[] = [];
|
|
||||||
|
|
||||||
if (isGuidLike(query)) {
|
if (isGuidLike(query)) {
|
||||||
// Search chatMemo
|
// Search chatMemo
|
||||||
summaryUIStates.forEach((summaryUI) => {
|
summaryUIStates.forEach((summaryUI, summaryIndex) => {
|
||||||
summaryUI.chatMemoRefs.forEach((buttonRef) => {
|
if (
|
||||||
|
!showImportantOnly ||
|
||||||
|
hypaV3DataState.summaries[summaryIndex].isImportant
|
||||||
|
) {
|
||||||
|
summaryUI.chatMemoRefs.forEach((buttonRef, memoIndex) => {
|
||||||
const buttonText = buttonRef.textContent?.toLowerCase() || "";
|
const buttonText = buttonRef.textContent?.toLowerCase() || "";
|
||||||
|
|
||||||
if (buttonText.includes(normalizedQuery)) {
|
if (buttonText.includes(normalizedQuery)) {
|
||||||
results.push({
|
results.push(new ChatMemoSearchResult(summaryIndex, memoIndex));
|
||||||
element: buttonRef as HTMLButtonElement,
|
|
||||||
matchType: "chatMemo",
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Search summary
|
// Search summary
|
||||||
summaryUIStates.forEach((summaryUI) => {
|
summaryUIStates.forEach((summaryUI, summaryIndex) => {
|
||||||
|
if (
|
||||||
|
!showImportantOnly ||
|
||||||
|
hypaV3DataState.summaries[summaryIndex].isImportant
|
||||||
|
) {
|
||||||
const textAreaText = summaryUI.originalRef.value?.toLowerCase();
|
const textAreaText = summaryUI.originalRef.value?.toLowerCase();
|
||||||
|
|
||||||
let pos = -1;
|
let pos = -1;
|
||||||
|
|
||||||
while (
|
while (
|
||||||
(pos = textAreaText.indexOf(normalizedQuery, pos + 1)) !== -1
|
(pos = textAreaText.indexOf(normalizedQuery, pos + 1)) !== -1
|
||||||
) {
|
) {
|
||||||
results.push({
|
results.push(
|
||||||
element: summaryUI.originalRef as HTMLTextAreaElement,
|
new SummarySearchResult(
|
||||||
matchType: "summary",
|
summaryIndex,
|
||||||
summaryPosition: {
|
pos,
|
||||||
start: pos,
|
pos + normalizedQuery.length
|
||||||
end: pos + normalizedQuery.length,
|
)
|
||||||
},
|
);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
searchUIState.results = results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (searchUIState.results.length === 0) return;
|
function isGuidLike(str: string): boolean {
|
||||||
|
const strTrimed = str.trim();
|
||||||
|
|
||||||
// Move to next result
|
// Exclude too short inputs
|
||||||
searchUIState.currentIndex =
|
if (strTrimed.length < 4) return false;
|
||||||
(searchUIState.currentIndex + 1) % searchUIState.results.length;
|
|
||||||
|
|
||||||
const result = searchUIState.results[searchUIState.currentIndex];
|
return /^[0-9a-f]{4,12}(-[0-9a-f]{4,12}){0,4}-?$/i.test(strTrimed);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNextSearchResult(backward: boolean): SearchResult | null {
|
||||||
|
if (!searchUIState || searchUIState.results.length === 0) return null;
|
||||||
|
|
||||||
|
let nextIndex: number;
|
||||||
|
|
||||||
|
if (searchUIState.requestedSearchFromIndex !== -1) {
|
||||||
|
const fromSummaryIndex = searchUIState.requestedSearchFromIndex;
|
||||||
|
|
||||||
|
nextIndex = backward
|
||||||
|
? searchUIState.results.findLastIndex(
|
||||||
|
(r) => r.summaryIndex <= fromSummaryIndex
|
||||||
|
)
|
||||||
|
: searchUIState.results.findIndex(
|
||||||
|
(r) => r.summaryIndex >= fromSummaryIndex
|
||||||
|
);
|
||||||
|
|
||||||
|
if (nextIndex === -1) {
|
||||||
|
nextIndex = backward ? searchUIState.results.length - 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
searchUIState.requestedSearchFromIndex = -1;
|
||||||
|
} else {
|
||||||
|
const delta = backward ? -1 : 1;
|
||||||
|
|
||||||
|
nextIndex =
|
||||||
|
(searchUIState.currentResultIndex +
|
||||||
|
delta +
|
||||||
|
searchUIState.results.length) %
|
||||||
|
searchUIState.results.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
searchUIState.currentResultIndex = nextIndex;
|
||||||
|
return searchUIState.results[nextIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
function navigateToSearchResult(result: SearchResult) {
|
||||||
|
searchUIState.isNavigating = true;
|
||||||
|
|
||||||
|
if (result instanceof SummarySearchResult) {
|
||||||
|
const textarea = summaryUIStates[result.summaryIndex].originalRef;
|
||||||
|
|
||||||
// Scroll to element
|
// Scroll to element
|
||||||
result.element.scrollIntoView({
|
textarea.scrollIntoView({
|
||||||
behavior: "instant",
|
behavior: "instant",
|
||||||
block: "center",
|
block: "center",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result.matchType === "chatMemo") {
|
if (result.start === result.end) {
|
||||||
// Highlight chatMemo result
|
return;
|
||||||
result.element.classList.add("ring-2", "ring-zinc-500");
|
}
|
||||||
|
|
||||||
// Remove highlight after a short delay
|
// Scroll to query
|
||||||
window.setTimeout(() => {
|
textarea.setSelectionRange(result.start, result.end);
|
||||||
result.element.classList.remove("ring-2", "ring-zinc-500");
|
|
||||||
}, 1000);
|
|
||||||
} else {
|
|
||||||
// Handle summary text selection
|
|
||||||
const textarea = result.element as HTMLTextAreaElement;
|
|
||||||
|
|
||||||
// Make readonly temporarily
|
|
||||||
textarea.readOnly = true;
|
|
||||||
|
|
||||||
// Select query
|
|
||||||
textarea.setSelectionRange(
|
|
||||||
result.summaryPosition.start,
|
|
||||||
result.summaryPosition.end
|
|
||||||
);
|
|
||||||
|
|
||||||
textarea.focus();
|
|
||||||
scrollToSelection(textarea);
|
scrollToSelection(textarea);
|
||||||
|
|
||||||
// This only works on firefox
|
// Highlight query on desktop environment
|
||||||
//textarea.scrollTop = textarea.scrollHeight; // Scroll to the bottom
|
if (!("ontouchend" in window)) {
|
||||||
//textarea.blur(); // Collapse selection
|
// Make readonly temporarily
|
||||||
//textarea.focus(); // This scrolls the textarea
|
textarea.readOnly = true;
|
||||||
|
textarea.focus();
|
||||||
// Highlight textarea
|
|
||||||
window.setTimeout(() => {
|
window.setTimeout(() => {
|
||||||
searchUIState.ref.focus(); // Restore focus to search bar
|
searchUIState.ref.focus(); // Restore focus to search bar
|
||||||
textarea.readOnly = false; // Remove readonly after focus moved
|
textarea.readOnly = false; // Remove readonly after focus moved
|
||||||
}, 300);
|
}, 300);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
const button =
|
||||||
|
summaryUIStates[result.summaryIndex].chatMemoRefs[result.memoIndex];
|
||||||
|
|
||||||
|
// Scroll to element
|
||||||
|
button.scrollIntoView({
|
||||||
|
behavior: "instant",
|
||||||
|
block: "center",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Highlight chatMemo
|
||||||
|
button.classList.add("ring-2", "ring-zinc-500");
|
||||||
|
|
||||||
|
// Remove highlight after a short delay
|
||||||
|
window.setTimeout(() => {
|
||||||
|
button.classList.remove("ring-2", "ring-zinc-500");
|
||||||
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
searchUIState.isNavigating = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function scrollToSelection(textarea: HTMLTextAreaElement) {
|
function scrollToSelection(textarea: HTMLTextAreaElement) {
|
||||||
@@ -286,15 +367,6 @@
|
|||||||
textarea.scrollTop = selectionTop - textarea.clientHeight / 2;
|
textarea.scrollTop = selectionTop - textarea.clientHeight / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isGuidLike(str: string): boolean {
|
|
||||||
const strTrimed = str.trim();
|
|
||||||
|
|
||||||
// Exclude too short inputs
|
|
||||||
if (strTrimed.length < 4) return false;
|
|
||||||
|
|
||||||
return /^[0-9a-f]{4,12}(-[0-9a-f]{4,12}){0,4}-?$/i.test(strTrimed);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function toggleTranslate(
|
async function toggleTranslate(
|
||||||
summaryIndex: number,
|
summaryIndex: number,
|
||||||
regenerate?: boolean
|
regenerate?: boolean
|
||||||
@@ -759,21 +831,42 @@
|
|||||||
<div class="flex justify-between items-center mb-2 sm:mb-4">
|
<div class="flex justify-between items-center mb-2 sm:mb-4">
|
||||||
<!-- Modal Title -->
|
<!-- Modal Title -->
|
||||||
<h1 class="text-lg sm:text-2xl font-semibold text-zinc-300">
|
<h1 class="text-lg sm:text-2xl font-semibold text-zinc-300">
|
||||||
HypaV3 Data
|
{language.hypaV3Modal.titleLabel}
|
||||||
</h1>
|
</h1>
|
||||||
<!-- Buttons Container -->
|
<!-- Buttons Container -->
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<!-- Search Button -->
|
<!-- Search Button -->
|
||||||
<button
|
<button
|
||||||
class="p-2 text-zinc-400 hover:text-zinc-200 transition-colors"
|
class="p-2 text-zinc-400 hover:text-zinc-200 transition-colors"
|
||||||
|
tabindex="-1"
|
||||||
onclick={async () => toggleSearch()}
|
onclick={async () => toggleSearch()}
|
||||||
>
|
>
|
||||||
<SearchIcon class="w-6 h-6" />
|
<SearchIcon class="w-6 h-6" />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<!-- Filter Important Summary Button -->
|
||||||
|
<button
|
||||||
|
class="p-2 transition-colors {showImportantOnly
|
||||||
|
? 'text-yellow-400 hover:text-yellow-300'
|
||||||
|
: 'text-zinc-400 hover:text-zinc-200'}"
|
||||||
|
tabindex="-1"
|
||||||
|
onclick={() => {
|
||||||
|
if (searchUIState) {
|
||||||
|
searchUIState.query = "";
|
||||||
|
searchUIState.results = [];
|
||||||
|
searchUIState.currentResultIndex = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
showImportantOnly = !showImportantOnly;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<StarIcon class="w-6 h-6" />
|
||||||
|
</button>
|
||||||
|
|
||||||
<!-- Settings Button -->
|
<!-- Settings Button -->
|
||||||
<button
|
<button
|
||||||
class="p-2 text-zinc-400 hover:text-zinc-200 transition-colors"
|
class="p-2 text-zinc-400 hover:text-zinc-200 transition-colors"
|
||||||
|
tabindex="-1"
|
||||||
onclick={() => {
|
onclick={() => {
|
||||||
alertStore.set({
|
alertStore.set({
|
||||||
type: "none",
|
type: "none",
|
||||||
@@ -790,11 +883,12 @@
|
|||||||
<!-- Reset Button -->
|
<!-- Reset Button -->
|
||||||
<button
|
<button
|
||||||
class="p-2 text-zinc-400 hover:text-rose-300 transition-colors"
|
class="p-2 text-zinc-400 hover:text-rose-300 transition-colors"
|
||||||
|
tabindex="-1"
|
||||||
onclick={async () => {
|
onclick={async () => {
|
||||||
if (
|
if (
|
||||||
await alertConfirmTwice(
|
await alertConfirmTwice(
|
||||||
"This action cannot be undone. Do you want to reset HypaV3 data?",
|
language.hypaV3Modal.resetConfirmMessage,
|
||||||
"This action is irreversible. Do you really, really want to reset HypaV3 data?"
|
language.hypaV3Modal.resetConfirmSecondMessage
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
DBState.db.characters[$selectedCharID].chats[
|
DBState.db.characters[$selectedCharID].chats[
|
||||||
@@ -814,6 +908,7 @@
|
|||||||
<!-- Close Button -->
|
<!-- Close Button -->
|
||||||
<button
|
<button
|
||||||
class="p-2 text-zinc-400 hover:text-zinc-200 transition-colors"
|
class="p-2 text-zinc-400 hover:text-zinc-200 transition-colors"
|
||||||
|
tabindex="-1"
|
||||||
onclick={() => {
|
onclick={() => {
|
||||||
alertStore.set({
|
alertStore.set({
|
||||||
type: "none",
|
type: "none",
|
||||||
@@ -827,7 +922,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Scrollable Container -->
|
<!-- Scrollable Container -->
|
||||||
<div class="flex flex-col gap-2 sm:gap-4 overflow-y-auto">
|
<div class="flex flex-col gap-2 sm:gap-4 overflow-y-auto" tabindex="-1">
|
||||||
{#if hypaV3DataState.summaries.length === 0}
|
{#if hypaV3DataState.summaries.length === 0}
|
||||||
<!-- Conversion Section -->
|
<!-- Conversion Section -->
|
||||||
{#if isHypaV2ConversionPossible()}
|
{#if isHypaV2ConversionPossible()}
|
||||||
@@ -836,33 +931,37 @@
|
|||||||
>
|
>
|
||||||
<div class="flex flex-col items-center">
|
<div class="flex flex-col items-center">
|
||||||
<div class="my-1 sm:my-2 text-center text-zinc-300">
|
<div class="my-1 sm:my-2 text-center text-zinc-300">
|
||||||
No summaries yet, but you may convert HypaV2 data to V3.
|
{language.hypaV3Modal.convertLabel}
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
class="my-1 sm:my-2 px-4 py-2 rounded-md text-zinc-300 font-semibold bg-zinc-700 hover:bg-zinc-500 transition-colors"
|
class="my-1 sm:my-2 px-4 py-2 rounded-md text-zinc-300 font-semibold bg-zinc-700 hover:bg-zinc-500 transition-colors"
|
||||||
|
tabindex="-1"
|
||||||
onclick={async () => {
|
onclick={async () => {
|
||||||
const conversionResult = convertHypaV2ToV3();
|
const conversionResult = convertHypaV2ToV3();
|
||||||
|
|
||||||
if (conversionResult.success) {
|
if (conversionResult.success) {
|
||||||
await alertNormalWait(
|
await alertNormalWait(
|
||||||
"Successfully converted HypaV2 data to V3"
|
language.hypaV3Modal.convertSuccessMessage
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
await alertNormalWait(
|
await alertNormalWait(
|
||||||
`Failed to convert HypaV2 data to V3: ${conversionResult.error}`
|
language.hypaV3Modal.convertErrorMessage.replace(
|
||||||
|
"{0}",
|
||||||
|
conversionResult.error
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
showHypaV3Alert();
|
showHypaV3Alert();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Convert to V3
|
{language.hypaV3Modal.convertButton}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="p-4 sm:p-3 md:p-4 text-center text-zinc-400">
|
<div class="p-4 sm:p-3 md:p-4 text-center text-zinc-400">
|
||||||
No summaries yet
|
{language.hypaV3Modal.noSummariesLabel}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
@@ -880,13 +979,13 @@
|
|||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
class="w-full px-2 sm:px-4 py-2 sm:py-3 rounded border border-zinc-700 focus:outline-none focus:ring-2 focus:ring-zinc-500 text-zinc-200 bg-zinc-900"
|
class="w-full px-2 sm:px-4 py-2 sm:py-3 rounded border border-zinc-700 focus:outline-none focus:ring-2 focus:ring-zinc-500 text-zinc-200 bg-zinc-900"
|
||||||
placeholder="Enter #N, ID, or search query"
|
placeholder={language.hypaV3Modal.searchPlaceholder}
|
||||||
bind:this={searchUIState.ref}
|
bind:this={searchUIState.ref}
|
||||||
bind:value={searchUIState.query}
|
bind:value={searchUIState.query}
|
||||||
oninput={() => {
|
oninput={() => {
|
||||||
if (searchUIState) {
|
if (searchUIState) {
|
||||||
searchUIState.currentIndex = -1;
|
|
||||||
searchUIState.results = [];
|
searchUIState.results = [];
|
||||||
|
searchUIState.currentResultIndex = -1;
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onkeydown={(e) => onSearch(e)}
|
onkeydown={(e) => onSearch(e)}
|
||||||
@@ -897,16 +996,32 @@
|
|||||||
<span
|
<span
|
||||||
class="absolute right-3 top-1/2 -translate-y-1/2 px-1.5 sm:px-3 py-1 sm:py-2 rounded text-sm font-semibold text-zinc-100 bg-zinc-700/65"
|
class="absolute right-3 top-1/2 -translate-y-1/2 px-1.5 sm:px-3 py-1 sm:py-2 rounded text-sm font-semibold text-zinc-100 bg-zinc-700/65"
|
||||||
>
|
>
|
||||||
{searchUIState.currentIndex + 1}/{searchUIState.results
|
{searchUIState.currentResultIndex + 1}/{searchUIState
|
||||||
.length}
|
.results.length}
|
||||||
</span>
|
</span>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Previous Button -->
|
||||||
<button
|
<button
|
||||||
class="p-2 text-zinc-400 hover:text-zinc-200 transition-colors"
|
class="p-2 text-zinc-400 hover:text-zinc-200 transition-colors"
|
||||||
onclick={async () => toggleSearch()}
|
tabindex="-1"
|
||||||
|
onclick={() => {
|
||||||
|
onSearch({ shiftKey: true, key: "Enter" } as KeyboardEvent);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<XIcon class="w-6 h-6" />
|
<ChevronUpIcon class="w-6 h-6" />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Next Button -->
|
||||||
|
<button
|
||||||
|
class="p-2 text-zinc-400 hover:text-zinc-200 transition-colors"
|
||||||
|
tabindex="-1"
|
||||||
|
onclick={() => {
|
||||||
|
onSearch({ key: "Enter" } as KeyboardEvent);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ChevronDownIcon class="w-6 h-6" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -914,6 +1029,7 @@
|
|||||||
|
|
||||||
<!-- Summaries List -->
|
<!-- Summaries List -->
|
||||||
{#each hypaV3DataState.summaries as summary, i}
|
{#each hypaV3DataState.summaries as summary, i}
|
||||||
|
{#if !showImportantOnly || summary.isImportant}
|
||||||
{#if summaryUIStates[i]}
|
{#if summaryUIStates[i]}
|
||||||
<!-- Summary Item -->
|
<!-- Summary Item -->
|
||||||
<div
|
<div
|
||||||
@@ -921,12 +1037,18 @@
|
|||||||
>
|
>
|
||||||
<!-- Original Summary Header -->
|
<!-- Original Summary Header -->
|
||||||
<div class="flex justify-between items-center">
|
<div class="flex justify-between items-center">
|
||||||
<span class="text-sm text-zinc-400">Summary #{i + 1}</span>
|
<span class="text-sm text-zinc-400"
|
||||||
|
>{language.hypaV3Modal.summaryNumberLabel.replace(
|
||||||
|
"{0}",
|
||||||
|
(i + 1).toString()
|
||||||
|
)}</span
|
||||||
|
>
|
||||||
|
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<!-- Translate Button -->
|
<!-- Translate Button -->
|
||||||
<button
|
<button
|
||||||
class="p-2 text-zinc-400 hover:text-zinc-200 transition-colors"
|
class="p-2 text-zinc-400 hover:text-zinc-200 transition-colors"
|
||||||
|
tabindex="-1"
|
||||||
use:handleDualAction={{
|
use:handleDualAction={{
|
||||||
onMainAction: () => toggleTranslate(i, false),
|
onMainAction: () => toggleTranslate(i, false),
|
||||||
onAlternativeAction: () => toggleTranslate(i, true),
|
onAlternativeAction: () => toggleTranslate(i, true),
|
||||||
@@ -937,9 +1059,10 @@
|
|||||||
|
|
||||||
<!-- Important Button -->
|
<!-- Important Button -->
|
||||||
<button
|
<button
|
||||||
class="p-2 hover:text-zinc-200 transition-colors {summary.isImportant
|
class="p-2 transition-colors {summary.isImportant
|
||||||
? 'text-yellow-400'
|
? 'text-yellow-400 hover:text-yellow-300'
|
||||||
: 'text-zinc-400'}"
|
: 'text-zinc-400 hover:text-zinc-200'}"
|
||||||
|
tabindex="-1"
|
||||||
onclick={() => {
|
onclick={() => {
|
||||||
summary.isImportant = !summary.isImportant;
|
summary.isImportant = !summary.isImportant;
|
||||||
}}
|
}}
|
||||||
@@ -950,8 +1073,9 @@
|
|||||||
<!-- Reroll Button -->
|
<!-- Reroll Button -->
|
||||||
<button
|
<button
|
||||||
class="p-2 text-zinc-400 hover:text-zinc-200 transition-colors"
|
class="p-2 text-zinc-400 hover:text-zinc-200 transition-colors"
|
||||||
onclick={async () => await toggleReroll(i)}
|
tabindex="-1"
|
||||||
disabled={!isRerollable(i)}
|
disabled={!isRerollable(i)}
|
||||||
|
onclick={async () => await toggleReroll(i)}
|
||||||
>
|
>
|
||||||
<RefreshCw class="w-4 h-4" />
|
<RefreshCw class="w-4 h-4" />
|
||||||
</button>
|
</button>
|
||||||
@@ -959,11 +1083,12 @@
|
|||||||
<!-- Delete After Button -->
|
<!-- Delete After Button -->
|
||||||
<button
|
<button
|
||||||
class="p-2 text-zinc-400 hover:text-rose-300 transition-colors"
|
class="p-2 text-zinc-400 hover:text-rose-300 transition-colors"
|
||||||
|
tabindex="-1"
|
||||||
onclick={async () => {
|
onclick={async () => {
|
||||||
if (
|
if (
|
||||||
await alertConfirmTwice(
|
await alertConfirmTwice(
|
||||||
"Delete all summaries after this one?",
|
language.hypaV3Modal.deleteAfterConfirmMessage,
|
||||||
"This action cannot be undone. Are you really sure?"
|
language.hypaV3Modal.deleteAfterConfirmSecondMessage
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
hypaV3DataState.summaries.splice(i + 1);
|
hypaV3DataState.summaries.splice(i + 1);
|
||||||
@@ -983,6 +1108,11 @@
|
|||||||
class="p-2 sm:p-4 w-full min-h-40 sm:min-h-56 resize-vertical rounded border border-zinc-700 focus:outline-none focus:ring-2 focus:ring-zinc-500 transition-colors text-zinc-200 bg-zinc-900"
|
class="p-2 sm:p-4 w-full min-h-40 sm:min-h-56 resize-vertical rounded border border-zinc-700 focus:outline-none focus:ring-2 focus:ring-zinc-500 transition-colors text-zinc-200 bg-zinc-900"
|
||||||
bind:this={summaryUIStates[i].originalRef}
|
bind:this={summaryUIStates[i].originalRef}
|
||||||
bind:value={summary.text}
|
bind:value={summary.text}
|
||||||
|
onfocus={() => {
|
||||||
|
if (searchUIState && !searchUIState.isNavigating) {
|
||||||
|
searchUIState.requestedSearchFromIndex = i;
|
||||||
|
}
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
</textarea>
|
</textarea>
|
||||||
</div>
|
</div>
|
||||||
@@ -991,14 +1121,14 @@
|
|||||||
{#if summaryUIStates[i].translation}
|
{#if summaryUIStates[i].translation}
|
||||||
<div class="mt-2 sm:mt-4">
|
<div class="mt-2 sm:mt-4">
|
||||||
<div class="mb-2 sm:mb-4 text-sm text-zinc-400">
|
<div class="mb-2 sm:mb-4 text-sm text-zinc-400">
|
||||||
Translation
|
{language.hypaV3Modal.translationLabel}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<textarea
|
<textarea
|
||||||
readonly
|
|
||||||
class="p-2 sm:p-4 w-full min-h-40 sm:min-h-56 resize-vertical rounded border border-zinc-700 focus:outline-none transition-colors text-zinc-200 bg-zinc-900"
|
class="p-2 sm:p-4 w-full min-h-40 sm:min-h-56 resize-vertical rounded border border-zinc-700 focus:outline-none transition-colors text-zinc-200 bg-zinc-900"
|
||||||
bind:this={summaryUIStates[i].translationRef}
|
readonly
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
|
bind:this={summaryUIStates[i].translationRef}
|
||||||
value={summaryUIStates[i].translation}
|
value={summaryUIStates[i].translation}
|
||||||
></textarea>
|
></textarea>
|
||||||
</div>
|
</div>
|
||||||
@@ -1008,13 +1138,17 @@
|
|||||||
<!-- Rerolled Summary Header -->
|
<!-- Rerolled Summary Header -->
|
||||||
<div class="mt-2 sm:mt-4">
|
<div class="mt-2 sm:mt-4">
|
||||||
<div class="flex justify-between items-center">
|
<div class="flex justify-between items-center">
|
||||||
<span class="text-sm text-zinc-400">Rerolled Summary</span>
|
<span class="text-sm text-zinc-400"
|
||||||
|
>{language.hypaV3Modal.rerolledSummaryLabel}</span
|
||||||
|
>
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<!-- Translate Rerolled Button -->
|
<!-- Translate Rerolled Button -->
|
||||||
<button
|
<button
|
||||||
class="p-2 text-zinc-400 hover:text-zinc-200 transition-colors"
|
class="p-2 text-zinc-400 hover:text-zinc-200 transition-colors"
|
||||||
|
tabindex="-1"
|
||||||
use:handleDualAction={{
|
use:handleDualAction={{
|
||||||
onMainAction: () => toggleTranslateRerolled(i, false),
|
onMainAction: () =>
|
||||||
|
toggleTranslateRerolled(i, false),
|
||||||
onAlternativeAction: () =>
|
onAlternativeAction: () =>
|
||||||
toggleTranslateRerolled(i, true),
|
toggleTranslateRerolled(i, true),
|
||||||
}}
|
}}
|
||||||
@@ -1025,6 +1159,7 @@
|
|||||||
<!-- Cancel Button -->
|
<!-- Cancel Button -->
|
||||||
<button
|
<button
|
||||||
class="p-2 text-zinc-400 hover:text-zinc-200 transition-colors"
|
class="p-2 text-zinc-400 hover:text-zinc-200 transition-colors"
|
||||||
|
tabindex="-1"
|
||||||
onclick={() => {
|
onclick={() => {
|
||||||
summaryUIStates[i].rerolledText = null;
|
summaryUIStates[i].rerolledText = null;
|
||||||
summaryUIStates[i].rerolledTranslation = null;
|
summaryUIStates[i].rerolledTranslation = null;
|
||||||
@@ -1036,6 +1171,7 @@
|
|||||||
<!-- Apply Button -->
|
<!-- Apply Button -->
|
||||||
<button
|
<button
|
||||||
class="p-2 text-zinc-400 hover:text-rose-300 transition-colors"
|
class="p-2 text-zinc-400 hover:text-rose-300 transition-colors"
|
||||||
|
tabindex="-1"
|
||||||
onclick={() => {
|
onclick={() => {
|
||||||
summary.text = summaryUIStates[i].rerolledText!;
|
summary.text = summaryUIStates[i].rerolledText!;
|
||||||
summaryUIStates[i].translation = null;
|
summaryUIStates[i].translation = null;
|
||||||
@@ -1053,6 +1189,7 @@
|
|||||||
<div class="mt-2 sm:mt-4">
|
<div class="mt-2 sm:mt-4">
|
||||||
<textarea
|
<textarea
|
||||||
class="p-2 sm:p-4 w-full min-h-40 sm:min-h-56 resize-vertical rounded border border-zinc-700 focus:outline-none focus:ring-2 focus:ring-zinc-500 transition-colors text-zinc-200 bg-zinc-900"
|
class="p-2 sm:p-4 w-full min-h-40 sm:min-h-56 resize-vertical rounded border border-zinc-700 focus:outline-none focus:ring-2 focus:ring-zinc-500 transition-colors text-zinc-200 bg-zinc-900"
|
||||||
|
tabindex="-1"
|
||||||
bind:value={summaryUIStates[i].rerolledText}
|
bind:value={summaryUIStates[i].rerolledText}
|
||||||
>
|
>
|
||||||
</textarea>
|
</textarea>
|
||||||
@@ -1062,14 +1199,14 @@
|
|||||||
{#if summaryUIStates[i].rerolledTranslation}
|
{#if summaryUIStates[i].rerolledTranslation}
|
||||||
<div class="mt-2 sm:mt-4">
|
<div class="mt-2 sm:mt-4">
|
||||||
<div class="mb-2 sm:mb-4 text-sm text-zinc-400">
|
<div class="mb-2 sm:mb-4 text-sm text-zinc-400">
|
||||||
Rerolled Translation
|
{language.hypaV3Modal.rerolledTranslationLabel}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<textarea
|
<textarea
|
||||||
readonly
|
|
||||||
class="p-2 sm:p-4 w-full min-h-40 sm:min-h-56 resize-vertical rounded border border-zinc-700 focus:outline-none transition-colors text-zinc-200 bg-zinc-900"
|
class="p-2 sm:p-4 w-full min-h-40 sm:min-h-56 resize-vertical rounded border border-zinc-700 focus:outline-none transition-colors text-zinc-200 bg-zinc-900"
|
||||||
bind:this={summaryUIStates[i].rerolledTranslationRef}
|
readonly
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
|
bind:this={summaryUIStates[i].rerolledTranslationRef}
|
||||||
value={summaryUIStates[i].rerolledTranslation}
|
value={summaryUIStates[i].rerolledTranslation}
|
||||||
></textarea>
|
></textarea>
|
||||||
</div>
|
</div>
|
||||||
@@ -1080,13 +1217,17 @@
|
|||||||
<div class="mt-2 sm:mt-4">
|
<div class="mt-2 sm:mt-4">
|
||||||
<div class="flex justify-between items-center">
|
<div class="flex justify-between items-center">
|
||||||
<span class="text-sm text-zinc-400"
|
<span class="text-sm text-zinc-400"
|
||||||
>Connected Messages ({summary.chatMemos.length})</span
|
>{language.hypaV3Modal.connectedMessageCountLabel.replace(
|
||||||
|
"{0}",
|
||||||
|
summary.chatMemos.length.toString()
|
||||||
|
)}</span
|
||||||
>
|
>
|
||||||
|
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<!-- Translate Message Button -->
|
<!-- Translate Message Button -->
|
||||||
<button
|
<button
|
||||||
class="p-2 text-zinc-400 hover:text-zinc-200 transition-colors"
|
class="p-2 text-zinc-400 hover:text-zinc-200 transition-colors"
|
||||||
|
tabindex="-1"
|
||||||
use:handleDualAction={{
|
use:handleDualAction={{
|
||||||
onMainAction: () =>
|
onMainAction: () =>
|
||||||
toggleTranslateExpandedMessage(false),
|
toggleTranslateExpandedMessage(false),
|
||||||
@@ -1110,10 +1251,13 @@
|
|||||||
)
|
)
|
||||||
? 'ring-2 ring-zinc-500'
|
? 'ring-2 ring-zinc-500'
|
||||||
: ''}"
|
: ''}"
|
||||||
|
tabindex="-1"
|
||||||
bind:this={summaryUIStates[i].chatMemoRefs[memoIndex]}
|
bind:this={summaryUIStates[i].chatMemoRefs[memoIndex]}
|
||||||
onclick={() => toggleExpandMessage(i, chatMemo)}
|
onclick={() => toggleExpandMessage(i, chatMemo)}
|
||||||
>
|
>
|
||||||
{chatMemo == null ? "First Message" : chatMemo}
|
{chatMemo == null
|
||||||
|
? language.hypaV3Modal.connectedFirstMessageLabel
|
||||||
|
: chatMemo}
|
||||||
</button>
|
</button>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
@@ -1126,22 +1270,31 @@
|
|||||||
{#if expandedMessage}
|
{#if expandedMessage}
|
||||||
<!-- Role -->
|
<!-- Role -->
|
||||||
<div class="mb-2 sm:mb-4 text-sm text-zinc-400">
|
<div class="mb-2 sm:mb-4 text-sm text-zinc-400">
|
||||||
{expandedMessage.role}'s Message
|
{language.hypaV3Modal.connectedMessageRoleLabel.replace(
|
||||||
|
"{0}",
|
||||||
|
expandedMessage.role
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Content -->
|
<!-- Content -->
|
||||||
<textarea
|
<textarea
|
||||||
readonly
|
|
||||||
class="p-2 sm:p-4 w-full min-h-40 sm:min-h-56 resize-vertical rounded border border-zinc-700 focus:outline-none transition-colors text-zinc-200 bg-zinc-900"
|
class="p-2 sm:p-4 w-full min-h-40 sm:min-h-56 resize-vertical rounded border border-zinc-700 focus:outline-none transition-colors text-zinc-200 bg-zinc-900"
|
||||||
|
readonly
|
||||||
|
tabindex="-1"
|
||||||
value={expandedMessage.data}
|
value={expandedMessage.data}
|
||||||
></textarea>
|
></textarea>
|
||||||
{:else}
|
{:else}
|
||||||
<span class="text-sm text-red-400">Message not found</span
|
<span class="text-sm text-red-400"
|
||||||
|
>{language.hypaV3Modal
|
||||||
|
.connectedMessageNotFoundLabel}</span
|
||||||
>
|
>
|
||||||
{/if}
|
{/if}
|
||||||
{:catch error}
|
{:catch error}
|
||||||
<span class="text-sm text-red-400"
|
<span class="text-sm text-red-400"
|
||||||
>Error loading expanded message: {error.message}</span
|
>{language.hypaV3Modal.connectedMessageLoadingError.replace(
|
||||||
|
"{0}",
|
||||||
|
error.message
|
||||||
|
)}</span
|
||||||
>
|
>
|
||||||
{/await}
|
{/await}
|
||||||
</div>
|
</div>
|
||||||
@@ -1150,14 +1303,14 @@
|
|||||||
{#if expandedMessageUIState.translation}
|
{#if expandedMessageUIState.translation}
|
||||||
<div class="mt-2 sm:mt-4">
|
<div class="mt-2 sm:mt-4">
|
||||||
<div class="mb-2 sm:mb-4 text-sm text-zinc-400">
|
<div class="mb-2 sm:mb-4 text-sm text-zinc-400">
|
||||||
Translation
|
{language.hypaV3Modal.connectedMessageTranslationLabel}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<textarea
|
<textarea
|
||||||
readonly
|
|
||||||
class="p-2 sm:p-4 w-full min-h-40 sm:min-h-56 resize-vertical rounded border border-zinc-700 focus:outline-none transition-colors text-zinc-200 bg-zinc-900"
|
class="p-2 sm:p-4 w-full min-h-40 sm:min-h-56 resize-vertical rounded border border-zinc-700 focus:outline-none transition-colors text-zinc-200 bg-zinc-900"
|
||||||
bind:this={expandedMessageUIState.translationRef}
|
readonly
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
|
bind:this={expandedMessageUIState.translationRef}
|
||||||
value={expandedMessageUIState.translation}
|
value={expandedMessageUIState.translation}
|
||||||
></textarea>
|
></textarea>
|
||||||
</div>
|
</div>
|
||||||
@@ -1165,6 +1318,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
<!-- Next Summarization Target -->
|
<!-- Next Summarization Target -->
|
||||||
@@ -1173,25 +1327,34 @@
|
|||||||
{#if nextMessage}
|
{#if nextMessage}
|
||||||
{@const chatId =
|
{@const chatId =
|
||||||
nextMessage.chatId === "first"
|
nextMessage.chatId === "first"
|
||||||
? "First Message"
|
? language.hypaV3Modal.nextSummarizationFirstMessageLabel
|
||||||
: nextMessage.chatId == null
|
: nextMessage.chatId == null
|
||||||
? "No Message ID"
|
? language.hypaV3Modal.nextSummarizationNoMessageIdLabel
|
||||||
: nextMessage.chatId}
|
: nextMessage.chatId}
|
||||||
<div class="mb-2 sm:mb-4 text-sm text-zinc-400">
|
<div class="mb-2 sm:mb-4 text-sm text-zinc-400">
|
||||||
HypaV3 will summarize [{chatId}]
|
{language.hypaV3Modal.nextSummarizationLabel.replace(
|
||||||
|
"{0}",
|
||||||
|
chatId
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<textarea
|
<textarea
|
||||||
readonly
|
|
||||||
class="p-2 sm:p-4 w-full min-h-40 sm:min-h-56 resize-none overflow-y-auto rounded border border-zinc-700 focus:outline-none transition-colors text-zinc-200 bg-zinc-900"
|
class="p-2 sm:p-4 w-full min-h-40 sm:min-h-56 resize-none overflow-y-auto rounded border border-zinc-700 focus:outline-none transition-colors text-zinc-200 bg-zinc-900"
|
||||||
|
readonly
|
||||||
value={nextMessage.data}
|
value={nextMessage.data}
|
||||||
></textarea>
|
></textarea>
|
||||||
{:else}
|
{:else}
|
||||||
<span class="text-sm text-red-400">WARN: No messages found</span>
|
<span class="text-sm text-red-400"
|
||||||
|
>{language.hypaV3Modal
|
||||||
|
.nextSummarizationNoMessagesFoundLabel}</span
|
||||||
|
>
|
||||||
{/if}
|
{/if}
|
||||||
{:catch error}
|
{:catch error}
|
||||||
<span class="text-sm text-red-400"
|
<span class="text-sm text-red-400"
|
||||||
>Error loading next message: {error.message}</span
|
>{language.hypaV3Modal.nextSummarizationLoadingError.replace(
|
||||||
|
"{0}",
|
||||||
|
error.message
|
||||||
|
)}</span
|
||||||
>
|
>
|
||||||
{/await}
|
{/await}
|
||||||
</div>
|
</div>
|
||||||
@@ -1200,7 +1363,7 @@
|
|||||||
{#if !getFirstMessage()}
|
{#if !getFirstMessage()}
|
||||||
<div class="mt-2 sm:mt-4">
|
<div class="mt-2 sm:mt-4">
|
||||||
<span class="text-sm text-red-400"
|
<span class="text-sm text-red-400"
|
||||||
>WARN: Selected first message is empty</span
|
>{language.hypaV3Modal.emptySelectedFirstMessageLabel}</span
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -467,6 +467,15 @@
|
|||||||
DBState.db.hypav2 = false
|
DBState.db.hypav2 = false
|
||||||
DBState.db.hanuraiEnable = false
|
DBState.db.hanuraiEnable = false
|
||||||
DBState.db.hypaV3 = true
|
DBState.db.hypaV3 = true
|
||||||
|
DBState.db.hypaV3Settings.memoryTokensRatio = 0.2
|
||||||
|
DBState.db.hypaV3Settings.extraSummarizationRatio = 0
|
||||||
|
DBState.db.hypaV3Settings.maxChatsPerSummary = 4
|
||||||
|
DBState.db.hypaV3Settings.recentMemoryRatio = 0.4
|
||||||
|
DBState.db.hypaV3Settings.similarMemoryRatio = 0.4
|
||||||
|
DBState.db.hypaV3Settings.enableSimilarityCorrection = false
|
||||||
|
DBState.db.hypaV3Settings.preserveOrphanedMemory = false
|
||||||
|
DBState.db.hypaV3Settings.processRegexScript = false
|
||||||
|
DBState.db.hypaV3Settings.doNotSummarizeUserMessage = false
|
||||||
} else {
|
} else {
|
||||||
DBState.db.supaModelType = 'none'
|
DBState.db.supaModelType = 'none'
|
||||||
DBState.db.memoryAlgorithmType = 'none'
|
DBState.db.memoryAlgorithmType = 'none'
|
||||||
@@ -508,46 +517,45 @@
|
|||||||
<span class="text-textcolor">{language.hypaAllocatedTokens}</span>
|
<span class="text-textcolor">{language.hypaAllocatedTokens}</span>
|
||||||
<NumberInput size="sm" marginBottom bind:value={DBState.db.hypaAllocatedTokens} min={100} />
|
<NumberInput size="sm" marginBottom bind:value={DBState.db.hypaAllocatedTokens} min={100} />
|
||||||
{:else if DBState.db.hypaV3}
|
{:else if DBState.db.hypaV3}
|
||||||
<span class="mb-2 text-textcolor2 text-sm text-wrap break-words max-w-full">{language.hypaV3Desc}</span>
|
<span class="mb-2 text-textcolor2 text-sm text-wrap break-words max-w-full">{language.hypaV3Settings.descriptionLabel}</span>
|
||||||
<span class="text-textcolor mt-4">{language.SuperMemory} {language.model}</span>
|
<span class="text-textcolor mt-4">{language.SuperMemory} {language.model}</span>
|
||||||
<SelectInput className="mt-2 mb-2" bind:value={DBState.db.supaModelType}>
|
<SelectInput className="mt-2 mb-2" bind:value={DBState.db.supaModelType}>
|
||||||
<OptionInput value="distilbart">distilbart-cnn-6-6 (Free/Local)</OptionInput>
|
<OptionInput value="distilbart">distilbart-cnn-6-6 (Free/Local)</OptionInput>
|
||||||
<OptionInput value="subModel">{language.submodel}</OptionInput>
|
<OptionInput value="subModel">{language.submodel}</OptionInput>
|
||||||
</SelectInput>
|
</SelectInput>
|
||||||
{#if DBState.db.supaModelType === "instruct35"}
|
|
||||||
<span class="text-textcolor">OpenAI API Key</span>
|
|
||||||
<TextInput marginBottom size="sm" bind:value={DBState.db.supaMemoryKey} />
|
|
||||||
{/if}
|
|
||||||
<span class="text-textcolor">{language.summarizationPrompt} <Help key="summarizationPrompt"/></span>
|
<span class="text-textcolor">{language.summarizationPrompt} <Help key="summarizationPrompt"/></span>
|
||||||
<div class="mb-2">
|
<div class="mb-2">
|
||||||
<TextAreaInput size="sm" placeholder="Leave it blank to use default" bind:value={DBState.db.supaMemoryPrompt} />
|
<TextAreaInput size="sm" placeholder={language.hypaV3Settings.supaMemoryPromptPlaceHolder} bind:value={DBState.db.supaMemoryPrompt} />
|
||||||
</div>
|
</div>
|
||||||
<span class="text-textcolor">Max Memory Tokens Ratio (Estimated)</span>
|
|
||||||
{#await getMaxMemoryRatio() then maxMemoryRatio}
|
{#await getMaxMemoryRatio() then maxMemoryRatio}
|
||||||
|
<span class="text-textcolor">{language.hypaV3Settings.maxMemoryTokensRatioLabel}</span>
|
||||||
<NumberInput marginBottom disabled size="sm" value={maxMemoryRatio} />
|
<NumberInput marginBottom disabled size="sm" value={maxMemoryRatio} />
|
||||||
{:catch error}
|
{:catch error}
|
||||||
<span class="text-textcolor">{error}</span>
|
<span class="text-red-400">{language.hypaV3Settings.maxMemoryTokensRatioError}</span>
|
||||||
{/await}
|
{/await}
|
||||||
<span class="text-textcolor">Memory Tokens Ratio</span>
|
<span class="text-textcolor">{language.hypaV3Settings.memoryTokensRatioLabel}</span>
|
||||||
<SliderInput marginBottom min={0} max={1} step={0.01} fixed={2} bind:value={DBState.db.hypaV3Settings.memoryTokensRatio} />
|
<SliderInput marginBottom min={0} max={1} step={0.01} fixed={2} bind:value={DBState.db.hypaV3Settings.memoryTokensRatio} />
|
||||||
<span class="text-textcolor">Extra Summarization Ratio</span>
|
<span class="text-textcolor">{language.hypaV3Settings.extraSummarizationRatioLabel}</span>
|
||||||
<SliderInput marginBottom min={0} max={1 - DBState.db.hypaV3Settings.memoryTokensRatio} step={0.01} fixed={2} bind:value={DBState.db.hypaV3Settings.extraSummarizationRatio} />
|
<SliderInput marginBottom min={0} max={1 - DBState.db.hypaV3Settings.memoryTokensRatio} step={0.01} fixed={2} bind:value={DBState.db.hypaV3Settings.extraSummarizationRatio} />
|
||||||
<span class="text-textcolor">Max Chats Per Summary</span>
|
<span class="text-textcolor">{language.hypaV3Settings.maxChatsPerSummaryLabel}</span>
|
||||||
<NumberInput marginBottom size="sm" min={1} bind:value={DBState.db.hypaV3Settings.maxChatsPerSummary} />
|
<NumberInput marginBottom size="sm" min={1} bind:value={DBState.db.hypaV3Settings.maxChatsPerSummary} />
|
||||||
<span class="text-textcolor">Recent Memory Ratio</span>
|
<span class="text-textcolor">{language.hypaV3Settings.recentMemoryRatioLabel}</span>
|
||||||
<SliderInput marginBottom min={0} max={1} step={0.01} fixed={2} bind:value={DBState.db.hypaV3Settings.recentMemoryRatio} />
|
<SliderInput marginBottom min={0} max={1} step={0.01} fixed={2} bind:value={DBState.db.hypaV3Settings.recentMemoryRatio} />
|
||||||
<span class="text-textcolor">Similar Memory Ratio</span>
|
<span class="text-textcolor">{language.hypaV3Settings.similarMemoryRatioLabel}</span>
|
||||||
<SliderInput marginBottom min={0} max={1} step={0.01} fixed={2} bind:value={DBState.db.hypaV3Settings.similarMemoryRatio} />
|
<SliderInput marginBottom min={0} max={1} step={0.01} fixed={2} bind:value={DBState.db.hypaV3Settings.similarMemoryRatio} />
|
||||||
<span class="text-textcolor">Random Memory Ratio</span>
|
<span class="text-textcolor">{language.hypaV3Settings.randomMemoryRatioLabel}</span>
|
||||||
<NumberInput marginBottom disabled size="sm" value={parseFloat((1 - DBState.db.hypaV3Settings.recentMemoryRatio - DBState.db.hypaV3Settings.similarMemoryRatio).toFixed(2))} />
|
<NumberInput marginBottom disabled size="sm" value={parseFloat((1 - DBState.db.hypaV3Settings.recentMemoryRatio - DBState.db.hypaV3Settings.similarMemoryRatio).toFixed(2))} />
|
||||||
<div class="flex mb-2">
|
<div class="flex mb-2">
|
||||||
<Check name="Enable Similarity Correction" bind:check={DBState.db.hypaV3Settings.enableSimilarityCorrection} />
|
<Check name={language.hypaV3Settings.enableSimilarityCorrectionLabel} bind:check={DBState.db.hypaV3Settings.enableSimilarityCorrection} />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex mb-2">
|
<div class="flex mb-2">
|
||||||
<Check name="Preserve Orphaned Memory" bind:check={DBState.db.hypaV3Settings.preserveOrphanedMemory} />
|
<Check name={language.hypaV3Settings.preserveOrphanedMemoryLabel} bind:check={DBState.db.hypaV3Settings.preserveOrphanedMemory} />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex mb-2">
|
<div class="flex mb-2">
|
||||||
<Check name="Process Regex Script (Reroll Only)" bind:check={DBState.db.hypaV3Settings.processRegexScript} />
|
<Check name={language.hypaV3Settings.applyRegexScriptWhenRerollingLabel} bind:check={DBState.db.hypaV3Settings.processRegexScript} />
|
||||||
|
</div>
|
||||||
|
<div class="flex mb-2">
|
||||||
|
<Check name={language.hypaV3Settings.doNotSummarizeUserMessageLabel} bind:check={DBState.db.hypaV3Settings.doNotSummarizeUserMessage} />
|
||||||
</div>
|
</div>
|
||||||
{:else if (DBState.db.supaModelType !== 'none' && DBState.db.hypav2 === false && DBState.db.hypaV3 === false)}
|
{:else if (DBState.db.supaModelType !== 'none' && DBState.db.hypav2 === false && DBState.db.hypaV3 === false)}
|
||||||
<span class="mb-2 text-textcolor2 text-sm text-wrap break-words max-w-full">{language.supaDesc}</span>
|
<span class="mb-2 text-textcolor2 text-sm text-wrap break-words max-w-full">{language.supaDesc}</span>
|
||||||
|
|||||||
@@ -421,6 +421,12 @@ export async function hypaMemoryV3(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (db.hypaV3Settings.doNotSummarizeUserMessage && chat.role === "user") {
|
||||||
|
console.log(`[HypaV3] Skipping user role at index ${i}`);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
toSummarize.push(chat);
|
toSummarize.push(chat);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -436,6 +442,7 @@ export async function hypaMemoryV3(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Attempt summarization
|
// Attempt summarization
|
||||||
|
if (toSummarize.length > 0) {
|
||||||
const summarizeResult = await retryableSummarize(toSummarize);
|
const summarizeResult = await retryableSummarize(toSummarize);
|
||||||
|
|
||||||
if (!summarizeResult.success) {
|
if (!summarizeResult.success) {
|
||||||
@@ -452,6 +459,7 @@ export async function hypaMemoryV3(
|
|||||||
chatMemos: new Set(toSummarize.map((chat) => chat.memo)),
|
chatMemos: new Set(toSummarize.map((chat) => chat.memo)),
|
||||||
isImportant: false,
|
isImportant: false,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
currentTokens -= toSummarizeTokens;
|
currentTokens -= toSummarizeTokens;
|
||||||
startIdx = endIdx;
|
startIdx = endIdx;
|
||||||
@@ -469,6 +477,37 @@ export async function hypaMemoryV3(
|
|||||||
availableMemoryTokens
|
availableMemoryTokens
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Early return if no summaries
|
||||||
|
if (data.summaries.length === 0) {
|
||||||
|
// Generate final memory prompt
|
||||||
|
const memory = encapsulateMemoryPrompt("");
|
||||||
|
|
||||||
|
const newChats: OpenAIChat[] = [
|
||||||
|
{
|
||||||
|
role: "system",
|
||||||
|
content: memory,
|
||||||
|
memo: "supaMemory",
|
||||||
|
},
|
||||||
|
...chats.slice(startIdx),
|
||||||
|
];
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
"[HypaV3] Exiting function:",
|
||||||
|
"\nCurrent Tokens:",
|
||||||
|
currentTokens,
|
||||||
|
"\nAll chats, including memory prompt:",
|
||||||
|
newChats,
|
||||||
|
"\nMemory Data:",
|
||||||
|
data
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
currentTokens,
|
||||||
|
chats: newChats,
|
||||||
|
memory: toSerializableHypaV3Data(data),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const selectedSummaries: Summary[] = [];
|
const selectedSummaries: Summary[] = [];
|
||||||
const randomMemoryRatio =
|
const randomMemoryRatio =
|
||||||
1 -
|
1 -
|
||||||
|
|||||||
@@ -474,13 +474,14 @@ export function setDatabase(data:Database){
|
|||||||
data.reasoningEffort ??= 0
|
data.reasoningEffort ??= 0
|
||||||
data.hypaV3Settings = {
|
data.hypaV3Settings = {
|
||||||
memoryTokensRatio: data.hypaV3Settings?.memoryTokensRatio ?? 0.2,
|
memoryTokensRatio: data.hypaV3Settings?.memoryTokensRatio ?? 0.2,
|
||||||
extraSummarizationRatio: data.hypaV3Settings?.extraSummarizationRatio ?? 0.2,
|
extraSummarizationRatio: data.hypaV3Settings?.extraSummarizationRatio ?? 0,
|
||||||
maxChatsPerSummary: data.hypaV3Settings?.maxChatsPerSummary ?? 4,
|
maxChatsPerSummary: data.hypaV3Settings?.maxChatsPerSummary ?? 4,
|
||||||
recentMemoryRatio: data.hypaV3Settings?.recentMemoryRatio ?? 0.4,
|
recentMemoryRatio: data.hypaV3Settings?.recentMemoryRatio ?? 0.4,
|
||||||
similarMemoryRatio: data.hypaV3Settings?.similarMemoryRatio ?? 0.4,
|
similarMemoryRatio: data.hypaV3Settings?.similarMemoryRatio ?? 0.4,
|
||||||
enableSimilarityCorrection: data.hypaV3Settings?.enableSimilarityCorrection ?? false,
|
enableSimilarityCorrection: data.hypaV3Settings?.enableSimilarityCorrection ?? false,
|
||||||
preserveOrphanedMemory: data.hypaV3Settings?.preserveOrphanedMemory ?? false,
|
preserveOrphanedMemory: data.hypaV3Settings?.preserveOrphanedMemory ?? false,
|
||||||
processRegexScript: data.hypaV3Settings?.processRegexScript ?? false
|
processRegexScript: data.hypaV3Settings?.processRegexScript ?? false,
|
||||||
|
doNotSummarizeUserMessage: data.hypaV3Settings?.doNotSummarizeUserMessage ?? false
|
||||||
}
|
}
|
||||||
changeLanguage(data.language)
|
changeLanguage(data.language)
|
||||||
setDatabaseLite(data)
|
setDatabaseLite(data)
|
||||||
@@ -894,6 +895,7 @@ export interface Database{
|
|||||||
enableSimilarityCorrection: boolean
|
enableSimilarityCorrection: boolean
|
||||||
preserveOrphanedMemory: boolean
|
preserveOrphanedMemory: boolean
|
||||||
processRegexScript: boolean
|
processRegexScript: boolean
|
||||||
|
doNotSummarizeUserMessage: boolean
|
||||||
},
|
},
|
||||||
OaiCompAPIKeys: {[key:string]:string}
|
OaiCompAPIKeys: {[key:string]:string}
|
||||||
inlayErrorResponse:boolean
|
inlayErrorResponse:boolean
|
||||||
|
|||||||
Reference in New Issue
Block a user