Spaces:
Running
Running
Komalpreet Kaur commited on
Commit ·
bbc2fa9
0
Parent(s):
feat: Establish initial FastAPI project with core configuration, API endpoints, and a basic Langgraph orchestrator.
Browse files- .env.example +7 -0
- .gitignore +15 -0
- app/api/endpoints.py +22 -0
- app/core/config.py +36 -0
- app/main.py +30 -0
- app/services/orchestrator.py +30 -0
- requirements.txt +13 -0
- tests/test_phase1.py +18 -0
.env.example
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
OPENAI_API_KEY=your_openai_api_key_here
|
| 2 |
+
REDIS_HOST=localhost
|
| 3 |
+
REDIS_PORT=6379
|
| 4 |
+
CHROMA_DB_PATH=./chroma_db
|
| 5 |
+
NEO4J_URI=bolt://localhost:7687
|
| 6 |
+
NEO4J_USER=neo4j
|
| 7 |
+
NEO4J_PASSWORD=password
|
.gitignore
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
__pycache__/
|
| 2 |
+
*.py[cod]
|
| 3 |
+
*$py.class
|
| 4 |
+
.env
|
| 5 |
+
.venv
|
| 6 |
+
env/
|
| 7 |
+
venv/
|
| 8 |
+
ENV/
|
| 9 |
+
env.bak/
|
| 10 |
+
venv.bak/
|
| 11 |
+
.idea/
|
| 12 |
+
.vscode/
|
| 13 |
+
*.swp
|
| 14 |
+
*.swo
|
| 15 |
+
chroma_db/
|
app/api/endpoints.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastapi import APIRouter, HTTPException
|
| 2 |
+
from pydantic import BaseModel
|
| 3 |
+
from typing import List, Optional
|
| 4 |
+
|
| 5 |
+
router = APIRouter()
|
| 6 |
+
|
| 7 |
+
class QueryRequest(BaseModel):
|
| 8 |
+
text: str
|
| 9 |
+
user_id: str = "default_user"
|
| 10 |
+
|
| 11 |
+
class QueryResponse(BaseModel):
|
| 12 |
+
response: str
|
| 13 |
+
sources: List[str] = []
|
| 14 |
+
|
| 15 |
+
@router.post("/query", response_model=QueryResponse)
|
| 16 |
+
async def process_query(request: QueryRequest):
|
| 17 |
+
# This will eventually call the cognitive orchestrator
|
| 18 |
+
# For now, it's a placeholder for Phase 1 verification
|
| 19 |
+
return QueryResponse(
|
| 20 |
+
response=f"Brain received: {request.text}. Phase 1: Foundation is active.",
|
| 21 |
+
sources=["Phase 1: Foundation"]
|
| 22 |
+
)
|
app/core/config.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
| 2 |
+
from functools import lru_cache
|
| 3 |
+
import os
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
from dotenv import load_dotenv
|
| 6 |
+
|
| 7 |
+
# Load .env file if it exists
|
| 8 |
+
env_path = Path(__file__).parent.parent.parent / ".env"
|
| 9 |
+
load_dotenv(dotenv_path=env_path)
|
| 10 |
+
|
| 11 |
+
class Settings(BaseSettings):
|
| 12 |
+
PROJECT_NAME: str = "Soma"
|
| 13 |
+
VERSION: str = "0.1.0"
|
| 14 |
+
API_V1_STR: str = "/api/v1"
|
| 15 |
+
|
| 16 |
+
OPENAI_API_KEY: str = os.getenv("OPENAI_API_KEY", "")
|
| 17 |
+
|
| 18 |
+
# Working Memory (Redis)
|
| 19 |
+
REDIS_HOST: str = os.getenv("REDIS_HOST", "localhost")
|
| 20 |
+
REDIS_PORT: int = int(os.getenv("REDIS_PORT", 6379))
|
| 21 |
+
|
| 22 |
+
# Episodic Memory (ChromaDB)
|
| 23 |
+
CHROMA_DB_PATH: str = os.getenv("CHROMA_DB_PATH", "./chroma_db")
|
| 24 |
+
|
| 25 |
+
# Semantic Memory (Neo4j)
|
| 26 |
+
NEO4J_URI: str = os.getenv("NEO4J_URI", "bolt://localhost:7687")
|
| 27 |
+
NEO4J_USER: str = os.getenv("NEO4J_USER", "neo4j")
|
| 28 |
+
NEO4J_PASSWORD: str = os.getenv("NEO4J_PASSWORD", "password")
|
| 29 |
+
|
| 30 |
+
model_config = SettingsConfigDict(case_sensitive=True)
|
| 31 |
+
|
| 32 |
+
@lru_cache()
|
| 33 |
+
def get_settings():
|
| 34 |
+
return Settings()
|
| 35 |
+
|
| 36 |
+
settings = get_settings()
|
app/main.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastapi import FastAPI
|
| 2 |
+
from fastapi.middleware.cors import CORSMiddleware
|
| 3 |
+
from app.core.config import settings
|
| 4 |
+
from app.api.endpoints import router as api_router
|
| 5 |
+
|
| 6 |
+
app = FastAPI(
|
| 7 |
+
title=settings.PROJECT_NAME,
|
| 8 |
+
version=settings.VERSION,
|
| 9 |
+
openapi_url=f"{settings.API_V1_STR}/openapi.json"
|
| 10 |
+
)
|
| 11 |
+
|
| 12 |
+
# Set up CORS
|
| 13 |
+
app.add_middleware(
|
| 14 |
+
CORSMiddleware,
|
| 15 |
+
allow_origins=["*"],
|
| 16 |
+
allow_credentials=True,
|
| 17 |
+
allow_methods=["*"],
|
| 18 |
+
allow_headers=["*"],
|
| 19 |
+
)
|
| 20 |
+
|
| 21 |
+
# Include the API router
|
| 22 |
+
app.include_router(api_router, prefix=settings.API_V1_STR)
|
| 23 |
+
|
| 24 |
+
@app.get("/")
|
| 25 |
+
async def root():
|
| 26 |
+
return {"message": f"Welcome to {settings.PROJECT_NAME} API"}
|
| 27 |
+
|
| 28 |
+
if __name__ == "__main__":
|
| 29 |
+
import uvicorn
|
| 30 |
+
uvicorn.run("app.main:app", host="0.0.0.0", port=8000, reload=True)
|
app/services/orchestrator.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from langgraph.graph import StateGraph, END
|
| 2 |
+
from typing import TypedDict, Annotated, List
|
| 3 |
+
import operator
|
| 4 |
+
|
| 5 |
+
class AgentState(TypedDict):
|
| 6 |
+
input: str
|
| 7 |
+
chat_history: List[dict]
|
| 8 |
+
context: List[str]
|
| 9 |
+
response: str
|
| 10 |
+
|
| 11 |
+
def call_model(state: AgentState):
|
| 12 |
+
# Simplified logic for Phase 1
|
| 13 |
+
# Will be expanded with memory layers in later phases
|
| 14 |
+
return {"response": f"Orchestrator processed: {state['input']}"}
|
| 15 |
+
|
| 16 |
+
def create_graph():
|
| 17 |
+
workflow = StateGraph(AgentState)
|
| 18 |
+
|
| 19 |
+
# Add nodes
|
| 20 |
+
workflow.add_node("call_model", call_model)
|
| 21 |
+
|
| 22 |
+
# Set entry point
|
| 23 |
+
workflow.set_entry_point("call_model")
|
| 24 |
+
|
| 25 |
+
# Add edges
|
| 26 |
+
workflow.add_edge("call_model", END)
|
| 27 |
+
|
| 28 |
+
return workflow.compile()
|
| 29 |
+
|
| 30 |
+
orchestrator = create_graph()
|
requirements.txt
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
fastapi
|
| 2 |
+
uvicorn
|
| 3 |
+
langgraph
|
| 4 |
+
langchain
|
| 5 |
+
langchain-openai
|
| 6 |
+
python-dotenv
|
| 7 |
+
pydantic
|
| 8 |
+
redis
|
| 9 |
+
chromadb
|
| 10 |
+
neo4j
|
| 11 |
+
python-multipart
|
| 12 |
+
aiosqlite
|
| 13 |
+
pydantic-settings
|
tests/test_phase1.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import requests
|
| 2 |
+
import json
|
| 3 |
+
|
| 4 |
+
url = "http://localhost:8000/api/v1/query"
|
| 5 |
+
payload = {
|
| 6 |
+
"text": "Hello Soma!",
|
| 7 |
+
"user_id": "test_user"
|
| 8 |
+
}
|
| 9 |
+
headers = {
|
| 10 |
+
"Content-Type": "application/json"
|
| 11 |
+
}
|
| 12 |
+
|
| 13 |
+
try:
|
| 14 |
+
response = requests.post(url, data=json.dumps(payload), headers=headers)
|
| 15 |
+
print(f"Status Code: {response.status_code}")
|
| 16 |
+
print(f"Response Body: {response.json()}")
|
| 17 |
+
except Exception as e:
|
| 18 |
+
print(f"Error: {e}")
|