prism-models 0.6.2__py3-none-any.whl → 0.6.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
prism_models/__init__.py CHANGED
@@ -6,7 +6,7 @@ __version__ = "0.1.0"
6
6
  from prism_models.agent_profile import Agent, AgentCollectionAccess, AgentProfile, AgentProfileStatus, Profile, ProfileCollectionAccess
7
7
  from prism_models.base import POSTGRES_NAMING_CONVENTION, Base, BaseModel, TimestampMixin
8
8
  from prism_models.chat import Contact, Conversation, ConversationMessage, ConversationMessageMetadata, UserPreferences
9
- from prism_models.content import Chunk, ChunkConfig, Collection, CollectionDocument, Document, IntegrationConfig, QAPair, Source, Vector
9
+ from prism_models.content import Chunk, ChunkConfig, Collection, CollectionDocument, Document, IntegrationConfig, Source, Vector
10
10
  from prism_models.feedback import Augmentation, Feedback, FeedbackAnalysis, FeedbackStatus, FeedbackType
11
11
  from prism_models.qdrant import QdrantVectorPayload, DestinationVectorPayload, PydanticType
12
12
 
@@ -38,7 +38,6 @@ __all__ = [
38
38
  "Profile",
39
39
  "ProfileCollectionAccess",
40
40
  "PydanticType",
41
- "QAPair",
42
41
  "QdrantVectorPayload",
43
42
  "Source",
44
43
  "TimestampMixin",
prism_models/chat.py CHANGED
@@ -27,6 +27,22 @@ class ContactSource(PyEnum):
27
27
  MICROSOFT_AD = "MICROSOFT_AD"
28
28
 
29
29
 
30
+ class ContactRole(PyEnum):
31
+ """
32
+ Hierarchical permission roles for contacts.
33
+
34
+ Permission hierarchy (highest to lowest):
35
+ - ADMIN: Full access to all contacts in the system
36
+ - ACCOUNT_ADMIN: Full access to contacts within their account
37
+ - MANAGER: Can view/edit contacts in their team (direct reports)
38
+ - VIEWER: Read-only access to own data and limited team visibility
39
+ """
40
+ ADMIN = "ADMIN"
41
+ ACCOUNT_ADMIN = "ACCOUNT_ADMIN"
42
+ MANAGER = "MANAGER"
43
+ VIEWER = "VIEWER"
44
+
45
+
30
46
  class ConversationType(PyEnum):
31
47
  TRAVEL_GUIDE = "TRAVEL_GUIDE"
32
48
  MSA_CHAT = "MSA_CHAT"
@@ -91,6 +107,28 @@ class Contact(ChatSchemaMixin, BaseModel):
91
107
  azure_ad_object_id = Column(String(36), nullable=True, unique=True, index=True)
92
108
  azure_ad_tenant_id = Column(String(36), nullable=True, index=True)
93
109
 
110
+ # Hierarchical permission system
111
+ contact_role: Mapped[ContactRole] = mapped_column(
112
+ Enum(ContactRole),
113
+ default=ContactRole.VIEWER,
114
+ nullable=False,
115
+ server_default="VIEWER"
116
+ )
117
+ manager_contact_id = Column(
118
+ Integer,
119
+ ForeignKey("contact.id", ondelete="SET NULL"),
120
+ nullable=True,
121
+ index=True
122
+ )
123
+
124
+ # Self-referential relationship for hierarchy
125
+ manager = relationship(
126
+ "Contact",
127
+ remote_side="Contact.id",
128
+ foreign_keys=[manager_contact_id],
129
+ backref="direct_reports"
130
+ )
131
+
94
132
  conversations = relationship("Conversation", back_populates="contact", cascade="all, delete-orphan")
95
133
 
96
134
  # preferences relationship
prism_models/content.py CHANGED
@@ -4,21 +4,18 @@ from typing import Any, Optional
4
4
  from sqlalchemy import (
5
5
  JSON,
6
6
  Boolean,
7
- Column,
8
7
  Enum,
9
8
  Float,
10
9
  ForeignKey,
11
- Index,
12
10
  Integer,
13
11
  String,
14
- Table,
15
12
  Text,
16
13
  UniqueConstraint,
17
14
  )
18
15
  from sqlalchemy.dialects.postgresql import ARRAY
19
16
  from sqlalchemy.orm import Mapped, mapped_column, relationship
20
17
 
21
- from prism_models.base import Base, BaseModel
18
+ from prism_models.base import BaseModel
22
19
  from prism_models.chat import Contact
23
20
  from prism_models.qdrant import QdrantVectorPayload, PydanticType
24
21
  from prism_models.qdrant import SparseEmbedding
@@ -174,7 +171,6 @@ class Document(BaseModel):
174
171
  uploaded_by: Mapped[Optional["Contact"]] = relationship("Contact", foreign_keys=[uploaded_by_id])
175
172
  collections: Mapped[list["CollectionDocument"]] = relationship(back_populates="document")
176
173
  chunks: Mapped[list["Chunk"]] = relationship(back_populates="document", cascade="all, delete-orphan")
177
- qa_pairs: Mapped[list["QAPair"]] = relationship(back_populates="document", cascade="all, delete-orphan")
178
174
 
179
175
 
180
176
  def __repr__(self):
@@ -220,14 +216,6 @@ class ChunkConfig(BaseModel):
220
216
  documents: Mapped[list["Document"]] = relationship("Document", back_populates="chunk_config")
221
217
 
222
218
 
223
- qa_pair_chunk_association_table = Table(
224
- "qa_pair_chunk_association",
225
- Base.metadata,
226
- Column("qa_pair_id", ForeignKey("qa_pair.id"), primary_key=True),
227
- Column("chunk_id", ForeignKey("chunk.id"), primary_key=True),
228
- )
229
-
230
-
231
219
  class Chunk(BaseModel):
232
220
  document_id: Mapped[int] = mapped_column(ForeignKey("document.id"), nullable=False, index=True)
233
221
  chunk_config_id: Mapped[int | None] = mapped_column(ForeignKey("chunk_config.id"))
@@ -238,23 +226,10 @@ class Chunk(BaseModel):
238
226
 
239
227
  document: Mapped["Document"] = relationship(back_populates="chunks")
240
228
  chunk_config: Mapped[Optional["ChunkConfig"]] = relationship()
241
- qa_pairs: Mapped[list["QAPair"]] = relationship(secondary=qa_pair_chunk_association_table, back_populates="source_chunks")
242
229
  vector: Mapped[Optional["Vector"]] = relationship(back_populates="chunk", uselist=False, cascade="all, delete-orphan")
243
230
 
244
-
245
- class QAPair(BaseModel):
246
- document_id: Mapped[int] = mapped_column(ForeignKey("document.id"), nullable=False, index=True)
247
- question: Mapped[str] = mapped_column(Text, nullable=False)
248
- answer: Mapped[str] = mapped_column(Text, nullable=False)
249
- provenance: Mapped[ProvenanceType] = mapped_column(String(50), default=ProvenanceType.GENERATED)
250
- confidence_score: Mapped[float | None] = mapped_column(Float, nullable=True)
251
- document: Mapped["Document"] = relationship(back_populates="qa_pairs")
252
- source_chunks: Mapped[list["Chunk"]] = relationship(secondary=qa_pair_chunk_association_table, back_populates="qa_pairs")
253
- vector: Mapped[Optional["Vector"]] = relationship(back_populates="qa_pair", uselist=False, cascade="all, delete-orphan")
254
-
255
231
  class Vector(BaseModel):
256
232
  chunk_id: Mapped[int] = mapped_column(ForeignKey("chunk.id"), nullable=True, unique=True)
257
- qa_pair_id: Mapped[int] = mapped_column(ForeignKey("qa_pair.id"), nullable=True, unique=True)
258
233
  model: Mapped[str] = mapped_column(String(100))
259
234
  qdrant_point_id: Mapped[str | None] = mapped_column(String(100), unique=True)
260
235
 
@@ -273,4 +248,3 @@ class Vector(BaseModel):
273
248
  )
274
249
 
275
250
  chunk: Mapped["Chunk"] = relationship(back_populates="vector")
276
- qa_pair: Mapped["QAPair"] = relationship(back_populates="vector")
prism_models/feedback.py CHANGED
@@ -19,7 +19,7 @@ from sqlalchemy.orm import Mapped, mapped_column, relationship
19
19
 
20
20
  from prism_models.base import BaseModel
21
21
  from prism_models.chat import Contact, ConversationMessage
22
- from prism_models.content import Chunk, Document, QAPair
22
+ from prism_models.content import Chunk, Document
23
23
 
24
24
  # MessageFeedback model removed - using new Feedback model below
25
25
 
@@ -0,0 +1,79 @@
1
+ """REMOVED: QA PAIR CHUNK
2
+
3
+ Revision ID: 4d9291a3acb1
4
+ Revises: 6abdd3f001ab
5
+ Create Date: 2025-12-17 12:20:30.848462
6
+
7
+ """
8
+ from typing import Sequence, Union
9
+
10
+ from alembic import op
11
+ import sqlalchemy as sa
12
+ from sqlalchemy.dialects import postgresql
13
+
14
+ contact_role_enum = sa.Enum('ADMIN', 'ACCOUNT_ADMIN', 'MANAGER', 'VIEWER', name='contactrole')
15
+
16
+ # revision identifiers, used by Alembic.
17
+ revision: str = '4d9291a3acb1'
18
+ down_revision: Union[str, Sequence[str], None] = '6abdd3f001ab'
19
+ branch_labels: Union[str, Sequence[str], None] = None
20
+ depends_on: Union[str, Sequence[str], None] = None
21
+
22
+
23
+ def upgrade() -> None:
24
+ """Upgrade schema."""
25
+ # ### commands auto generated by Alembic - please adjust! ###
26
+ # Drop references to qa_pair before removing the table to satisfy FK constraints.
27
+ op.drop_constraint(op.f('vector_qa_pair_id_key'), 'vector', type_='unique')
28
+ op.drop_constraint(op.f('vector_qa_pair_id_fkey'), 'vector', type_='foreignkey')
29
+ op.drop_column('vector', 'qa_pair_id')
30
+
31
+ op.drop_table('qa_pair_chunk_association')
32
+ op.drop_index(op.f('qa_pair_document_id_idx'), table_name='qa_pair')
33
+ op.drop_index(op.f('qa_pair_id_idx'), table_name='qa_pair')
34
+ op.drop_table('qa_pair')
35
+ contact_role_enum.create(op.get_bind(), checkfirst=True)
36
+ op.add_column('contact', sa.Column('contact_role', contact_role_enum, server_default='VIEWER', nullable=False))
37
+ op.add_column('contact', sa.Column('manager_contact_id', sa.Integer(), nullable=True))
38
+ op.create_index(op.f('contact_manager_contact_id_idx'), 'contact', ['manager_contact_id'], unique=False)
39
+ op.create_foreign_key(op.f('contact_manager_contact_id_fkey'), 'contact', 'contact', ['manager_contact_id'], ['id'], ondelete='SET NULL')
40
+ op.drop_index(op.f('idx_document_title_trgm'), table_name='document', postgresql_ops={'title': 'gin_trgm_ops'}, postgresql_using='gin')
41
+ # ### end Alembic commands ###
42
+
43
+
44
+ def downgrade() -> None:
45
+ """Downgrade schema."""
46
+ # ### commands auto generated by Alembic - please adjust! ###
47
+ op.create_index(op.f('idx_document_title_trgm'), 'document', ['title'], unique=False, postgresql_ops={'title': 'gin_trgm_ops'}, postgresql_using='gin')
48
+ op.drop_constraint(op.f('contact_manager_contact_id_fkey'), 'contact', type_='foreignkey')
49
+ op.drop_index(op.f('contact_manager_contact_id_idx'), table_name='contact')
50
+ op.drop_column('contact', 'manager_contact_id')
51
+ op.drop_column('contact', 'contact_role')
52
+ contact_role_enum.drop(op.get_bind(), checkfirst=True)
53
+ op.create_table('qa_pair',
54
+ sa.Column('document_id', sa.INTEGER(), autoincrement=False, nullable=False),
55
+ sa.Column('question', sa.TEXT(), autoincrement=False, nullable=False),
56
+ sa.Column('answer', sa.TEXT(), autoincrement=False, nullable=False),
57
+ sa.Column('provenance', sa.VARCHAR(length=50), autoincrement=False, nullable=False),
58
+ sa.Column('confidence_score', sa.DOUBLE_PRECISION(precision=53), autoincrement=False, nullable=True),
59
+ sa.Column('id', sa.INTEGER(), server_default=sa.text("nextval('qa_pair_id_seq'::regclass)"), autoincrement=True, nullable=False),
60
+ sa.Column('created_at', postgresql.TIMESTAMP(timezone=True), server_default=sa.text('now()'), autoincrement=False, nullable=False),
61
+ sa.Column('updated_at', postgresql.TIMESTAMP(timezone=True), server_default=sa.text('now()'), autoincrement=False, nullable=False),
62
+ sa.Column('deleted_at', postgresql.TIMESTAMP(timezone=True), autoincrement=False, nullable=True),
63
+ sa.ForeignKeyConstraint(['document_id'], ['document.id'], name='qa_pair_document_id_fkey'),
64
+ sa.PrimaryKeyConstraint('id', name='qa_pair_pkey'),
65
+ postgresql_ignore_search_path=False
66
+ )
67
+ op.create_index(op.f('qa_pair_id_idx'), 'qa_pair', ['id'], unique=False)
68
+ op.create_index(op.f('qa_pair_document_id_idx'), 'qa_pair', ['document_id'], unique=False)
69
+ op.create_table('qa_pair_chunk_association',
70
+ sa.Column('qa_pair_id', sa.INTEGER(), autoincrement=False, nullable=False),
71
+ sa.Column('chunk_id', sa.INTEGER(), autoincrement=False, nullable=False),
72
+ sa.ForeignKeyConstraint(['chunk_id'], ['chunk.id'], name=op.f('qa_pair_chunk_association_chunk_id_fkey')),
73
+ sa.ForeignKeyConstraint(['qa_pair_id'], ['qa_pair.id'], name=op.f('qa_pair_chunk_association_qa_pair_id_fkey')),
74
+ sa.PrimaryKeyConstraint('qa_pair_id', 'chunk_id', name=op.f('qa_pair_chunk_association_pkey'))
75
+ )
76
+ op.add_column('vector', sa.Column('qa_pair_id', sa.INTEGER(), autoincrement=False, nullable=True))
77
+ op.create_foreign_key(op.f('vector_qa_pair_id_fkey'), 'vector', 'qa_pair', ['qa_pair_id'], ['id'])
78
+ op.create_unique_constraint(op.f('vector_qa_pair_id_key'), 'vector', ['qa_pair_id'], postgresql_nulls_not_distinct=False)
79
+ # ### end Alembic commands ###
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: prism-models
3
- Version: 0.6.2
3
+ Version: 0.6.4
4
4
  Requires-Python: >=3.12
5
5
  Requires-Dist: sqlalchemy[asyncio]>=2.0.0
6
6
  Requires-Dist: alembic>=1.16.0
@@ -1,10 +1,10 @@
1
- prism_models/__init__.py,sha256=MmKTV3lCKovI9BZVMtPvBdRDoJwttIbe0NoQdzDcj7k,1442
1
+ prism_models/__init__.py,sha256=Z4IOhsD992zLMKmo9a2eWdcxThSrl2N9igGn_mRKM_4,1420
2
2
  prism_models/agent_profile.py,sha256=SSZhrMSGYXr2Skc3niw1SiCZGK5JhwUyyH7Au-UXuPQ,7190
3
3
  prism_models/base.py,sha256=Ka8zNToTiTG0jNgzqqj2goGmPXt8zxuuSMYvotnb8wY,2281
4
- prism_models/chat.py,sha256=giEOHfG-22zmgH9Ca6ydce7pfzuOWSrORZPFEGNrz5g,13967
4
+ prism_models/chat.py,sha256=EwxENfZ2dkAwgrUzqcQZRRzbwiW7J_tJ53qBT2UvsDg,15055
5
5
  prism_models/config.py,sha256=gy_6HknnG17Clv8X_EBhaXEBFBLGR1PLjvN5-SFTo5E,962
6
- prism_models/content.py,sha256=wCBpqj3sxMMeDPmudHXmMcC1ekH7ynK2KO0rhr8QE00,11799
7
- prism_models/feedback.py,sha256=wOgF_hx0-b0Yn8CrVyC0hWHbcs3jIGVNe11dCv-BsW8,6710
6
+ prism_models/content.py,sha256=mzVZw54UiLIdWB9-A_HdjigJNNWBevmTMbGW6copXBM,10361
7
+ prism_models/feedback.py,sha256=Z2-Fj51xGhoC2j0i6NtkbqnWzPBzJV7F7g9nB7l18I0,6702
8
8
  prism_models/qdrant.py,sha256=Ta0fsLsxbT3Evdm8KEo-zw6IzoNckuWDmDZNfBtqjfA,3950
9
9
  prism_models/migration/README,sha256=MVlc9TYmr57RbhXET6QxgyCcwWP7w-vLkEsirENqiIQ,38
10
10
  prism_models/migration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -63,7 +63,8 @@ prism_models/migration/versions/2025_11_24_1124_dc57fb290621_added_conversation_
63
63
  prism_models/migration/versions/2025_11_25_1847_c6c36663acd5_added_user_preferences_table.py,sha256=4E51jRKENB-pU2yg_Pf2zxORWFqPfHcQ4aQmblPS4Ew,2438
64
64
  prism_models/migration/versions/2025_12_07_2236_88f01df468f2_added_sparse_embeddings_field_in_vector_.py,sha256=Qrg6ouy11sESaPJcfkfh9Vk8CoOW34vrMmF69OStZDg,995
65
65
  prism_models/migration/versions/2025_12_09_1146_6abdd3f001ab_adding_orchestrator_model_to_profile_.py,sha256=eiCgTyFW7TbifwXPbZtsYW9_UPYwyCMF4I7eXnMOTwQ,937
66
- prism_models-0.6.2.dist-info/METADATA,sha256=-8QMpG3bPU8ThGlOSaL5wVWtN0Ine3c9VnZtCWKhKkE,283
67
- prism_models-0.6.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
68
- prism_models-0.6.2.dist-info/top_level.txt,sha256=UNzqwpLgFYU0EoyB9LiB1jTtc89A1sQ24fSEyNVvgJI,13
69
- prism_models-0.6.2.dist-info/RECORD,,
66
+ prism_models/migration/versions/2025_12_17_1220_4d9291a3acb1_removed_qa_pair_chunk.py,sha256=QnbVia8YU2_Rp0LWFvbA2lUy7kmdrGLbDmTHw-YQAoM,4752
67
+ prism_models-0.6.4.dist-info/METADATA,sha256=W3MMiA5CcdMhLTsxcRPLD5HYZjBLro5OXoov5VaIofg,283
68
+ prism_models-0.6.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
69
+ prism_models-0.6.4.dist-info/top_level.txt,sha256=UNzqwpLgFYU0EoyB9LiB1jTtc89A1sQ24fSEyNVvgJI,13
70
+ prism_models-0.6.4.dist-info/RECORD,,