""" DAARION Memory Service - Integration API Endpoints """ from fastapi import APIRouter, HTTPException from pydantic import BaseModel from typing import Optional, List import logging from .integrations import obsidian_integrator, gdrive_integrator logger = logging.getLogger(__name__) router = APIRouter(prefix="/integrations", tags=["integrations"]) class SetVaultRequest(BaseModel): vault_path: str class SyncRequest(BaseModel): output_dir: Optional[str] = "/tmp/daarion_sync" include_attachments: Optional[bool] = False folder_filter: Optional[List[str]] = None tag_filter: Optional[List[str]] = None class GDriveSyncRequest(BaseModel): output_dir: Optional[str] = "/tmp/daarion_sync" folder_ids: Optional[List[str]] = None file_extensions: Optional[List[str]] = None @router.get("/status") async def get_integrations_status(): """Get status of all integrations""" obsidian_status = obsidian_integrator.get_status() gdrive_status = gdrive_integrator.get_status() return { "obsidian": obsidian_status, "google_drive": gdrive_status } # ===================== # OBSIDIAN ENDPOINTS # ===================== @router.post("/obsidian/set-vault") async def set_obsidian_vault(request: SetVaultRequest): """Set Obsidian vault path""" success = obsidian_integrator.set_vault_path(request.vault_path) if not success: raise HTTPException(status_code=400, detail="Invalid vault path") return {"status": "ok", "vault_path": request.vault_path} @router.post("/obsidian/scan") async def scan_obsidian_vault(): """Scan Obsidian vault for notes""" if not obsidian_integrator.vault_path: raise HTTPException(status_code=400, detail="Vault path not set") stats = obsidian_integrator.scan_vault() return { "status": "ok", "stats": stats } @router.get("/obsidian/search") async def search_obsidian_notes(query: str, limit: int = 10): """Search Obsidian notes""" if not obsidian_integrator.notes_cache: raise HTTPException(status_code=400, detail="Vault not scanned") results = obsidian_integrator.search_notes(query, limit=limit) return { "query": query, "results": [ { "title": r["title"], "path": r["path"], "tags": r["tags"], "match_score": r.get("match_score", 0), "preview": r["content"][:200] + "..." if len(r["content"]) > 200 else r["content"] } for r in results ] } @router.post("/obsidian/sync") async def sync_obsidian_vault(request: SyncRequest): """Sync Obsidian vault to DAARION""" if not obsidian_integrator.vault_path: raise HTTPException(status_code=400, detail="Vault path not set") if not obsidian_integrator.notes_cache: obsidian_integrator.scan_vault() from pathlib import Path output_path = Path(request.output_dir) output_path.mkdir(parents=True, exist_ok=True) stats = obsidian_integrator.sync_to_daarion( output_path, include_attachments=request.include_attachments, folder_filter=request.folder_filter, tag_filter=request.tag_filter ) return { "status": "ok", "stats": stats } @router.get("/obsidian/tags") async def get_obsidian_tags(): """Get all tags from Obsidian vault""" if not obsidian_integrator.tags_index: raise HTTPException(status_code=400, detail="Vault not scanned") return { "tags": [ {"name": tag, "count": len(notes)} for tag, notes in sorted( obsidian_integrator.tags_index.items(), key=lambda x: len(x[1]), reverse=True ) ] } @router.get("/obsidian/graph") async def get_obsidian_graph(): """Get note connection graph""" if not obsidian_integrator.links_graph: raise HTTPException(status_code=400, detail="Vault not scanned") nodes = [] links = [] for note_title, note_data in obsidian_integrator.notes_cache.items(): nodes.append({ "id": note_title, "title": note_title, "tags": note_data["tags"], "size": note_data["size"] }) for note_title, graph_data in obsidian_integrator.links_graph.items(): for linked_note in graph_data["outbound"]: if linked_note in obsidian_integrator.notes_cache: links.append({ "source": note_title, "target": linked_note }) return { "nodes": nodes, "links": links } # ===================== # GOOGLE DRIVE ENDPOINTS # ===================== @router.post("/google-drive/auth") async def authenticate_google_drive(): """Authenticate with Google Drive""" success = gdrive_integrator.authenticate() if not success: raise HTTPException( status_code=401, detail="Authentication failed. Check client_secrets.json" ) return {"status": "ok", "authenticated": True} @router.get("/google-drive/files") async def list_google_drive_files( folder_id: Optional[str] = None, max_results: int = 50 ): """List files from Google Drive""" files = gdrive_integrator.list_files(folder_id=folder_id, max_results=max_results) return { "files": files, "count": len(files) } @router.post("/google-drive/sync") async def sync_google_drive(request: GDriveSyncRequest): """Sync files from Google Drive""" from pathlib import Path output_path = Path(request.output_dir) output_path.mkdir(parents=True, exist_ok=True) stats = gdrive_integrator.sync_to_daarion( output_path, folder_ids=request.folder_ids, file_extensions=request.file_extensions ) return { "status": "ok", "stats": stats } @router.get("/google-drive/folders") async def get_google_drive_folders(): """Get folder structure from Google Drive""" structure = gdrive_integrator.get_folder_structure() return {"structure": structure}