repositories
loading repo index
repositories
loading repo index
repository
loading code, commits, and activity
public Clawd ADK gateway launch mirror
stars
latest
clone command
git clone gitlawb://did:key:z6Mkq5mY...iFZ5/my-project-publ...git clone gitlawb://did:key:z6Mkq5mY.../my-project-publ...2fa351d6docs: add automaton and perps launch sources16d ago| #1 | from typing import Optional |
| #2 | from uuid import UUID |
| #3 | |
| #4 | from app.database import get_db |
| #5 | from app.models import App, Memory, MemoryAccessLog, MemoryState |
| #6 | from fastapi import APIRouter, Depends, HTTPException, Query |
| #7 | from sqlalchemy import desc, func |
| #8 | from sqlalchemy.orm import Session, joinedload |
| #9 | |
| #10 | router = APIRouter(prefix="/api/v1/apps", tags=["apps"]) |
| #11 | |
| #12 | # Helper functions |
| #13 | def get_app_or_404(db: Session, app_id: UUID) -> App: |
| #14 | app = db.query(App).filter(App.id == app_id).first() |
| #15 | if not app: |
| #16 | raise HTTPException(status_code=404, detail="App not found") |
| #17 | return app |
| #18 | |
| #19 | # List all apps with filtering |
| #20 | @router.get("/") |
| #21 | async def list_apps( |
| #22 | name: Optional[str] = None, |
| #23 | is_active: Optional[bool] = None, |
| #24 | sort_by: str = 'name', |
| #25 | sort_direction: str = 'asc', |
| #26 | page: int = Query(1, ge=1), |
| #27 | page_size: int = Query(10, ge=1, le=100), |
| #28 | db: Session = Depends(get_db) |
| #29 | ): |
| #30 | # Create a subquery for memory counts |
| #31 | memory_counts = db.query( |
| #32 | Memory.app_id, |
| #33 | func.count(Memory.id).label('memory_count') |
| #34 | ).filter( |
| #35 | Memory.state.in_([MemoryState.active, MemoryState.paused, MemoryState.archived]) |
| #36 | ).group_by(Memory.app_id).subquery() |
| #37 | |
| #38 | # Create a subquery for access counts |
| #39 | access_counts = db.query( |
| #40 | MemoryAccessLog.app_id, |
| #41 | func.count(func.distinct(MemoryAccessLog.memory_id)).label('access_count') |
| #42 | ).group_by(MemoryAccessLog.app_id).subquery() |
| #43 | |
| #44 | # Base query |
| #45 | query = db.query( |
| #46 | App, |
| #47 | func.coalesce(memory_counts.c.memory_count, 0).label('total_memories_created'), |
| #48 | func.coalesce(access_counts.c.access_count, 0).label('total_memories_accessed') |
| #49 | ) |
| #50 | |
| #51 | # Join with subqueries |
| #52 | query = query.outerjoin( |
| #53 | memory_counts, |
| #54 | App.id == memory_counts.c.app_id |
| #55 | ).outerjoin( |
| #56 | access_counts, |
| #57 | App.id == access_counts.c.app_id |
| #58 | ) |
| #59 | |
| #60 | if name: |
| #61 | query = query.filter(App.name.ilike(f"%{name}%")) |
| #62 | |
| #63 | if is_active is not None: |
| #64 | query = query.filter(App.is_active == is_active) |
| #65 | |
| #66 | # Apply sorting |
| #67 | if sort_by == 'name': |
| #68 | sort_field = App.name |
| #69 | elif sort_by == 'memories': |
| #70 | sort_field = func.coalesce(memory_counts.c.memory_count, 0) |
| #71 | elif sort_by == 'memories_accessed': |
| #72 | sort_field = func.coalesce(access_counts.c.access_count, 0) |
| #73 | else: |
| #74 | sort_field = App.name # default sort |
| #75 | |
| #76 | if sort_direction == 'desc': |
| #77 | query = query.order_by(desc(sort_field)) |
| #78 | else: |
| #79 | query = query.order_by(sort_field) |
| #80 | |
| #81 | total = query.count() |
| #82 | apps = query.offset((page - 1) * page_size).limit(page_size).all() |
| #83 | |
| #84 | return { |
| #85 | "total": total, |
| #86 | "page": page, |
| #87 | "page_size": page_size, |
| #88 | "apps": [ |
| #89 | { |
| #90 | "id": app[0].id, |
| #91 | "name": app[0].name, |
| #92 | "is_active": app[0].is_active, |
| #93 | "total_memories_created": app[1], |
| #94 | "total_memories_accessed": app[2] |
| #95 | } |
| #96 | for app in apps |
| #97 | ] |
| #98 | } |
| #99 | |
| #100 | # Get app details |
| #101 | @router.get("/{app_id}") |
| #102 | async def get_app_details( |
| #103 | app_id: UUID, |
| #104 | db: Session = Depends(get_db) |
| #105 | ): |
| #106 | app = get_app_or_404(db, app_id) |
| #107 | |
| #108 | # Get memory access statistics |
| #109 | access_stats = db.query( |
| #110 | func.count(MemoryAccessLog.id).label("total_memories_accessed"), |
| #111 | func.min(MemoryAccessLog.accessed_at).label("first_accessed"), |
| #112 | func.max(MemoryAccessLog.accessed_at).label("last_accessed") |
| #113 | ).filter(MemoryAccessLog.app_id == app_id).first() |
| #114 | |
| #115 | return { |
| #116 | "is_active": app.is_active, |
| #117 | "total_memories_created": db.query(Memory) |
| #118 | .filter(Memory.app_id == app_id) |
| #119 | .count(), |
| #120 | "total_memories_accessed": access_stats.total_memories_accessed or 0, |
| #121 | "first_accessed": access_stats.first_accessed, |
| #122 | "last_accessed": access_stats.last_accessed |
| #123 | } |
| #124 | |
| #125 | # List memories created by app |
| #126 | @router.get("/{app_id}/memories") |
| #127 | async def list_app_memories( |
| #128 | app_id: UUID, |
| #129 | page: int = Query(1, ge=1), |
| #130 | page_size: int = Query(10, ge=1, le=100), |
| #131 | db: Session = Depends(get_db) |
| #132 | ): |
| #133 | get_app_or_404(db, app_id) |
| #134 | query = db.query(Memory).filter( |
| #135 | Memory.app_id == app_id, |
| #136 | Memory.state.in_([MemoryState.active, MemoryState.paused, MemoryState.archived]) |
| #137 | ) |
| #138 | # Add eager loading for categories |
| #139 | query = query.options(joinedload(Memory.categories)) |
| #140 | total = query.count() |
| #141 | memories = query.order_by(Memory.created_at.desc()).offset((page - 1) * page_size).limit(page_size).all() |
| #142 | |
| #143 | return { |
| #144 | "total": total, |
| #145 | "page": page, |
| #146 | "page_size": page_size, |
| #147 | "memories": [ |
| #148 | { |
| #149 | "id": memory.id, |
| #150 | "content": memory.content, |
| #151 | "created_at": memory.created_at, |
| #152 | "state": memory.state.value, |
| #153 | "app_id": memory.app_id, |
| #154 | "categories": [category.name for category in memory.categories], |
| #155 | "metadata_": memory.metadata_ |
| #156 | } |
| #157 | for memory in memories |
| #158 | ] |
| #159 | } |
| #160 | |
| #161 | # List memories accessed by app |
| #162 | @router.get("/{app_id}/accessed") |
| #163 | async def list_app_accessed_memories( |
| #164 | app_id: UUID, |
| #165 | page: int = Query(1, ge=1), |
| #166 | page_size: int = Query(10, ge=1, le=100), |
| #167 | db: Session = Depends(get_db) |
| #168 | ): |
| #169 | |
| #170 | # Get memories with access counts |
| #171 | query = db.query( |
| #172 | Memory, |
| #173 | func.count(MemoryAccessLog.id).label("access_count") |
| #174 | ).join( |
| #175 | MemoryAccessLog, |
| #176 | Memory.id == MemoryAccessLog.memory_id |
| #177 | ).filter( |
| #178 | MemoryAccessLog.app_id == app_id |
| #179 | ).group_by( |
| #180 | Memory.id |
| #181 | ).order_by( |
| #182 | desc("access_count") |
| #183 | ) |
| #184 | |
| #185 | # Add eager loading for categories |
| #186 | query = query.options(joinedload(Memory.categories)) |
| #187 | |
| #188 | total = query.count() |
| #189 | results = query.offset((page - 1) * page_size).limit(page_size).all() |
| #190 | |
| #191 | return { |
| #192 | "total": total, |
| #193 | "page": page, |
| #194 | "page_size": page_size, |
| #195 | "memories": [ |
| #196 | { |
| #197 | "memory": { |
| #198 | "id": memory.id, |
| #199 | "content": memory.content, |
| #200 | "created_at": memory.created_at, |
| #201 | "state": memory.state.value, |
| #202 | "app_id": memory.app_id, |
| #203 | "app_name": memory.app.name if memory.app else None, |
| #204 | "categories": [category.name for category in memory.categories], |
| #205 | "metadata_": memory.metadata_ |
| #206 | }, |
| #207 | "access_count": count |
| #208 | } |
| #209 | for memory, count in results |
| #210 | ] |
| #211 | } |
| #212 | |
| #213 | |
| #214 | @router.put("/{app_id}") |
| #215 | async def update_app_details( |
| #216 | app_id: UUID, |
| #217 | is_active: bool, |
| #218 | db: Session = Depends(get_db) |
| #219 | ): |
| #220 | app = get_app_or_404(db, app_id) |
| #221 | app.is_active = is_active |
| #222 | db.commit() |
| #223 | return {"status": "success", "message": "Updated app details successfully"} |
| #224 |