open-webui/backend/open_webui/models/knowledge.py

242 lines
7.3 KiB
Python
Raw Normal View History

2024-10-02 08:35:35 +08:00
import json
import logging
import time
from typing import Optional
2024-10-02 12:32:59 +08:00
import uuid
2024-10-02 08:35:35 +08:00
2024-12-10 16:54:13 +08:00
from open_webui.internal.db import Base, get_db
2024-10-02 08:35:35 +08:00
from open_webui.env import SRC_LOG_LEVELS
2024-12-10 16:54:13 +08:00
from open_webui.models.files import FileMetadataResponse
from open_webui.models.groups import Groups
2024-12-10 16:54:13 +08:00
from open_webui.models.users import Users, UserResponse
2024-10-02 08:35:35 +08:00
from pydantic import BaseModel, ConfigDict
from sqlalchemy import BigInteger, Column, String, Text, JSON
2024-11-17 08:51:55 +08:00
from open_webui.utils.access_control import has_access
2024-10-02 08:35:35 +08:00
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["MODELS"])
####################
2024-10-02 13:45:04 +08:00
# Knowledge DB Schema
2024-10-02 08:35:35 +08:00
####################
2024-10-02 13:45:04 +08:00
class Knowledge(Base):
__tablename__ = "knowledge"
2024-10-02 08:35:35 +08:00
id = Column(Text, unique=True, primary_key=True)
user_id = Column(Text)
name = Column(Text)
description = Column(Text)
data = Column(JSON, nullable=True)
meta = Column(JSON, nullable=True)
2024-11-15 10:57:25 +08:00
access_control = Column(JSON, nullable=True) # Controls data access levels.
2024-11-15 12:13:43 +08:00
# Defines access control rules for this entry.
# - `None`: Public access, available to all users with the "user" role.
# - `{}`: Private access, restricted exclusively to the owner.
# - Custom permissions: Specific access control for reading and writing;
# Can specify group or user-level restrictions:
# {
# "read": {
# "group_ids": ["group_id1", "group_id2"],
# "user_ids": ["user_id1", "user_id2"]
# },
# "write": {
# "group_ids": ["group_id1", "group_id2"],
# "user_ids": ["user_id1", "user_id2"]
# }
# }
2024-11-15 10:57:25 +08:00
2024-10-02 08:35:35 +08:00
created_at = Column(BigInteger)
updated_at = Column(BigInteger)
2024-10-02 13:45:04 +08:00
class KnowledgeModel(BaseModel):
2024-10-02 08:35:35 +08:00
model_config = ConfigDict(from_attributes=True)
id: str
user_id: str
name: str
description: str
data: Optional[dict] = None
meta: Optional[dict] = None
2024-11-15 12:13:43 +08:00
access_control: Optional[dict] = None
2024-11-15 10:57:25 +08:00
2024-10-02 08:35:35 +08:00
created_at: int # timestamp in epoch
updated_at: int # timestamp in epoch
####################
# Forms
####################
2024-11-18 21:51:01 +08:00
class KnowledgeUserModel(KnowledgeModel):
user: Optional[UserResponse] = None
class KnowledgeResponse(KnowledgeModel):
files: Optional[list[FileMetadataResponse | dict]] = None
2024-11-17 12:47:45 +08:00
2024-10-02 08:35:35 +08:00
2024-11-18 21:51:01 +08:00
class KnowledgeUserResponse(KnowledgeUserModel):
files: Optional[list[FileMetadataResponse | dict]] = None
2024-10-02 08:35:35 +08:00
2024-10-02 13:45:04 +08:00
class KnowledgeForm(BaseModel):
2024-10-02 08:35:35 +08:00
name: str
description: str
data: Optional[dict] = None
2024-11-17 12:47:45 +08:00
access_control: Optional[dict] = None
2024-10-03 11:42:10 +08:00
2024-10-02 13:45:04 +08:00
class KnowledgeTable:
def insert_new_knowledge(
self, user_id: str, form_data: KnowledgeForm
) -> Optional[KnowledgeModel]:
2024-10-02 08:35:35 +08:00
with get_db() as db:
2024-10-02 13:45:04 +08:00
knowledge = KnowledgeModel(
2024-10-02 08:35:35 +08:00
**{
**form_data.model_dump(),
2024-10-02 12:32:59 +08:00
"id": str(uuid.uuid4()),
2024-10-02 08:35:35 +08:00
"user_id": user_id,
"created_at": int(time.time()),
"updated_at": int(time.time()),
}
)
try:
2024-10-02 13:45:04 +08:00
result = Knowledge(**knowledge.model_dump())
2024-10-02 08:35:35 +08:00
db.add(result)
db.commit()
db.refresh(result)
if result:
2024-10-02 13:45:04 +08:00
return KnowledgeModel.model_validate(result)
2024-10-02 08:35:35 +08:00
else:
return None
except Exception:
return None
2024-11-18 21:51:01 +08:00
def get_knowledge_bases(self) -> list[KnowledgeUserModel]:
2024-10-02 08:35:35 +08:00
with get_db() as db:
all_knowledge = (
db.query(Knowledge).order_by(Knowledge.updated_at.desc()).all()
)
user_ids = list(set(knowledge.user_id for knowledge in all_knowledge))
users = Users.get_users_by_user_ids(user_ids) if user_ids else []
users_dict = {user.id: user for user in users}
2024-11-20 08:47:35 +08:00
knowledge_bases = []
for knowledge in all_knowledge:
user = users_dict.get(knowledge.user_id)
2024-11-20 08:47:35 +08:00
knowledge_bases.append(
KnowledgeUserModel.model_validate(
{
**KnowledgeModel.model_validate(knowledge).model_dump(),
"user": user.model_dump() if user else None,
}
)
2024-11-18 21:51:01 +08:00
)
2024-11-20 08:47:35 +08:00
return knowledge_bases
2024-10-02 08:35:35 +08:00
def check_access_by_user_id(self, id, user_id, permission="write") -> bool:
knowledge = self.get_knowledge_by_id(id)
if not knowledge:
return False
if knowledge.user_id == user_id:
return True
user_group_ids = {group.id for group in Groups.get_groups_by_member_id(user_id)}
return has_access(user_id, permission, knowledge.access_control, user_group_ids)
2024-11-17 08:51:55 +08:00
def get_knowledge_bases_by_user_id(
self, user_id: str, permission: str = "write"
2024-11-18 21:51:01 +08:00
) -> list[KnowledgeUserModel]:
2024-11-17 08:51:55 +08:00
knowledge_bases = self.get_knowledge_bases()
user_group_ids = {group.id for group in Groups.get_groups_by_member_id(user_id)}
2024-11-17 08:51:55 +08:00
return [
knowledge_base
for knowledge_base in knowledge_bases
if knowledge_base.user_id == user_id
or has_access(
user_id, permission, knowledge_base.access_control, user_group_ids
)
2024-11-17 08:51:55 +08:00
]
2024-10-02 13:45:04 +08:00
def get_knowledge_by_id(self, id: str) -> Optional[KnowledgeModel]:
2024-10-02 08:35:35 +08:00
try:
with get_db() as db:
2024-10-02 13:45:04 +08:00
knowledge = db.query(Knowledge).filter_by(id=id).first()
return KnowledgeModel.model_validate(knowledge) if knowledge else None
2024-10-02 08:35:35 +08:00
except Exception:
return None
2024-10-02 13:45:04 +08:00
def update_knowledge_by_id(
2024-11-17 12:47:45 +08:00
self, id: str, form_data: KnowledgeForm, overwrite: bool = False
) -> Optional[KnowledgeModel]:
try:
with get_db() as db:
knowledge = self.get_knowledge_by_id(id=id)
db.query(Knowledge).filter_by(id=id).update(
{
**form_data.model_dump(),
"updated_at": int(time.time()),
}
)
db.commit()
return self.get_knowledge_by_id(id=id)
except Exception as e:
log.exception(e)
return None
def update_knowledge_data_by_id(
self, id: str, data: dict
2024-10-02 13:45:04 +08:00
) -> Optional[KnowledgeModel]:
2024-10-02 08:35:35 +08:00
try:
with get_db() as db:
2024-10-03 21:46:20 +08:00
knowledge = self.get_knowledge_by_id(id=id)
2024-10-02 13:45:04 +08:00
db.query(Knowledge).filter_by(id=id).update(
2024-10-02 08:35:35 +08:00
{
2024-11-17 12:47:45 +08:00
"data": data,
2024-10-03 11:42:10 +08:00
"updated_at": int(time.time()),
2024-10-02 08:35:35 +08:00
}
)
db.commit()
2024-10-03 11:42:10 +08:00
return self.get_knowledge_by_id(id=id)
2024-10-02 08:35:35 +08:00
except Exception as e:
log.exception(e)
return None
2024-10-02 13:45:04 +08:00
def delete_knowledge_by_id(self, id: str) -> bool:
2024-10-02 08:35:35 +08:00
try:
with get_db() as db:
2024-10-02 13:45:04 +08:00
db.query(Knowledge).filter_by(id=id).delete()
2024-10-02 08:35:35 +08:00
db.commit()
return True
except Exception:
return False
2024-10-13 18:02:02 +08:00
def delete_all_knowledge(self) -> bool:
with get_db() as db:
try:
db.query(Knowledge).delete()
db.commit()
return True
except Exception:
return False
2024-10-02 08:35:35 +08:00
2024-10-02 13:45:04 +08:00
Knowledges = KnowledgeTable()