slothquery 1.0.0__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.
Binary file
app/dist/index.html ADDED
@@ -0,0 +1,14 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>SlothQuery</title>
8
+ <script type="module" crossorigin src="/assets/index-DKvMVJoY.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/assets/index-BDTPNUTQ.css">
10
+ </head>
11
+ <body>
12
+ <div id="root"></div>
13
+ </body>
14
+ </html>
app/main.py ADDED
@@ -0,0 +1,79 @@
1
+ from fastapi import FastAPI
2
+ from fastapi.middleware.cors import CORSMiddleware
3
+ from fastapi.staticfiles import StaticFiles
4
+ from fastapi.responses import FileResponse
5
+ import os
6
+ from .database import engine, Base
7
+ from . import models
8
+ from .routers import core
9
+
10
+ # Create tables if they don't exist
11
+ Base.metadata.create_all(bind=engine)
12
+
13
+ # Ensure vault_ids column exists in chats table
14
+ from sqlalchemy import text
15
+ with engine.connect() as conn:
16
+ try:
17
+ conn.execute(text("ALTER TABLE chats ADD COLUMN vault_ids JSON"))
18
+ conn.commit()
19
+ except Exception:
20
+ pass
21
+
22
+ try:
23
+ conn.execute(text("ALTER TABLE playbooks ADD COLUMN always_include BOOLEAN DEFAULT 0"))
24
+ conn.commit()
25
+ except Exception:
26
+ pass
27
+
28
+ app = FastAPI(title="SlothQuery API", description="Local-first organizational intelligence platform")
29
+
30
+ app.add_middleware(
31
+ CORSMiddleware,
32
+ allow_origins=["*"], # Allow all origins for local ease-of-use
33
+ allow_credentials=True,
34
+ allow_methods=["*"],
35
+ allow_headers=["*"],
36
+ )
37
+
38
+ app.include_router(core.router)
39
+
40
+ @app.get("/health")
41
+ def health_check():
42
+ return {"status": "healthy"}
43
+
44
+ # Mount frontend build static files if built
45
+ current_dir = os.path.dirname(os.path.abspath(__file__))
46
+ # 1. First check if dist is inside package directory (installed mode)
47
+ dist_path = os.path.join(current_dir, "dist")
48
+ if not os.path.exists(dist_path):
49
+ # 2. Fallback to development directory structure
50
+ root_dir = os.path.dirname(os.path.dirname(current_dir))
51
+ dist_path = os.path.join(root_dir, "frontend", "dist")
52
+
53
+ if os.path.exists(dist_path):
54
+ assets_path = os.path.join(dist_path, "assets")
55
+ if os.path.exists(assets_path):
56
+ app.mount("/assets", StaticFiles(directory=assets_path), name="assets")
57
+
58
+ @app.get("/")
59
+ def serve_index():
60
+ return FileResponse(os.path.join(dist_path, "index.html"))
61
+
62
+ @app.get("/{catchall:path}")
63
+ def serve_catchall(catchall: str):
64
+ # Avoid intercepting API routes or health check
65
+ if catchall.startswith("api") or catchall.startswith("health"):
66
+ return {"detail": "Not Found"}
67
+
68
+ # If it matches an actual file in dist (like logo.png or favicon.ico), serve it
69
+ local_file = os.path.join(dist_path, catchall)
70
+ if os.path.exists(local_file) and os.path.isfile(local_file):
71
+ return FileResponse(local_file)
72
+
73
+ # Fallback to index.html for React Router
74
+ return FileResponse(os.path.join(dist_path, "index.html"))
75
+ else:
76
+ @app.get("/")
77
+ def read_root():
78
+ return {"message": "Welcome to SlothQuery API (Frontend not built)"}
79
+
app/models.py ADDED
@@ -0,0 +1,90 @@
1
+ import uuid
2
+ from datetime import datetime
3
+ from sqlalchemy import Column, String, Text, DateTime, ForeignKey, Boolean, JSON
4
+ from sqlalchemy.orm import relationship
5
+ from .database import Base
6
+
7
+ def generate_uuid():
8
+ return str(uuid.uuid4())
9
+
10
+ class Vault(Base):
11
+ __tablename__ = "vaults"
12
+ id = Column(String, primary_key=True, default=generate_uuid)
13
+ name = Column(String, nullable=False)
14
+ description = Column(String, nullable=True)
15
+ created_at = Column(DateTime, default=datetime.utcnow)
16
+
17
+ queries = relationship("Query", back_populates="vault")
18
+ playbooks = relationship("Playbook", back_populates="vault")
19
+
20
+ class Query(Base):
21
+ __tablename__ = "queries"
22
+ id = Column(String, primary_key=True, default=generate_uuid)
23
+ vault_id = Column(String, ForeignKey("vaults.id"))
24
+ title = Column(String, nullable=False)
25
+ description = Column(String, nullable=True)
26
+ sql_query = Column(Text, nullable=False)
27
+ sql_comments = Column(Text, nullable=True)
28
+ tags = Column(String, nullable=True)
29
+ dialect = Column(String, nullable=False) # snowflake | bigquery | postgresql etc.
30
+ created_at = Column(DateTime, default=datetime.utcnow)
31
+ updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
32
+
33
+ vault = relationship("Vault", back_populates="queries")
34
+ context = relationship("QueryContext", back_populates="query", uselist=False)
35
+
36
+ class QueryContext(Base):
37
+ __tablename__ = "query_contexts"
38
+ id = Column(String, primary_key=True, default=generate_uuid)
39
+ query_id = Column(String, ForeignKey("queries.id"), unique=True)
40
+ context_json = Column(JSON, nullable=False)
41
+ approval_status = Column(String, default="draft") # draft | approved | archived
42
+ version_hash = Column(String, nullable=True)
43
+ created_at = Column(DateTime, default=datetime.utcnow)
44
+ updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
45
+
46
+ query = relationship("Query", back_populates="context")
47
+
48
+ class Playbook(Base):
49
+ __tablename__ = "playbooks"
50
+ id = Column(String, primary_key=True, default=generate_uuid)
51
+ vault_id = Column(String, ForeignKey("vaults.id"))
52
+ playbook_type = Column(String, nullable=False)
53
+ name = Column(String, nullable=False)
54
+ content = Column(Text, nullable=False)
55
+ always_include = Column(Boolean, default=False)
56
+ created_at = Column(DateTime, default=datetime.utcnow)
57
+ updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
58
+
59
+ vault = relationship("Vault", back_populates="playbooks")
60
+
61
+ class Chat(Base):
62
+ __tablename__ = "chats"
63
+ id = Column(String, primary_key=True, default=generate_uuid)
64
+ title = Column(String, nullable=False)
65
+ vault_ids = Column(JSON, nullable=True) # List of vault ID strings
66
+ created_at = Column(DateTime, default=datetime.utcnow)
67
+ last_interacted_at = Column(DateTime, default=datetime.utcnow)
68
+
69
+ messages = relationship("ChatMessage", back_populates="chat", order_by="ChatMessage.created_at")
70
+
71
+ class ChatMessage(Base):
72
+ __tablename__ = "chat_messages"
73
+ id = Column(String, primary_key=True, default=generate_uuid)
74
+ chat_id = Column(String, ForeignKey("chats.id"))
75
+ role = Column(String, nullable=False) # user | assistant
76
+ content = Column(Text, nullable=False)
77
+ metadata_json = Column(JSON, nullable=True) # avoiding metadata as name collision with Base.metadata
78
+ created_at = Column(DateTime, default=datetime.utcnow)
79
+
80
+ chat = relationship("Chat", back_populates="messages")
81
+
82
+ class Provider(Base):
83
+ __tablename__ = "providers"
84
+ id = Column(String, primary_key=True, default=generate_uuid)
85
+ provider_type = Column(String, nullable=False) # openai | anthropic | google | groq | openrouter | deepseek
86
+ profile_name = Column(String, nullable=False)
87
+ model_name = Column(String, nullable=False)
88
+ encrypted_api_key = Column(String, nullable=False)
89
+ is_active = Column(Boolean, default=False)
90
+ created_at = Column(DateTime, default=datetime.utcnow)
app/schemas.py ADDED
@@ -0,0 +1,119 @@
1
+ from pydantic import BaseModel, Field
2
+ from typing import Optional, List, Dict, Any
3
+ from datetime import datetime
4
+
5
+ class ProviderBase(BaseModel):
6
+ provider_type: str
7
+ profile_name: str
8
+ model_name: str
9
+
10
+ class ProviderCreate(ProviderBase):
11
+ api_key: str
12
+
13
+ class ProviderResponse(ProviderBase):
14
+ id: str
15
+ is_active: bool
16
+ created_at: datetime
17
+
18
+ class Config:
19
+ from_attributes = True
20
+
21
+ class VaultBase(BaseModel):
22
+ name: str
23
+ description: Optional[str] = None
24
+
25
+ class VaultCreate(VaultBase):
26
+ pass
27
+
28
+ class VaultResponse(VaultBase):
29
+ id: str
30
+ created_at: datetime
31
+
32
+ class Config:
33
+ from_attributes = True
34
+
35
+ class QueryBase(BaseModel):
36
+ title: str
37
+ description: Optional[str] = None
38
+ sql_query: str
39
+ sql_comments: Optional[str] = None
40
+ tags: Optional[str] = None
41
+ dialect: str
42
+
43
+ class QueryCreate(QueryBase):
44
+ vault_id: str
45
+
46
+ class QueryResponse(QueryBase):
47
+ id: str
48
+ vault_id: str
49
+ created_at: datetime
50
+ updated_at: datetime
51
+
52
+ class Config:
53
+ from_attributes = True
54
+
55
+ class ChatMessageBase(BaseModel):
56
+ role: str
57
+ content: str
58
+ metadata_json: Optional[Dict[str, Any]] = None
59
+
60
+ class ChatMessageCreate(ChatMessageBase):
61
+ chat_id: str
62
+
63
+ class ChatMessageResponse(ChatMessageBase):
64
+ id: str
65
+ chat_id: str
66
+ created_at: datetime
67
+
68
+ class Config:
69
+ from_attributes = True
70
+
71
+ class ChatBase(BaseModel):
72
+ title: str
73
+
74
+ class ChatCreate(ChatBase):
75
+ pass
76
+
77
+ class ChatResponse(ChatBase):
78
+ id: str
79
+ vault_ids: Optional[List[str]] = []
80
+ created_at: datetime
81
+ last_interacted_at: Optional[datetime] = None
82
+ messages: List[ChatMessageResponse] = []
83
+
84
+ class Config:
85
+ from_attributes = True
86
+
87
+ class PlaybookBase(BaseModel):
88
+ name: str
89
+ playbook_type: str
90
+ content: str
91
+ always_include: Optional[bool] = False
92
+
93
+ class PlaybookCreate(PlaybookBase):
94
+ vault_id: str
95
+
96
+ class PlaybookResponse(PlaybookBase):
97
+ id: str
98
+ vault_id: str
99
+ created_at: datetime
100
+ updated_at: datetime
101
+
102
+ class Config:
103
+ from_attributes = True
104
+
105
+ class DraftExtractionRequest(BaseModel):
106
+ vault_id: str
107
+ title: str
108
+ description: Optional[str] = None
109
+ sql_query: str
110
+ sql_comments: Optional[str] = None
111
+ tags: Optional[str] = None
112
+ dialect: str
113
+
114
+ class QueryCreateWithContext(QueryCreate):
115
+ context_json: Dict[str, Any]
116
+
117
+ class PlaybookPushPreviewRequest(BaseModel):
118
+ vault_id: str
119
+ context_json: Dict[str, Any]
@@ -0,0 +1,11 @@
1
+ Metadata-Version: 2.4
2
+ Name: slothquery
3
+ Version: 1.0.0
4
+ Summary: Local-first organizational intelligence platform
5
+ Author: Ayush Thakur
6
+ Author-email: ayush01thakur@gmail.com
7
+ Requires-Python: >=3.8
8
+ Dynamic: author
9
+ Dynamic: author-email
10
+ Dynamic: requires-python
11
+ Dynamic: summary
@@ -0,0 +1,15 @@
1
+ app/__init__.py,sha256=yh-SB_A42QQ4lYkFF4N3npKmcEHpG17QJc9wzRYthww,25
2
+ app/cli.py,sha256=MaWk7l-ZXNHgqdXeH0iSoazXE8zSo3lRoIqiUWK_T6A,860
3
+ app/database.py,sha256=ANYP1K76wd1dCluVkRMpk3Dj8tUCau5p97Im1_Xg0xc,687
4
+ app/main.py,sha256=TM6-faB4MCKrBOcEY0SwIQOJV5XlJF7tZDxlYcPhD3M,2726
5
+ app/models.py,sha256=xPVCQ5S0xQpHqySHNatQbCE_DxAgmi0nBx8KhDdcEbI,4118
6
+ app/schemas.py,sha256=4_KReSLloGu32Ga284ea4_s4BmNXLH9Kdj_tlpVOPNU,2600
7
+ app/dist/index.html,sha256=PXn452Bhf3jIdMEtEpYH0Gk3UkhkHOIfJI1MOoYGjWQ,457
8
+ app/dist/assets/index-BDTPNUTQ.css,sha256=0xj9MPToNENXCuWcSK15NWkE2leui6XD7zU4mVrYRNo,26628
9
+ app/dist/assets/index-DKvMVJoY.js,sha256=m9kYc_2ALBTYkrc_OZWBm8CiuYIlB5QTs0IfDzh-cZA,444634
10
+ app/dist/assets/logo-RBZv3XvP.png,sha256=HCQOHxDDiNmwsrvP_9Yg3myRRVLerobU7nh1WMhcthI,464247
11
+ slothquery-1.0.0.dist-info/METADATA,sha256=C6spHFLvi5ksTB4Bi4AjPSSaexpktOBb4mYwWT7QXx4,285
12
+ slothquery-1.0.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
13
+ slothquery-1.0.0.dist-info/entry_points.txt,sha256=AawlO-VZOgiZFjLyIXG8lZ4_eqCDqjBoNj9CvrsF_1w,44
14
+ slothquery-1.0.0.dist-info/top_level.txt,sha256=io9g7LCbfmTG1SFKgEOGXmCFB9uMP2H5lerm0HiHWQE,4
15
+ slothquery-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ slothquery = app.cli:main
@@ -0,0 +1 @@
1
+ app