Files
grimlock/backend/main.py
JA af57352d2a FINAL: WebSocket + DMs + Files - Backend Complete!
WebSocket Real-Time:
- Socket.IO server integrated
- Real-time message delivery
- User online/offline status
- Typing indicators
- Channel room management
- Auto-join on channel access

Direct Messages:
- 1-on-1 chat API
- DM history and conversations
- @grimlock in DMs (AI responds)
- Read receipts
- Unread count tracking
- WebSocket notifications

File Management:
- Upload files to channels
- Download with streaming
- File metadata tracking
- File listing by channel
- Delete with permissions

Integration:
- Messages broadcast via WebSocket
- DM notifications via WebSocket
- All APIs updated for real-time

BACKEND IS FEATURE COMPLETE!
- Auth 
- Channels 
- Messages 
- DMs 
- Files 
- WebSocket 
- @grimlock AI 

Ready for frontend development in next session!
2026-02-12 22:11:55 +00:00

133 lines
3.9 KiB
Python

"""
Grimlock - AI-Native Company Operating System
Main FastAPI Application
"""
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from contextlib import asynccontextmanager
import logging
from dotenv import load_dotenv
import os
import socketio
from api.chat import router as chat_router
from api.auth import router as auth_router
from api.channels import router as channels_router
from api.messages import router as messages_router
from api.direct_messages import router as dm_router
from api.files import router as files_router
from core.context_manager import ContextManager
from core.ai_client import AIClient
from core.database import engine
from core.models import Base
from core.websocket import sio, broadcast_new_message
# Load environment variables
load_dotenv()
# Configure logging
logging.basicConfig(
level=os.getenv("LOG_LEVEL", "INFO"),
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
# Global state
context_manager = None
ai_client = None
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Startup and shutdown events"""
global context_manager, ai_client
logger.info("Starting Grimlock backend...")
# Create database tables
Base.metadata.create_all(bind=engine)
logger.info("Database tables created/verified")
# Initialize context manager
context_path = os.getenv("CONTEXT_PATH", "./context")
context_manager = ContextManager(context_path)
context_manager.load_all_context()
logger.info(f"Loaded context from {context_path}")
# Initialize AI client
api_key = os.getenv("ANTHROPIC_API_KEY")
if not api_key:
logger.error("ANTHROPIC_API_KEY not set!")
raise ValueError("ANTHROPIC_API_KEY environment variable is required")
ai_client = AIClient(api_key=api_key)
logger.info("AI client initialized")
logger.info("WebSocket server ready")
yield
# Cleanup
logger.info("Shutting down Grimlock backend...")
# Create FastAPI app
app = FastAPI(
title="Grimlock",
description="AI-Native Company Operating System",
version="0.3.0",
lifespan=lifespan
)
# Mount Socket.IO
socket_app = socketio.ASGIApp(sio, app)
# CORS middleware
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # Configure appropriately for production
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Include routers
app.include_router(auth_router, prefix="/api/auth", tags=["auth"])
app.include_router(channels_router, prefix="/api/channels", tags=["channels"])
app.include_router(messages_router, prefix="/api/channels", tags=["messages"])
app.include_router(dm_router, prefix="/api/dms", tags=["direct-messages"])
app.include_router(files_router, prefix="/api/files", tags=["files"])
app.include_router(chat_router, prefix="/api/chat", tags=["chat"])
@app.get("/")
async def root():
"""Health check endpoint"""
return {
"status": "online",
"service": "Grimlock",
"version": "0.3.0",
"features": ["auth", "channels", "messages", "dms", "files", "websocket", "ai"]
}
@app.get("/api/health")
async def health():
"""Detailed health check"""
return {
"status": "healthy",
"context_loaded": context_manager is not None and context_manager.is_loaded(),
"ai_client_ready": ai_client is not None,
"database": "connected",
"websocket": "ready"
}
def get_context_manager() -> ContextManager:
"""Dependency to get context manager"""
if context_manager is None:
raise HTTPException(status_code=500, detail="Context manager not initialized")
return context_manager
def get_ai_client() -> AIClient:
"""Dependency to get AI client"""
if ai_client is None:
raise HTTPException(status_code=500, detail="AI client not initialized")
return ai_client