migrated all pawprint work

This commit is contained in:
buenosairesam
2025-12-31 08:34:18 -03:00
parent fc63e9010c
commit 680969ca42
63 changed files with 4687 additions and 5 deletions

View File

@@ -0,0 +1 @@
# Slack models

View File

@@ -0,0 +1,70 @@
"""
Text formatters for Slack data (LLM-friendly output).
"""
from .message import MessageList, ChannelList, UserList, Message, Channel
def format_message(msg: Message, users: dict[str, str] | None = None) -> str:
"""Format a single message."""
user_display = msg.user
if users and msg.user and msg.user in users:
user_display = users[msg.user]
time_str = msg.timestamp.strftime("%Y-%m-%d %H:%M") if msg.timestamp else msg.ts
thread_info = f" [thread: {msg.reply_count} replies]" if msg.reply_count > 0 else ""
return f"[{time_str}] {user_display}: {msg.text}{thread_info}"
def format_message_list(data: MessageList, users: dict[str, str] | None = None) -> str:
"""Format message list for text output."""
lines = [f"Channel: {data.channel_id}", f"Messages: {len(data.messages)}", ""]
for msg in data.messages:
lines.append(format_message(msg, users))
if data.has_more:
lines.append("\n[More messages available...]")
return "\n".join(lines)
def format_channel(ch: Channel) -> str:
"""Format a single channel."""
flags = []
if ch.is_private:
flags.append("private")
if ch.is_archived:
flags.append("archived")
if ch.is_member:
flags.append("member")
flag_str = f" ({', '.join(flags)})" if flags else ""
members_str = f" [{ch.num_members} members]" if ch.num_members else ""
return f"#{ch.name} ({ch.id}){flag_str}{members_str}"
def format_channel_list(data: ChannelList) -> str:
"""Format channel list for text output."""
lines = [f"Channels: {data.total}", ""]
for ch in data.channels:
lines.append(format_channel(ch))
if ch.purpose:
lines.append(f" Purpose: {ch.purpose}")
return "\n".join(lines)
def format_user_list(data: UserList) -> str:
"""Format user list for text output."""
lines = [f"Users: {data.total}", ""]
for u in data.users:
bot_flag = " [bot]" if u.is_bot else ""
display = u.display_name or u.real_name or u.name
lines.append(f"@{u.name} ({u.id}) - {display}{bot_flag}")
return "\n".join(lines)

View File

@@ -0,0 +1,98 @@
"""
Slack models with self-parsing from Slack API responses.
"""
from pydantic import BaseModel
from typing import Optional, List
from datetime import datetime
class User(BaseModel):
id: str
name: str
real_name: Optional[str] = None
display_name: Optional[str] = None
is_bot: bool = False
@classmethod
def from_slack(cls, user: dict) -> "User":
profile = user.get("profile", {})
return cls(
id=user["id"],
name=user.get("name", ""),
real_name=profile.get("real_name") or user.get("real_name"),
display_name=profile.get("display_name"),
is_bot=user.get("is_bot", False),
)
class Channel(BaseModel):
id: str
name: str
is_private: bool = False
is_archived: bool = False
is_member: bool = False
topic: Optional[str] = None
purpose: Optional[str] = None
num_members: Optional[int] = None
@classmethod
def from_slack(cls, channel: dict) -> "Channel":
return cls(
id=channel["id"],
name=channel.get("name", ""),
is_private=channel.get("is_private", False),
is_archived=channel.get("is_archived", False),
is_member=channel.get("is_member", False),
topic=channel.get("topic", {}).get("value"),
purpose=channel.get("purpose", {}).get("value"),
num_members=channel.get("num_members"),
)
class Message(BaseModel):
ts: str # Slack timestamp (unique message ID)
user: Optional[str] = None
text: str
thread_ts: Optional[str] = None
reply_count: int = 0
reactions: List[dict] = []
timestamp: Optional[datetime] = None
@classmethod
def from_slack(cls, msg: dict) -> "Message":
ts = msg.get("ts", "")
return cls(
ts=ts,
user=msg.get("user"),
text=msg.get("text", ""),
thread_ts=msg.get("thread_ts"),
reply_count=msg.get("reply_count", 0),
reactions=msg.get("reactions", []),
timestamp=cls._ts_to_datetime(ts),
)
@staticmethod
def _ts_to_datetime(ts: str) -> Optional[datetime]:
if not ts:
return None
try:
return datetime.fromtimestamp(float(ts))
except (ValueError, TypeError):
return None
class MessageList(BaseModel):
messages: List[Message]
channel_id: str
has_more: bool = False
class ChannelList(BaseModel):
channels: List[Channel]
total: int
class UserList(BaseModel):
users: List[User]
total: int