slide-narrator 0.2.1__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.

Potentially problematic release.


This version of slide-narrator might be problematic. Click here for more details.

narrator/__init__.py ADDED
@@ -0,0 +1,18 @@
1
+ """
2
+ The Narrator - Thread and file storage components for conversational AI
3
+ """
4
+
5
+ from .database.thread_store import ThreadStore
6
+ from .storage.file_store import FileStore
7
+ from .models.thread import Thread
8
+ from .models.message import Message
9
+ from .models.attachment import Attachment
10
+
11
+ __version__ = "0.2.1"
12
+ __all__ = [
13
+ "ThreadStore",
14
+ "FileStore",
15
+ "Thread",
16
+ "Message",
17
+ "Attachment",
18
+ ]
@@ -0,0 +1,8 @@
1
+ """
2
+ Database package for Tyler Stores
3
+ """
4
+
5
+ from .thread_store import ThreadStore
6
+ from .models import ThreadRecord, MessageRecord
7
+
8
+ __all__ = ["ThreadStore", "ThreadRecord", "MessageRecord"]
@@ -0,0 +1,66 @@
1
+ """Database CLI for Tyler Stores"""
2
+ import asyncio
3
+ import click
4
+ from .thread_store import ThreadStore
5
+ from ..utils.logging import get_logger
6
+
7
+ logger = get_logger(__name__)
8
+
9
+ @click.group()
10
+ def main():
11
+ """Tyler Stores Database CLI"""
12
+ pass
13
+
14
+ @click.command()
15
+ @click.option('--database-url', help='Database URL for initialization')
16
+ async def init(database_url):
17
+ """Initialize database tables"""
18
+ try:
19
+ if database_url:
20
+ store = await ThreadStore.create(database_url)
21
+ else:
22
+ # Use environment variables or default
23
+ store = await ThreadStore.create()
24
+
25
+ logger.info("Database initialized successfully")
26
+ click.echo("Database initialized successfully")
27
+ except Exception as e:
28
+ logger.error(f"Failed to initialize database: {e}")
29
+ click.echo(f"Error: Failed to initialize database: {e}")
30
+ raise click.Abort()
31
+
32
+ @click.command()
33
+ @click.option('--database-url', help='Database URL')
34
+ async def status(database_url):
35
+ """Check database status"""
36
+ try:
37
+ if database_url:
38
+ store = await ThreadStore.create(database_url)
39
+ else:
40
+ store = await ThreadStore.create()
41
+
42
+ # Get some basic stats
43
+ threads = await store.list_recent(limit=5)
44
+ click.echo(f"Database connection: OK")
45
+ click.echo(f"Recent threads count: {len(threads)}")
46
+
47
+ except Exception as e:
48
+ logger.error(f"Database status check failed: {e}")
49
+ click.echo(f"Error: Database status check failed: {e}")
50
+ raise click.Abort()
51
+
52
+ # Add async wrapper for commands
53
+ def async_command(f):
54
+ def wrapper(*args, **kwargs):
55
+ return asyncio.run(f(*args, **kwargs))
56
+ return wrapper
57
+
58
+ # Apply async wrapper to commands
59
+ init = click.command()(async_command(init))
60
+ status = click.command()(async_command(status))
61
+
62
+ main.add_command(init)
63
+ main.add_command(status)
64
+
65
+ if __name__ == '__main__':
66
+ main()
@@ -0,0 +1,6 @@
1
+ """
2
+ Database migrations for Tyler Stores
3
+
4
+ This directory will contain future database migrations.
5
+ For new installations, the schema is created directly from the models.
6
+ """
@@ -0,0 +1,69 @@
1
+ import json
2
+ from sqlalchemy.types import TypeDecorator, TEXT, JSON
3
+
4
+ """Database models for SQLAlchemy"""
5
+ from sqlalchemy import Column, String, DateTime, Text, ForeignKey, Integer
6
+ from sqlalchemy.dialects.postgresql import JSONB
7
+ from sqlalchemy.orm import declarative_base
8
+ from sqlalchemy.orm import relationship
9
+ from datetime import datetime, UTC
10
+
11
+ class JSONBCompat(TypeDecorator):
12
+ impl = TEXT
13
+ cache_ok = True
14
+
15
+ def load_dialect_impl(self, dialect):
16
+ if dialect.name == 'postgresql':
17
+ return dialect.type_descriptor(JSONB())
18
+ else:
19
+ return dialect.type_descriptor(JSON())
20
+
21
+ def process_bind_param(self, value, dialect):
22
+ if dialect.name == 'postgresql':
23
+ return value
24
+ if value is not None:
25
+ return value
26
+ return value
27
+
28
+ def process_result_value(self, value, dialect):
29
+ if dialect.name == 'postgresql':
30
+ return value
31
+ if value is not None:
32
+ return value
33
+ return value
34
+
35
+ Base = declarative_base()
36
+
37
+ class ThreadRecord(Base):
38
+ __tablename__ = 'threads'
39
+
40
+ id = Column(String, primary_key=True)
41
+ title = Column(String, nullable=True)
42
+ attributes = Column(JSONBCompat, nullable=False, default={})
43
+ platforms = Column(JSONBCompat, nullable=True)
44
+ created_at = Column(DateTime(timezone=True), default=lambda: datetime.now(UTC))
45
+ updated_at = Column(DateTime(timezone=True), default=lambda: datetime.now(UTC), onupdate=lambda: datetime.now(UTC))
46
+
47
+ messages = relationship("MessageRecord", back_populates="thread", cascade="all, delete-orphan")
48
+
49
+ class MessageRecord(Base):
50
+ __tablename__ = 'messages'
51
+
52
+ id = Column(String, primary_key=True)
53
+ thread_id = Column(String, ForeignKey('threads.id', ondelete='CASCADE'), nullable=False)
54
+ sequence = Column(Integer, nullable=False)
55
+ turn = Column(Integer, nullable=True)
56
+ role = Column(String, nullable=False)
57
+ content = Column(Text, nullable=True)
58
+ name = Column(String, nullable=True)
59
+ tool_call_id = Column(String, nullable=True)
60
+ tool_calls = Column(JSONBCompat, nullable=True)
61
+ attributes = Column(JSONBCompat, nullable=False, default={})
62
+ timestamp = Column(DateTime(timezone=True), default=lambda: datetime.now(UTC))
63
+ source = Column(JSONBCompat, nullable=True)
64
+ platforms = Column(JSONBCompat, nullable=True)
65
+ attachments = Column(JSONBCompat, nullable=True)
66
+ metrics = Column(JSONBCompat, nullable=False, default={})
67
+ reactions = Column(JSONBCompat, nullable=True)
68
+
69
+ thread = relationship("ThreadRecord", back_populates="messages")