mirror of
https://github.com/open-webui/open-webui
synced 2024-11-22 08:07:55 +00:00
enh: tools user info
This commit is contained in:
parent
43ffd61aeb
commit
c50b678dce
@ -2,7 +2,7 @@ import time
|
||||
from typing import Optional
|
||||
|
||||
from open_webui.apps.webui.internal.db import Base, get_db
|
||||
from open_webui.apps.webui.models.groups import Groups
|
||||
from open_webui.apps.webui.models.users import Users, UserResponse
|
||||
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
from sqlalchemy import BigInteger, Column, String, Text, JSON
|
||||
@ -57,6 +57,10 @@ class PromptModel(BaseModel):
|
||||
####################
|
||||
|
||||
|
||||
class PromptUserResponse(PromptModel):
|
||||
user: Optional[UserResponse] = None
|
||||
|
||||
|
||||
class PromptForm(BaseModel):
|
||||
command: str
|
||||
title: str
|
||||
@ -97,15 +101,21 @@ class PromptsTable:
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def get_prompts(self) -> list[PromptModel]:
|
||||
def get_prompts(self) -> list[PromptUserResponse]:
|
||||
with get_db() as db:
|
||||
return [
|
||||
PromptModel.model_validate(prompt) for prompt in db.query(Prompt).all()
|
||||
PromptUserResponse.model_validate(
|
||||
{
|
||||
**PromptModel.model_validate(prompt).model_dump(),
|
||||
"user": Users.get_user_by_id(prompt.user_id).model_dump(),
|
||||
}
|
||||
)
|
||||
for prompt in db.query(Prompt).all()
|
||||
]
|
||||
|
||||
def get_prompts_by_user_id(
|
||||
self, user_id: str, permission: str = "write"
|
||||
) -> list[PromptModel]:
|
||||
) -> list[PromptUserResponse]:
|
||||
prompts = self.get_prompts()
|
||||
|
||||
return [
|
||||
|
@ -3,7 +3,7 @@ import time
|
||||
from typing import Optional
|
||||
|
||||
from open_webui.apps.webui.internal.db import Base, JSONField, get_db
|
||||
from open_webui.apps.webui.models.users import Users
|
||||
from open_webui.apps.webui.models.users import Users, UserResponse
|
||||
from open_webui.env import SRC_LOG_LEVELS
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
from sqlalchemy import BigInteger, Column, String, Text, JSON
|
||||
@ -86,6 +86,10 @@ class ToolResponse(BaseModel):
|
||||
created_at: int # timestamp in epoch
|
||||
|
||||
|
||||
class ToolUserResponse(ToolResponse):
|
||||
user: Optional[UserResponse] = None
|
||||
|
||||
|
||||
class ToolForm(BaseModel):
|
||||
id: str
|
||||
name: str
|
||||
@ -134,13 +138,21 @@ class ToolsTable:
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def get_tools(self) -> list[ToolModel]:
|
||||
def get_tools(self) -> list[ToolUserResponse]:
|
||||
with get_db() as db:
|
||||
return [ToolModel.model_validate(tool) for tool in db.query(Tool).all()]
|
||||
return [
|
||||
ToolUserResponse.model_validate(
|
||||
{
|
||||
**ToolModel.model_validate(tool).model_dump(),
|
||||
"user": Users.get_user_by_id(tool.user_id).model_dump(),
|
||||
}
|
||||
)
|
||||
for tool in db.query(Tool).order_by(Tool.updated_at.desc()).all()
|
||||
]
|
||||
|
||||
def get_tools_by_user_id(
|
||||
self, user_id: str, permission: str = "write"
|
||||
) -> list[ToolModel]:
|
||||
) -> list[ToolUserResponse]:
|
||||
tools = self.get_tools()
|
||||
|
||||
return [
|
||||
|
@ -1,6 +1,11 @@
|
||||
from typing import Optional
|
||||
|
||||
from open_webui.apps.webui.models.prompts import PromptForm, PromptModel, Prompts
|
||||
from open_webui.apps.webui.models.prompts import (
|
||||
PromptForm,
|
||||
PromptUserResponse,
|
||||
PromptModel,
|
||||
Prompts,
|
||||
)
|
||||
from open_webui.constants import ERROR_MESSAGES
|
||||
from fastapi import APIRouter, Depends, HTTPException, status, Request
|
||||
from open_webui.utils.utils import get_admin_user, get_verified_user
|
||||
@ -23,7 +28,7 @@ async def get_prompts(user=Depends(get_verified_user)):
|
||||
return prompts
|
||||
|
||||
|
||||
@router.get("/list", response_model=list[PromptModel])
|
||||
@router.get("/list", response_model=list[PromptUserResponse])
|
||||
async def get_prompt_list(user=Depends(get_verified_user)):
|
||||
if user.role == "admin":
|
||||
prompts = Prompts.get_prompts()
|
||||
|
@ -2,7 +2,13 @@ import os
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
from open_webui.apps.webui.models.tools import ToolForm, ToolModel, ToolResponse, Tools
|
||||
from open_webui.apps.webui.models.tools import (
|
||||
ToolForm,
|
||||
ToolModel,
|
||||
ToolResponse,
|
||||
ToolUserResponse,
|
||||
Tools,
|
||||
)
|
||||
from open_webui.apps.webui.utils import load_tools_module_by_id, replace_imports
|
||||
from open_webui.config import CACHE_DIR, DATA_DIR
|
||||
from open_webui.constants import ERROR_MESSAGES
|
||||
@ -19,7 +25,7 @@ router = APIRouter()
|
||||
############################
|
||||
|
||||
|
||||
@router.get("/", response_model=list[ToolResponse])
|
||||
@router.get("/", response_model=list[ToolUserResponse])
|
||||
async def get_tools(user=Depends(get_verified_user)):
|
||||
if user.role == "admin":
|
||||
tools = Tools.get_tools()
|
||||
@ -33,7 +39,7 @@ async def get_tools(user=Depends(get_verified_user)):
|
||||
############################
|
||||
|
||||
|
||||
@router.get("/list", response_model=list[ToolResponse])
|
||||
@router.get("/list", response_model=list[ToolUserResponse])
|
||||
async def get_tool_list(user=Depends(get_verified_user)):
|
||||
if user.role == "admin":
|
||||
tools = Tools.get_tools()
|
||||
|
@ -84,7 +84,7 @@
|
||||
}}
|
||||
/>
|
||||
|
||||
<div class="flex flex-col gap-1 mt-1.5 mb-2">
|
||||
<div class="flex flex-col gap-1 my-1.5">
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="flex md:self-center text-xl font-medium px-0.5 items-center">
|
||||
{$i18n.t('Knowledge')}
|
||||
@ -121,10 +121,10 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="my-3 mb-5 grid lg:grid-cols-2 xl:grid-cols-3 gap-2">
|
||||
<div class="mb-5 grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-2">
|
||||
{#each filteredItems as item}
|
||||
<button
|
||||
class=" flex space-x-4 cursor-pointer text-left w-full px-4 py-3 border border-gray-50 dark:border-gray-850 dark:hover:border-gray-800 hover:bg-gray-50 dark:hover:bg-gray-850 transition rounded-xl"
|
||||
class=" flex space-x-4 cursor-pointer text-left w-full px-4 py-3 hover:bg-gray-50 dark:hover:bg-gray-850 transition rounded-xl"
|
||||
on:click={() => {
|
||||
if (item?.meta?.document) {
|
||||
toast.error(
|
||||
@ -163,7 +163,7 @@
|
||||
</div>
|
||||
|
||||
<div class="mt-3 flex justify-between">
|
||||
<div class="text-xs">
|
||||
<div class="text-xs text-gray-500">
|
||||
<Tooltip
|
||||
content={item?.user?.email}
|
||||
className="flex shrink-0"
|
||||
|
@ -196,7 +196,7 @@
|
||||
}}
|
||||
/>
|
||||
|
||||
<div class="flex flex-col gap-1 mt-1.5 mb-2">
|
||||
<div class="flex flex-col gap-1 my-1.5">
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="flex items-center md:self-center text-xl font-medium px-0.5">
|
||||
{$i18n.t('Models')}
|
||||
@ -230,14 +230,14 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" my-2 mb-5 grid gap-2 md:grid-cols-2 lg:grid-cols-3" id="model-list">
|
||||
<div class=" my-2 mb-5 gap-2 grid lg:grid-cols-2 xl:grid-cols-3" id="model-list">
|
||||
{#each filteredModels as model}
|
||||
<div
|
||||
class=" flex flex-col cursor-pointer w-full px-3 py-2 dark:hover:bg-white/5 hover:bg-black/5 rounded-lg transition"
|
||||
id="model-item-{model.id}"
|
||||
>
|
||||
<div class="flex gap-4 mt-1 mb-0.5">
|
||||
<div class=" w-10">
|
||||
<div class=" w-[44px]">
|
||||
<div
|
||||
class=" rounded-full object-cover {model.is_active
|
||||
? ''
|
||||
@ -252,7 +252,7 @@
|
||||
</div>
|
||||
|
||||
<a
|
||||
class=" flex flex-1 space-x-3.5 cursor-pointer w-full"
|
||||
class=" flex flex-1 cursor-pointer w-full"
|
||||
href={`/?models=${encodeURIComponent(model.id)}`}
|
||||
>
|
||||
<div class=" flex-1 self-center {model.is_active ? '' : 'text-gray-500'}">
|
||||
@ -261,7 +261,7 @@
|
||||
className=" w-fit"
|
||||
placement="top-start"
|
||||
>
|
||||
<div class=" font-medium line-clamp-1">{model.name}</div>
|
||||
<div class=" font-semibold line-clamp-1">{model.name}</div>
|
||||
</Tooltip>
|
||||
|
||||
<div class="flex gap-1 text-xs overflow-hidden">
|
||||
@ -278,7 +278,7 @@
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between items-center">
|
||||
<div class=" text-xs">
|
||||
<div class=" text-xs mt-1">
|
||||
<Tooltip content={model?.user?.email} className="flex shrink-0" placement="top-start">
|
||||
<div class="shrink-0 text-gray-500">
|
||||
{$i18n.t('By {{name}}', {
|
||||
|
@ -21,6 +21,8 @@
|
||||
import Plus from '../icons/Plus.svelte';
|
||||
import ChevronRight from '../icons/ChevronRight.svelte';
|
||||
import Spinner from '../common/Spinner.svelte';
|
||||
import Tooltip from '../common/Tooltip.svelte';
|
||||
import { capitalizeFirstLetter } from '$lib/utils';
|
||||
|
||||
const i18n = getContext('i18n');
|
||||
let promptsImportInputElement: HTMLInputElement;
|
||||
@ -103,7 +105,7 @@
|
||||
</div>
|
||||
</DeleteConfirmDialog>
|
||||
|
||||
<div class="flex flex-col gap-1 mt-1.5 mb-2">
|
||||
<div class="flex flex-col gap-1 my-1.5">
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="flex md:self-center text-xl font-medium px-0.5 items-center">
|
||||
{$i18n.t('Prompts')}
|
||||
@ -137,19 +139,33 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-5">
|
||||
<div class="mb-5 gap-2 grid lg:grid-cols-2 xl:grid-cols-3">
|
||||
{#each filteredItems as prompt}
|
||||
<div
|
||||
class=" flex space-x-4 cursor-pointer w-full px-3 py-2 dark:hover:bg-white/5 hover:bg-black/5 rounded-xl"
|
||||
class=" flex space-x-4 cursor-pointer w-full px-3 py-2 dark:hover:bg-white/5 hover:bg-black/5 rounded-xl transition"
|
||||
>
|
||||
<div class=" flex flex-1 space-x-4 cursor-pointer w-full">
|
||||
<a href={`/workspace/prompts/edit?command=${encodeURIComponent(prompt.command)}`}>
|
||||
<div class=" flex-1 self-center pl-1.5">
|
||||
<div class=" font-semibold line-clamp-1">{prompt.command}</div>
|
||||
<div class=" flex-1 flex items-center gap-2 self-center">
|
||||
<div class=" font-semibold line-clamp-1 capitalize">{prompt.title}</div>
|
||||
<div class=" text-xs overflow-hidden text-ellipsis line-clamp-1">
|
||||
{prompt.title}
|
||||
{prompt.command}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" text-xs">
|
||||
<Tooltip
|
||||
content={prompt?.user?.email}
|
||||
className="flex shrink-0"
|
||||
placement="top-start"
|
||||
>
|
||||
<div class="shrink-0 text-gray-500">
|
||||
{$i18n.t('By {{name}}', {
|
||||
name: capitalizeFirstLetter(prompt?.user?.name ?? prompt?.user?.email)
|
||||
})}
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="flex flex-row gap-0.5 self-center">
|
||||
|
@ -30,6 +30,7 @@
|
||||
import Plus from '../icons/Plus.svelte';
|
||||
import ChevronRight from '../icons/ChevronRight.svelte';
|
||||
import Spinner from '../common/Spinner.svelte';
|
||||
import { capitalizeFirstLetter } from '$lib/utils';
|
||||
|
||||
const i18n = getContext('i18n');
|
||||
|
||||
@ -172,7 +173,7 @@
|
||||
</svelte:head>
|
||||
|
||||
{#if loaded}
|
||||
<div class="flex flex-col gap-1 mt-1.5 mb-2">
|
||||
<div class="flex flex-col gap-1 my-1.5">
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="flex md:self-center text-xl font-medium px-0.5 items-center">
|
||||
{$i18n.t('Tools')}
|
||||
@ -206,10 +207,10 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-5">
|
||||
<div class="mb-5 gap-2 grid lg:grid-cols-2 xl:grid-cols-3">
|
||||
{#each filteredItems as tool}
|
||||
<div
|
||||
class=" flex space-x-4 cursor-pointer w-full px-3 py-2 dark:hover:bg-white/5 hover:bg-black/5 rounded-xl"
|
||||
class=" flex space-x-4 cursor-pointer w-full px-3 py-2 dark:hover:bg-white/5 hover:bg-black/5 rounded-xl transition"
|
||||
>
|
||||
<a
|
||||
class=" flex flex-1 space-x-3.5 cursor-pointer w-full"
|
||||
@ -217,33 +218,47 @@
|
||||
>
|
||||
<div class="flex items-center text-left">
|
||||
<div class=" flex-1 self-center pl-1">
|
||||
<div class=" font-semibold flex items-center gap-1.5">
|
||||
<div
|
||||
class=" text-xs font-bold px-1 rounded uppercase line-clamp-1 bg-gray-500/20 text-gray-700 dark:text-gray-200"
|
||||
>
|
||||
TOOL
|
||||
</div>
|
||||
|
||||
{#if tool?.meta?.manifest?.version}
|
||||
<Tooltip content={tool?.meta?.description ?? ''} placement="top-start">
|
||||
<div class=" font-semibold flex items-center gap-1.5">
|
||||
<div
|
||||
class="text-xs font-bold px-1 rounded line-clamp-1 bg-gray-500/20 text-gray-700 dark:text-gray-200"
|
||||
class=" text-xs font-bold px-1 rounded uppercase line-clamp-1 bg-gray-500/20 text-gray-700 dark:text-gray-200"
|
||||
>
|
||||
v{tool?.meta?.manifest?.version ?? ''}
|
||||
TOOL
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="line-clamp-1">
|
||||
{tool.name}
|
||||
{#if tool?.meta?.manifest?.version}
|
||||
<div
|
||||
class="text-xs font-bold px-1 rounded line-clamp-1 bg-gray-500/20 text-gray-700 dark:text-gray-200"
|
||||
>
|
||||
v{tool?.meta?.manifest?.version ?? ''}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="line-clamp-1">
|
||||
{tool.name}
|
||||
|
||||
<span class=" text-gray-500 text-xs font-medium flex-shrink-0">{tool.id}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-1.5 px-1">
|
||||
<div class=" text-gray-500 text-xs font-medium flex-shrink-0">{tool.id}</div>
|
||||
</Tooltip>
|
||||
|
||||
<div class="flex gap-1.5 mb-0.5">
|
||||
<div class=" text-xs overflow-hidden text-ellipsis line-clamp-1">
|
||||
{tool.meta.description}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-xs text-gray-500 shrink-0">
|
||||
<Tooltip
|
||||
content={tool?.user?.email}
|
||||
className="flex shrink-0"
|
||||
placement="top-start"
|
||||
>
|
||||
{$i18n.t('By {{name}}', {
|
||||
name: capitalizeFirstLetter(tool?.user?.name ?? tool?.user?.email)
|
||||
})}
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
Loading…
Reference in New Issue
Block a user