mirror of
https://github.com/vegu-ai/talemate.git
synced 2026-09-01 19:48:52 +02:00
Add Search Strictness slider with adjustable distance_mod for embeddings
This commit is contained in:
@@ -27,6 +27,7 @@
|
||||
- "Contextual Generate: Fixed list-type generation prefilling an empty line after '1.', which caused some LLMs to produce empty lists."
|
||||
- "Advance Time: Fixed toolbar time advancement being completely non-functional due to a missing websocket handler. Also fixed invalid ISO 8601 duration strings for the 1 week and 2 weeks options."
|
||||
improvements:
|
||||
- "Search Strictness: The distance_mod embedding preset value is now a float (was int) with a range of 0.1–2.0, allowing both tighter and looser similarity matching. A 'Search Strictness' slider is now available in the Context Database UI, letting users tune search sensitivity on the fly. Changes persist to the active embedding preset immediately."
|
||||
- "Embeddings Device Switching: Changing the embeddings device (e.g., CPU to CUDA) no longer requires a restart. The old model is properly released from ChromaDB's class-level cache and GPU memory is freed before loading the new model."
|
||||
- "Context Formatting: The |condensed template filter no longer permanently compacts multi-line context (e.g., world info, memories, pins) into a single line when sending prompts to the LLM. Formatting is now only compacted temporarily for deduplication comparison and restored to its original multi-line structure afterwards."
|
||||
- "Client Config UX: Moved advanced settings (Inference Presets, Structured Data Format, Section Format, Response Length Enforcement, Prompt Caching, Rate Limit) into a dedicated Advanced tab to declutter the general view. A convenient link in the general tab provides quick access. Toggling Simple View on now resets to the General tab, and switching clients always starts on General."
|
||||
|
||||
@@ -288,7 +288,7 @@ class EmbeddingFunctionPreset(pydantic.BaseModel):
|
||||
trust_remote_code: bool = False
|
||||
device: str = "cpu"
|
||||
distance: float = 1.5
|
||||
distance_mod: int = 1
|
||||
distance_mod: float = 1.0
|
||||
distance_function: str = "l2"
|
||||
fast: bool = True
|
||||
gpu_recommendation: bool = False
|
||||
|
||||
@@ -13,6 +13,7 @@ from talemate.instance import get_agent
|
||||
from talemate.world_state.manager import WorldStateManager, Suggestion
|
||||
from talemate.status import set_loading
|
||||
import talemate.game.focal as focal
|
||||
from talemate.config import save_config
|
||||
from talemate.server.websocket_plugin import Plugin
|
||||
|
||||
from .scene_intent import SceneIntentMixin
|
||||
@@ -91,6 +92,10 @@ class WorldEntryReinforcementPayload(pydantic.BaseModel):
|
||||
reset: bool = False
|
||||
|
||||
|
||||
class UpdateDistanceModPayload(pydantic.BaseModel):
|
||||
distance_mod: float = pydantic.Field(gt=0, le=2.0)
|
||||
|
||||
|
||||
class QueryContextDBPayload(pydantic.BaseModel):
|
||||
query: str
|
||||
meta: dict = {}
|
||||
@@ -213,6 +218,11 @@ class WorldStateManagerPlugin(
|
||||
def scene(self):
|
||||
return self.websocket_handler.scene
|
||||
|
||||
@property
|
||||
def current_embeddings_config(self):
|
||||
memory_agent = get_agent("memory")
|
||||
return memory_agent.embeddings_config if memory_agent else None
|
||||
|
||||
@property
|
||||
def world_state_manager(self):
|
||||
return WorldStateManager(self.scene)
|
||||
@@ -655,16 +665,48 @@ class WorldStateManagerPlugin(
|
||||
payload.query, **payload.meta
|
||||
)
|
||||
|
||||
embeddings_config = self.current_embeddings_config
|
||||
|
||||
self.websocket_handler.queue_put(
|
||||
{
|
||||
"type": "world_state_manager",
|
||||
"action": "context_db_result",
|
||||
"data": context_db.model_dump(),
|
||||
"distance_mod": embeddings_config.distance_mod if embeddings_config else 1.0,
|
||||
}
|
||||
)
|
||||
|
||||
await self.signal_operation_done()
|
||||
|
||||
async def handle_get_distance_mod(self, data):
|
||||
embeddings_config = self.current_embeddings_config
|
||||
|
||||
self.websocket_handler.queue_put(
|
||||
{
|
||||
"type": "world_state_manager",
|
||||
"action": "distance_mod_updated",
|
||||
"distance_mod": embeddings_config.distance_mod if embeddings_config else 1.0,
|
||||
}
|
||||
)
|
||||
|
||||
async def handle_update_distance_mod(self, data):
|
||||
payload = UpdateDistanceModPayload(**data)
|
||||
|
||||
embeddings_config = self.current_embeddings_config
|
||||
if not embeddings_config:
|
||||
return
|
||||
|
||||
embeddings_config.distance_mod = payload.distance_mod
|
||||
save_config()
|
||||
|
||||
self.websocket_handler.queue_put(
|
||||
{
|
||||
"type": "world_state_manager",
|
||||
"action": "distance_mod_updated",
|
||||
"distance_mod": payload.distance_mod,
|
||||
}
|
||||
)
|
||||
|
||||
async def handle_update_context_db(self, data):
|
||||
payload = UpdateContextDBPayload(**data)
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
|
||||
<v-slider :disabled="busy" thumb-label="always" density="compact" v-model="config.embeddings[selected[0]].distance" min="0.1" max="10.0" step="0.1" label="Distance" @update:model-value="setPresetChanged(selected[0])"></v-slider>
|
||||
|
||||
<v-slider :disabled="busy" thumb-label="always" density="compact" v-model="config.embeddings[selected[0]].distance_mod" min="1" max="1000" step="10" label="Distance Mod" @update:model-value="setPresetChanged(selected[0])"></v-slider>
|
||||
<v-slider :disabled="busy" thumb-label="always" density="compact" v-model="config.embeddings[selected[0]].distance_mod" min="0.1" max="2.0" step="0.1" label="Distance Mod" @update:model-value="setPresetChanged(selected[0])"></v-slider>
|
||||
|
||||
<v-select :disabled="busy" v-model="config.embeddings[selected[0]].distance_function" :items="distanceFunctions" label="Distance Function" @update:model-value="setPresetChanged(selected[0])"></v-select>
|
||||
|
||||
@@ -253,7 +253,7 @@ export default {
|
||||
trust_remote_code: false,
|
||||
device: 'cpu',
|
||||
distance: 1.0,
|
||||
distance_mod: 1,
|
||||
distance_mod: 1.0,
|
||||
distance_function: 'cosine',
|
||||
fast: true,
|
||||
gpu_recommendation: false,
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
Manage your context entries through the <v-icon>mdi-earth</v-icon> <strong>World</strong>, <v-icon>mdi-clock</v-icon> <strong>History</strong> and <v-icon>mdi-account-group</v-icon> <strong>Characters</strong> tabs.
|
||||
<p class="text-caption">
|
||||
Content search is based on <strong class="text-primary">semantic similarity</strong> using embeddings from the Memory agent, its <strong class="text-error">NOT</strong> using exact matching.
|
||||
Use the <strong>Search Strictness</strong> slider to control how closely results must match your query. Lower values require closer matches, higher values allow more loosely related results. This setting is saved to the active embedding preset.
|
||||
</p>
|
||||
</v-alert>
|
||||
<div :style="{ maxWidth: MAX_CONTENT_WIDTH }">
|
||||
@@ -38,6 +39,13 @@
|
||||
:style="{ minWidth: '150px', maxWidth: '200px' }"
|
||||
variant="underlined" single-line hide-details density="compact"></v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="6" md="auto" class="pt-4">
|
||||
<v-slider v-model="distanceMod" min="0.1" max="2.0" step="0.1"
|
||||
:style="{ minWidth: '250px', maxWidth: '350px' }"
|
||||
label="Search Strictness" hide-details
|
||||
thumb-label="always"
|
||||
@update:model-value="updateDistanceMod"></v-slider>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="auto" md="auto" class="ml-auto d-flex flex-wrap ga-1">
|
||||
<!-- button that opens the tools menu -->
|
||||
<v-menu>
|
||||
@@ -199,6 +207,7 @@
|
||||
|
||||
<script>
|
||||
import { MAX_CONTENT_WIDTH } from '@/constants';
|
||||
import { debounce } from 'lodash';
|
||||
|
||||
export default {
|
||||
name: "WorldStateManagerContextDB",
|
||||
@@ -212,6 +221,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
updateTimeout: null,
|
||||
distanceMod: 1.0,
|
||||
query: null,
|
||||
queryMetaKey: null,
|
||||
queryMetaValue: null,
|
||||
@@ -390,6 +400,21 @@ export default {
|
||||
}));
|
||||
},
|
||||
|
||||
updateDistanceMod: debounce(function(value) {
|
||||
this.getWebsocket().send(JSON.stringify({
|
||||
type: 'world_state_manager',
|
||||
action: 'update_distance_mod',
|
||||
distance_mod: value,
|
||||
}));
|
||||
}, 300),
|
||||
|
||||
requestDistanceMod() {
|
||||
this.getWebsocket().send(JSON.stringify({
|
||||
type: 'world_state_manager',
|
||||
action: 'get_distance_mod',
|
||||
}));
|
||||
},
|
||||
|
||||
resetDB() {
|
||||
let confirm = window.confirm("Are you sure you want to reset the context database? This will remove all entries and reimport them from the current save file.");
|
||||
if (!confirm) {
|
||||
@@ -409,11 +434,17 @@ export default {
|
||||
else if (message.action === 'context_db_result') {
|
||||
this.contextDB = message.data;
|
||||
this.currentQuery = this.contextDBQuery;
|
||||
if (message.distance_mod !== undefined) {
|
||||
this.distanceMod = message.distance_mod;
|
||||
}
|
||||
}
|
||||
else if (message.action === 'context_db_updated') {
|
||||
this.$emit('request-sync')
|
||||
//this.load(message.data.id);
|
||||
}
|
||||
else if (message.action === 'distance_mod_updated') {
|
||||
this.distanceMod = message.distance_mod;
|
||||
}
|
||||
else if (message.action === 'context_db_deleted') {
|
||||
let entry_id = message.data.id;
|
||||
for (let i = 0; i < this.contextDB.entries.length; i++) {
|
||||
@@ -428,6 +459,7 @@ export default {
|
||||
},
|
||||
created() {
|
||||
this.registerMessageHandler(this.handleMessage);
|
||||
this.requestDistanceMod();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user