Spaces:
Running
Running
GitHub Actions commited on
Commit ·
a066e5a
1
Parent(s): edbfac1
Deploy from GitHub Actions (2026-03-12 11:50 UTC)
Browse files- .gitignore +1 -0
- app/main.py +5 -1
- app/models/database.py +8 -0
- app/models/smart_models.py +17 -0
- app/routers/knowledge_base.py +75 -0
- app/schemas/knowledge_base.py +19 -0
.gitignore
CHANGED
|
@@ -200,6 +200,7 @@ PROJECT.md
|
|
| 200 |
# Everything inside `archive` except `daily_log.md`
|
| 201 |
archive/*
|
| 202 |
!archive/daily_log.md
|
|
|
|
| 203 |
|
| 204 |
# Microservice credentials (sensitive)
|
| 205 |
services/credentials/*.json
|
|
|
|
| 200 |
# Everything inside `archive` except `daily_log.md`
|
| 201 |
archive/*
|
| 202 |
!archive/daily_log.md
|
| 203 |
+
!archive/development_notes/
|
| 204 |
|
| 205 |
# Microservice credentials (sensitive)
|
| 206 |
services/credentials/*.json
|
app/main.py
CHANGED
|
@@ -17,6 +17,7 @@ from app.models.conversation_manager import ConversationManager
|
|
| 17 |
from app.models.database import init_database, get_database, User, Conversation, Message
|
| 18 |
from app.models.smart_models import UserPreference, UserInsight, ConversationTopic
|
| 19 |
from app.data.training_data import TRAINING_DATA
|
|
|
|
| 20 |
|
| 21 |
# Load configuration (this sets up logging automatically)
|
| 22 |
config = get_config()
|
|
@@ -54,6 +55,7 @@ async def lifespan(fastapi_app: FastAPI): # pylint: disable=unused-argument
|
|
| 54 |
|
| 55 |
|
| 56 |
app = FastAPI(title=config.api.title, debug=config.api.debug, lifespan=lifespan)
|
|
|
|
| 57 |
|
| 58 |
# Enable CORS
|
| 59 |
app.add_middleware(
|
|
@@ -247,4 +249,6 @@ async def get_user_stats(session_id: str):
|
|
| 247 |
# Must be mounted LAST so API routes above take precedence
|
| 248 |
_frontend_dir = Path(__file__).parent.parent / "frontend"
|
| 249 |
if _frontend_dir.exists():
|
| 250 |
-
app.mount(
|
|
|
|
|
|
|
|
|
| 17 |
from app.models.database import init_database, get_database, User, Conversation, Message
|
| 18 |
from app.models.smart_models import UserPreference, UserInsight, ConversationTopic
|
| 19 |
from app.data.training_data import TRAINING_DATA
|
| 20 |
+
from app.routers import knowledge_base
|
| 21 |
|
| 22 |
# Load configuration (this sets up logging automatically)
|
| 23 |
config = get_config()
|
|
|
|
| 55 |
|
| 56 |
|
| 57 |
app = FastAPI(title=config.api.title, debug=config.api.debug, lifespan=lifespan)
|
| 58 |
+
app.include_router(knowledge_base.router)
|
| 59 |
|
| 60 |
# Enable CORS
|
| 61 |
app.add_middleware(
|
|
|
|
| 249 |
# Must be mounted LAST so API routes above take precedence
|
| 250 |
_frontend_dir = Path(__file__).parent.parent / "frontend"
|
| 251 |
if _frontend_dir.exists():
|
| 252 |
+
app.mount(
|
| 253 |
+
"/", StaticFiles(directory=str(_frontend_dir), html=True), name="frontend"
|
| 254 |
+
)
|
app/models/database.py
CHANGED
|
@@ -185,3 +185,11 @@ def get_database() -> DatabaseManager:
|
|
| 185 |
def init_database():
|
| 186 |
"""Initialize the global database manager instance and create tables"""
|
| 187 |
return db_manager.init_database()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 185 |
def init_database():
|
| 186 |
"""Initialize the global database manager instance and create tables"""
|
| 187 |
return db_manager.init_database()
|
| 188 |
+
|
| 189 |
+
|
| 190 |
+
def get_db():
|
| 191 |
+
db = get_database().get_session()
|
| 192 |
+
try:
|
| 193 |
+
yield db
|
| 194 |
+
finally:
|
| 195 |
+
db.close()
|
app/models/smart_models.py
CHANGED
|
@@ -107,3 +107,20 @@ class UserInsight(Base):
|
|
| 107 |
|
| 108 |
def __repr__(self):
|
| 109 |
return f"<UserInsight(id={self.id} user_id={self.user_id}, {self.insight_key}={self.insight_value})>"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 107 |
|
| 108 |
def __repr__(self):
|
| 109 |
return f"<UserInsight(id={self.id} user_id={self.user_id}, {self.insight_key}={self.insight_value})>"
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
class KnowledgeBase(Base):
|
| 113 |
+
__tablename__ = "knowledge_base"
|
| 114 |
+
|
| 115 |
+
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
| 116 |
+
created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc))
|
| 117 |
+
updated_at = Column(
|
| 118 |
+
DateTime,
|
| 119 |
+
default=lambda: datetime.now(timezone.utc),
|
| 120 |
+
onupdate=lambda: datetime.now(timezone.utc),
|
| 121 |
+
)
|
| 122 |
+
tenant_id = Column(UUID(as_uuid=True), nullable=False)
|
| 123 |
+
entry = Column(Text, nullable=False)
|
| 124 |
+
|
| 125 |
+
def __repr__(self):
|
| 126 |
+
return f"<KnowledgeBase(id={self.id} tenant_id={self.tenant_id})>"
|
app/routers/knowledge_base.py
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import uuid
|
| 2 |
+
|
| 3 |
+
from fastapi import APIRouter, Depends, HTTPException
|
| 4 |
+
from sqlalchemy import select
|
| 5 |
+
from sqlalchemy.orm import Session
|
| 6 |
+
|
| 7 |
+
from app.models.smart_models import KnowledgeBase
|
| 8 |
+
from app.schemas.knowledge_base import KBEntryCreate, KBEntryResponse, KBEntryUpdate
|
| 9 |
+
from app.models.database import get_db
|
| 10 |
+
|
| 11 |
+
router = APIRouter()
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
@router.post("/kb/entries", status_code=201, response_model=KBEntryResponse)
|
| 15 |
+
def create_entry(
|
| 16 |
+
entry: KBEntryCreate, db: Session = Depends(get_db)
|
| 17 |
+
) -> KBEntryResponse:
|
| 18 |
+
|
| 19 |
+
knowledge_base = KnowledgeBase()
|
| 20 |
+
knowledge_base.tenant_id = uuid.uuid4()
|
| 21 |
+
knowledge_base.entry = entry.entry
|
| 22 |
+
db.add(knowledge_base)
|
| 23 |
+
db.commit()
|
| 24 |
+
db.refresh(knowledge_base)
|
| 25 |
+
|
| 26 |
+
return knowledge_base
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
@router.get("/kb/entries/{entry_id}", status_code=200, response_model=KBEntryResponse)
|
| 30 |
+
def read_entry(entry_id: uuid.UUID, db: Session = Depends(get_db)) -> KBEntryResponse:
|
| 31 |
+
|
| 32 |
+
kb = db.get(KnowledgeBase, entry_id)
|
| 33 |
+
|
| 34 |
+
if kb is None:
|
| 35 |
+
raise HTTPException(status_code=404, detail="Entry not found")
|
| 36 |
+
|
| 37 |
+
return kb
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
@router.get("/kb/entries", status_code=200, response_model=list[KBEntryResponse])
|
| 41 |
+
def read_entries(db: Session = Depends(get_db)) -> list[KBEntryResponse]:
|
| 42 |
+
|
| 43 |
+
kb_entries = db.scalars(select(KnowledgeBase)).all()
|
| 44 |
+
|
| 45 |
+
return kb_entries
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
@router.put("/kb/entries/{entry_id}", status_code=200, response_model=KBEntryResponse)
|
| 49 |
+
def update_entry(
|
| 50 |
+
entry_id: uuid.UUID, entry: KBEntryUpdate, db: Session = Depends(get_db)
|
| 51 |
+
) -> KBEntryResponse:
|
| 52 |
+
|
| 53 |
+
kb = db.get(KnowledgeBase, entry_id)
|
| 54 |
+
|
| 55 |
+
if kb is None:
|
| 56 |
+
raise HTTPException(status_code=404, detail="Entry not found")
|
| 57 |
+
kb.entry = entry.entry
|
| 58 |
+
db.commit()
|
| 59 |
+
db.refresh(kb)
|
| 60 |
+
|
| 61 |
+
return kb
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
@router.delete("/kb/entries/{entry_id}", status_code=204)
|
| 65 |
+
def delete_entry(entry_id: uuid.UUID, db: Session = Depends(get_db)) -> None:
|
| 66 |
+
|
| 67 |
+
kb = db.get(KnowledgeBase, entry_id)
|
| 68 |
+
|
| 69 |
+
if kb is None:
|
| 70 |
+
raise HTTPException(status_code=404, detail="Entry not found")
|
| 71 |
+
|
| 72 |
+
db.delete(kb)
|
| 73 |
+
db.commit()
|
| 74 |
+
|
| 75 |
+
return
|
app/schemas/knowledge_base.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from datetime import datetime
|
| 2 |
+
import uuid
|
| 3 |
+
from pydantic import BaseModel
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
class KBEntryCreate(BaseModel):
|
| 7 |
+
entry: str
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
class KBEntryResponse(BaseModel):
|
| 11 |
+
id: uuid.UUID
|
| 12 |
+
created_at: datetime
|
| 13 |
+
updated_at: datetime
|
| 14 |
+
tenant_id: uuid.UUID
|
| 15 |
+
entry: str
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
class KBEntryUpdate(BaseModel):
|
| 19 |
+
entry: str
|