-
Notifications
You must be signed in to change notification settings - Fork 175
Expand file tree
/
Copy pathrelationship.py
More file actions
110 lines (97 loc) · 3.87 KB
/
relationship.py
File metadata and controls
110 lines (97 loc) · 3.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
from datetime import datetime
from app.utils.singleflight_cache import singleflight_cache
from typing import Optional, Type
from uuid import UUID
from pydantic import BaseModel
from sqlalchemy import Column, Text, JSON, DateTime
from sqlmodel import (
SQLModel,
Field,
Relationship as SQLRelationship,
)
from tidb_vector.sqlalchemy import VectorType
from app.models.entity import get_kb_entity_model
from app.models.knowledge_base import KnowledgeBase
from app.models.knowledge_base_scoped.table_naming import get_kb_vector_dims
from app.utils.namespace import format_namespace
from app.logger import logger
class RelationshipPublic(BaseModel):
id: int
description: str
source_entity_id: int
target_entity_id: int
meta: dict = Field(default_factory=dict)
weight: Optional[int] = Field(default=0)
last_modified_at: Optional[datetime] = Field(default=None)
document_id: Optional[int] = Field(default=None)
chunk_id: Optional[UUID] = Field(default=None)
def get_kb_relationship_model(kb: KnowledgeBase) -> Type[SQLModel]:
vector_dimension = get_kb_vector_dims(kb)
entity_model = get_kb_entity_model(kb)
return get_dynamic_relationship_model(vector_dimension, str(kb.id), entity_model)
@singleflight_cache
def get_dynamic_relationship_model(
vector_dimension: int,
namespace: Optional[str] = None,
entity_model: Optional[Type[SQLModel]] = None,
) -> Type[SQLModel]:
namespace = format_namespace(namespace)
entity_table_name = entity_model.__tablename__
entity_model_name = entity_model.__name__
relationship_table_name = f"relationships_{namespace}"
relationship_model_name = f"Relationship_{namespace}_{vector_dimension}"
logger.info(
"Dynamic create relationship model (dimension: %s, table: %s, model: %s)",
vector_dimension,
relationship_table_name,
relationship_model_name,
)
class Relationship(SQLModel):
id: Optional[int] = Field(default=None, primary_key=True)
description: str = Field(sa_column=Column(Text))
meta: dict = Field(default_factory=dict, sa_column=Column(JSON))
weight: int = 0
source_entity_id: int = Field(foreign_key=f"{entity_table_name}.id")
target_entity_id: int = Field(foreign_key=f"{entity_table_name}.id")
last_modified_at: Optional[datetime] = Field(sa_column=Column(DateTime))
document_id: Optional[int] = Field(default=None, nullable=True)
chunk_id: Optional[UUID] = Field(default=None, nullable=True)
description_vec: list[float] = Field(sa_type=VectorType(vector_dimension))
def __hash__(self):
return hash(self.id)
def screenshot(self):
obj_dict = self.model_dump(
exclude={
"description_vec",
"source_entity",
"target_entity",
"last_modified_at",
}
)
return obj_dict
relationship_model = type(
relationship_model_name,
(Relationship,),
{
"__tablename__": relationship_table_name,
"__table_args__": {"extend_existing": True},
"__annotations__": {
"source_entity": entity_model,
"target_entity": entity_model,
},
"source_entity": SQLRelationship(
sa_relationship_kwargs={
"primaryjoin": f"{relationship_model_name}.source_entity_id == {entity_model_name}.id",
"lazy": "joined",
},
),
"target_entity": SQLRelationship(
sa_relationship_kwargs={
"primaryjoin": f"{relationship_model_name}.target_entity_id == {entity_model_name}.id",
"lazy": "joined",
},
),
},
table=True,
)
return relationship_model