mirror of
https://github.com/open-webui/open-webui.git
synced 2026-02-24 04:00:31 +01:00
refac
This commit is contained in:
@@ -18,11 +18,6 @@ log = logging.getLogger(__name__)
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/ef")
|
||||
async def get_embeddings(request: Request):
|
||||
return {"result": await request.app.state.EMBEDDING_FUNCTION("hello world")}
|
||||
|
||||
|
||||
############################
|
||||
# GetMemories
|
||||
############################
|
||||
@@ -165,7 +160,7 @@ async def reset_memory_from_vector_db(
|
||||
user=Depends(get_verified_user),
|
||||
):
|
||||
"""Reset user's memory vector embeddings.
|
||||
|
||||
|
||||
CRITICAL: We intentionally do NOT use Depends(get_session) here.
|
||||
This endpoint generates embeddings for ALL user memories in parallel using
|
||||
asyncio.gather(). A user with 100 memories would trigger 100 embedding API
|
||||
|
||||
@@ -2099,9 +2099,10 @@ async def process_chat_payload(request, form_data, user, metadata, model):
|
||||
|
||||
# Skills: inject manifest only — model uses view_skill tool to load full content on-demand
|
||||
user_skill_ids = form_data.pop("skill_ids", None) or []
|
||||
model_skill_ids = model.get("info", {}).get("meta", {}).get("skills", [])
|
||||
model_skill_ids = model.get("info", {}).get("meta", {}).get("skillIds", [])
|
||||
|
||||
all_skill_ids = list(set(user_skill_ids + model_skill_ids))
|
||||
available_skills = []
|
||||
if all_skill_ids:
|
||||
from open_webui.models.skills import Skills as SkillsModel
|
||||
|
||||
@@ -2348,6 +2349,7 @@ async def process_chat_payload(request, form_data, user, metadata, model):
|
||||
{
|
||||
**extra_params,
|
||||
"__event_emitter__": event_emitter,
|
||||
"__skill_ids__": [s.id for s in available_skills],
|
||||
},
|
||||
features,
|
||||
model,
|
||||
|
||||
@@ -508,7 +508,7 @@ def get_builtin_tools(
|
||||
)
|
||||
|
||||
# Skills tools - view_skill allows model to load full skill instructions on demand
|
||||
if is_builtin_tool_enabled("skills"):
|
||||
if extra_params.get("__skill_ids__"):
|
||||
builtin_functions.append(view_skill)
|
||||
|
||||
for func in builtin_functions:
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
import Tags from '$lib/components/common/Tags.svelte';
|
||||
import Knowledge from '$lib/components/workspace/Models/Knowledge.svelte';
|
||||
import ToolsSelector from '$lib/components/workspace/Models/ToolsSelector.svelte';
|
||||
import SkillsSelector from '$lib/components/workspace/Models/SkillsSelector.svelte';
|
||||
import FiltersSelector from '$lib/components/workspace/Models/FiltersSelector.svelte';
|
||||
import ActionsSelector from '$lib/components/workspace/Models/ActionsSelector.svelte';
|
||||
import Capabilities from '$lib/components/workspace/Models/Capabilities.svelte';
|
||||
@@ -89,6 +90,7 @@
|
||||
|
||||
let knowledge = [];
|
||||
let toolIds = [];
|
||||
let skillIds = [];
|
||||
|
||||
let filterIds = [];
|
||||
let defaultFilterIds = [];
|
||||
@@ -166,6 +168,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
if (skillIds.length > 0) {
|
||||
info.meta.skillIds = skillIds;
|
||||
} else {
|
||||
if (info.meta.skillIds) {
|
||||
delete info.meta.skillIds;
|
||||
}
|
||||
}
|
||||
|
||||
if (filterIds.length > 0) {
|
||||
info.meta.filterIds = filterIds;
|
||||
} else {
|
||||
@@ -293,6 +303,7 @@
|
||||
});
|
||||
|
||||
toolIds = model?.meta?.toolIds ?? [];
|
||||
skillIds = model?.meta?.skillIds ?? [];
|
||||
filterIds = model?.meta?.filterIds ?? [];
|
||||
defaultFilterIds = model?.meta?.defaultFilterIds ?? [];
|
||||
actionIds = model?.meta?.actionIds ?? [];
|
||||
@@ -736,6 +747,10 @@
|
||||
<ToolsSelector bind:selectedToolIds={toolIds} tools={$tools ?? []} />
|
||||
</div>
|
||||
|
||||
<div class="my-4">
|
||||
<SkillsSelector bind:selectedSkillIds={skillIds} />
|
||||
</div>
|
||||
|
||||
{#if ($functions ?? []).filter((func) => func.type === 'filter').length > 0 || ($functions ?? []).filter((func) => func.type === 'action').length > 0}
|
||||
<hr class=" border-gray-100/30 dark:border-gray-850/30 my-4" />
|
||||
|
||||
|
||||
62
src/lib/components/workspace/Models/SkillsSelector.svelte
Normal file
62
src/lib/components/workspace/Models/SkillsSelector.svelte
Normal file
@@ -0,0 +1,62 @@
|
||||
<script lang="ts">
|
||||
import Checkbox from '$lib/components/common/Checkbox.svelte';
|
||||
import Tooltip from '$lib/components/common/Tooltip.svelte';
|
||||
import { getContext, onMount } from 'svelte';
|
||||
|
||||
import { getSkillItems } from '$lib/apis/skills';
|
||||
|
||||
export let selectedSkillIds: string[] = [];
|
||||
|
||||
let _skills: Record<string, any> = {};
|
||||
|
||||
const i18n = getContext('i18n');
|
||||
|
||||
onMount(async () => {
|
||||
const res = await getSkillItems(localStorage.token).catch(() => null);
|
||||
const skills = res?.items ?? [];
|
||||
_skills = skills.reduce((acc: Record<string, any>, skill: any) => {
|
||||
acc[skill.id] = {
|
||||
...skill,
|
||||
selected: selectedSkillIds.includes(skill.id)
|
||||
};
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
});
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<div class="flex w-full justify-between mb-1">
|
||||
<div class=" self-center text-xs font-medium text-gray-500">{$i18n.t('Skills')}</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col mb-1">
|
||||
{#if Object.keys(_skills).length > 0}
|
||||
<div class=" flex items-center flex-wrap">
|
||||
{#each Object.keys(_skills) as skill, skillIdx}
|
||||
<div class=" flex items-center gap-2 mr-3">
|
||||
<div class="self-center flex items-center">
|
||||
<Checkbox
|
||||
state={_skills[skill].selected ? 'checked' : 'unchecked'}
|
||||
on:change={(e) => {
|
||||
_skills[skill].selected = e.detail === 'checked';
|
||||
selectedSkillIds = Object.keys(_skills).filter((s) => _skills[s].selected);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Tooltip content={_skills[skill]?.description ?? _skills[skill].id}>
|
||||
<div class=" py-0.5 text-sm w-full capitalize font-medium">
|
||||
{_skills[skill].name}
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class=" text-xs dark:text-gray-700">
|
||||
{$i18n.t('To select skills here, add them to the "Skills" workspace first.')}
|
||||
</div>
|
||||
</div>
|
||||
@@ -54,22 +54,7 @@
|
||||
let viewOption = '';
|
||||
let page = 1;
|
||||
|
||||
// Debounce only query changes
|
||||
$: if (query !== undefined) {
|
||||
loading = true;
|
||||
clearTimeout(searchDebounceTimer);
|
||||
searchDebounceTimer = setTimeout(() => {
|
||||
page = 1;
|
||||
getSkillItems();
|
||||
}, 300);
|
||||
}
|
||||
|
||||
// Immediate response to page/filter changes
|
||||
$: if (page && viewOption !== undefined) {
|
||||
getSkillItems();
|
||||
}
|
||||
|
||||
const getSkillItems = async () => {
|
||||
const loadSkillItems = async () => {
|
||||
if (!loaded) return;
|
||||
|
||||
loading = true;
|
||||
@@ -95,6 +80,21 @@
|
||||
}
|
||||
};
|
||||
|
||||
// Debounce only query changes
|
||||
$: if (query !== undefined) {
|
||||
loading = true;
|
||||
clearTimeout(searchDebounceTimer);
|
||||
searchDebounceTimer = setTimeout(() => {
|
||||
page = 1;
|
||||
loadSkillItems();
|
||||
}, 300);
|
||||
}
|
||||
|
||||
// Immediate response to page/filter changes
|
||||
$: if (page && viewOption !== undefined) {
|
||||
loadSkillItems();
|
||||
}
|
||||
|
||||
const cloneHandler = async (skill) => {
|
||||
const _skill = await getSkillById(localStorage.token, skill.id).catch((error) => {
|
||||
toast.error(`${error}`);
|
||||
@@ -136,7 +136,7 @@
|
||||
}
|
||||
|
||||
page = 1;
|
||||
getSkillItems();
|
||||
loadSkillItems();
|
||||
await _skills.set(await getSkills(localStorage.token));
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user