172 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			172 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| """
 | |
| HCFS API Server - FastAPI-based REST API for context operations.
 | |
| """
 | |
| 
 | |
| from typing import List, Optional
 | |
| from datetime import datetime
 | |
| from pydantic import BaseModel
 | |
| 
 | |
| from fastapi import FastAPI, HTTPException, Depends
 | |
| from fastapi.responses import JSONResponse
 | |
| 
 | |
| from ..core.context_db import ContextDatabase, Context
 | |
| from ..core.embeddings import EmbeddingManager
 | |
| 
 | |
| 
 | |
| # Pydantic models
 | |
| class ContextCreateRequest(BaseModel):
 | |
|     path: str
 | |
|     content: str
 | |
|     summary: Optional[str] = None
 | |
|     author: Optional[str] = None
 | |
| 
 | |
| 
 | |
| class ContextResponse(BaseModel):
 | |
|     id: int
 | |
|     path: str
 | |
|     content: str
 | |
|     summary: Optional[str]
 | |
|     author: Optional[str]
 | |
|     created_at: datetime
 | |
|     updated_at: datetime
 | |
|     version: int
 | |
| 
 | |
| 
 | |
| class SearchRequest(BaseModel):
 | |
|     query: str
 | |
|     path_prefix: Optional[str] = None
 | |
|     top_k: int = 5
 | |
|     search_type: str = "hybrid"  # "semantic", "hybrid"
 | |
| 
 | |
| 
 | |
| class SearchResult(BaseModel):
 | |
|     context: ContextResponse
 | |
|     score: float
 | |
| 
 | |
| 
 | |
| class ContextAPI:
 | |
|     """HCFS REST API server."""
 | |
|     
 | |
|     def __init__(self, context_db: ContextDatabase, embedding_manager: EmbeddingManager):
 | |
|         self.context_db = context_db
 | |
|         self.embedding_manager = embedding_manager
 | |
|         self.app = FastAPI(
 | |
|             title="HCFS Context API",
 | |
|             description="Context-Aware Hierarchical Context File System API",
 | |
|             version="0.1.0"
 | |
|         )
 | |
|         self._setup_routes()
 | |
|     
 | |
|     def _setup_routes(self):
 | |
|         """Setup API routes."""
 | |
|         
 | |
|         @self.app.get("/health")
 | |
|         async def health_check():
 | |
|             """Health check endpoint."""
 | |
|             return {"status": "healthy", "service": "hcfs-api"}
 | |
|         
 | |
|         @self.app.post("/context", response_model=ContextResponse)
 | |
|         async def create_context(request: ContextCreateRequest):
 | |
|             """Create a new context."""
 | |
|             context = Context(
 | |
|                 id=None,
 | |
|                 path=request.path,
 | |
|                 content=request.content,
 | |
|                 summary=request.summary,
 | |
|                 author=request.author
 | |
|             )
 | |
|             
 | |
|             # Store with embedding
 | |
|             context_id = self.embedding_manager.store_context_with_embedding(context)
 | |
|             
 | |
|             # Retrieve the stored context
 | |
|             stored_contexts = self.context_db.list_contexts_at_path(request.path)
 | |
|             stored_context = next((c for c in stored_contexts if c.id == context_id), None)
 | |
|             
 | |
|             if not stored_context:
 | |
|                 raise HTTPException(status_code=500, detail="Failed to store context")
 | |
|             
 | |
|             return ContextResponse(**stored_context.__dict__)
 | |
|         
 | |
|         @self.app.get("/context/{path:path}", response_model=List[ContextResponse])
 | |
|         async def get_context(path: str, depth: int = 1):
 | |
|             """Get contexts for a path with optional parent inheritance."""
 | |
|             contexts = self.context_db.get_context_by_path(f"/{path}", depth=depth)
 | |
|             return [ContextResponse(**ctx.__dict__) for ctx in contexts]
 | |
|         
 | |
|         @self.app.get("/context", response_model=List[ContextResponse])
 | |
|         async def list_contexts(path: str):
 | |
|             """List all contexts at a specific path."""
 | |
|             contexts = self.context_db.list_contexts_at_path(path)
 | |
|             return [ContextResponse(**ctx.__dict__) for ctx in contexts]
 | |
|         
 | |
|         @self.app.put("/context/{context_id}")
 | |
|         async def update_context(context_id: int, content: str, summary: Optional[str] = None):
 | |
|             """Update an existing context."""
 | |
|             success = self.context_db.update_context(context_id, content, summary)
 | |
|             if not success:
 | |
|                 raise HTTPException(status_code=404, detail="Context not found")
 | |
|             
 | |
|             # Update embedding
 | |
|             contexts = self.context_db.list_contexts_at_path("")  # Get updated context
 | |
|             updated_context = next((c for c in contexts if c.id == context_id), None)
 | |
|             if updated_context:
 | |
|                 embedding = self.embedding_manager.generate_embedding(updated_context.content)
 | |
|                 self.embedding_manager._store_embedding(context_id, embedding)
 | |
|             
 | |
|             return {"message": "Context updated successfully"}
 | |
|         
 | |
|         @self.app.delete("/context/{context_id}")
 | |
|         async def delete_context(context_id: int):
 | |
|             """Delete a context."""
 | |
|             success = self.context_db.delete_context(context_id)
 | |
|             if not success:
 | |
|                 raise HTTPException(status_code=404, detail="Context not found")
 | |
|             return {"message": "Context deleted successfully"}
 | |
|         
 | |
|         @self.app.post("/search", response_model=List[SearchResult])
 | |
|         async def search_contexts(request: SearchRequest):
 | |
|             """Search contexts using semantic or hybrid search."""
 | |
|             if request.search_type == "semantic":
 | |
|                 results = self.embedding_manager.semantic_search(
 | |
|                     request.query, 
 | |
|                     request.path_prefix, 
 | |
|                     request.top_k
 | |
|                 )
 | |
|             elif request.search_type == "hybrid":
 | |
|                 results = self.embedding_manager.hybrid_search(
 | |
|                     request.query, 
 | |
|                     request.path_prefix, 
 | |
|                     request.top_k
 | |
|                 )
 | |
|             else:
 | |
|                 raise HTTPException(status_code=400, detail="Invalid search_type")
 | |
|             
 | |
|             return [
 | |
|                 SearchResult(
 | |
|                     context=ContextResponse(**ctx.__dict__),
 | |
|                     score=score
 | |
|                 )
 | |
|                 for ctx, score in results
 | |
|             ]
 | |
|         
 | |
|         @self.app.get("/similar/{context_id}", response_model=List[SearchResult])
 | |
|         async def get_similar_contexts(context_id: int, top_k: int = 5):
 | |
|             """Find contexts similar to a given context."""
 | |
|             results = self.embedding_manager.get_similar_contexts(context_id, top_k)
 | |
|             
 | |
|             return [
 | |
|                 SearchResult(
 | |
|                     context=ContextResponse(**ctx.__dict__),
 | |
|                     score=score
 | |
|                 )
 | |
|                 for ctx, score in results
 | |
|             ]
 | |
| 
 | |
| 
 | |
| def create_app(db_path: str = "hcfs_context.db") -> FastAPI:
 | |
|     """Create FastAPI application with HCFS components."""
 | |
|     context_db = ContextDatabase(db_path)
 | |
|     embedding_manager = EmbeddingManager(context_db)
 | |
|     api = ContextAPI(context_db, embedding_manager)
 | |
|     return api.app | 
