feat: add appointments, campaigns, admin, storage, tests and various updates

- Add new routers: admin, appointments, campaigns
- Add storage service and logging config
- Add migrations directory and test suite with pytest config
- Add supabase_migration_features.sql
- Update models, dependencies, config, and existing routers
- Remove whatsapp_service (deleted)
- Update pyproject.toml and uv.lock dependencies

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
belviskhoremk
2026-04-03 09:11:58 +00:00
parent 9dccc83293
commit 92d4c2fc5e
51 changed files with 7076 additions and 515 deletions

View File

@@ -5,6 +5,7 @@ from app.dependencies import get_current_user
from app.services.document_processor import process_document
from app.services.embeddings import embedding_service
from app.services.vector_store import vector_store
from app.services.storage import delete_from_storage, extract_storage_path
from app.config import settings
from typing import List
import uuid
@@ -205,10 +206,72 @@ async def delete_document(chatbot_id: str, document_id: str, user=Depends(get_cu
except Exception as e:
logger.warning(f"Failed to delete vectors: {e}")
# Delete file from Supabase Storage
if doc.data[0].get("file_url"):
delete_from_storage(supabase, "documents", doc.data[0]["file_url"])
supabase.table("documents").delete().eq("id", document_id).execute()
return SuccessResponse(success=True, message="Document deleted")
@router.post("/{document_id}/retry", response_model=DocumentResponse)
async def retry_document_processing(
chatbot_id: str,
document_id: str,
background_tasks: BackgroundTasks,
user=Depends(get_current_user),
):
"""Retry processing a failed document."""
supabase = get_supabase()
chatbot = _get_user_chatbot(chatbot_id, user.id, supabase)
doc = supabase.table("documents").select("*").eq("id", document_id).eq("chatbot_id", chatbot_id).execute()
if not doc.data:
raise HTTPException(status_code=404, detail="Document not found")
document = doc.data[0]
if document.get("status") != "failed":
raise HTTPException(status_code=400, detail="Only failed documents can be retried")
file_url = document.get("file_url")
if not file_url:
raise HTTPException(
status_code=400,
detail="No file URL stored. Please re-upload this document."
)
# Download file from storage
try:
path = extract_storage_path(file_url, "documents")
if not path:
raise HTTPException(status_code=400, detail="Cannot locate file in storage. Please re-upload.")
file_bytes = supabase.storage.from_("documents").download(path)
except HTTPException:
raise
except Exception as e:
logger.error(f"Failed to download document {document_id} for retry: {e}")
raise HTTPException(status_code=400, detail="Cannot retrieve file from storage. Please re-upload.")
# Reset status to processing
result = supabase.table("documents").update({
"status": "processing",
"error_message": None,
"chunk_count": 0,
}).eq("id", document_id).execute()
# Re-enqueue background processing
background_tasks.add_task(
_process_document_bg,
file_bytes=file_bytes,
file_name=document["file_name"],
doc_id=document_id,
chatbot=chatbot,
supabase=supabase,
)
return DocumentResponse(**result.data[0])
# ── URL Sources ───────────────────────────────────────────────────────────────
@url_router.get("", response_model=List[UrlSourceResponse])