Skip to content

Commit 47a9b89

Browse files
committed
routes and deps
1 parent e5d09e1 commit 47a9b89

File tree

5 files changed

+110
-53
lines changed

5 files changed

+110
-53
lines changed

backend/app/api/deps.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,30 @@ def get_current_user_org(
107107
CurrentUserOrg = Annotated[UserOrganization, Depends(get_current_user_org)]
108108

109109

110+
def get_current_user_org_project(
111+
current_user: CurrentUser, session: SessionDep, request: Request
112+
) -> UserProjectOrg:
113+
api_key = request.headers.get("X-API-KEY")
114+
organization_id = None
115+
project_id = None
116+
117+
if api_key:
118+
api_key_record = get_api_key_by_value(session, api_key)
119+
if api_key_record:
120+
validate_organization(session, api_key_record.organization_id)
121+
organization_id = api_key_record.organization_id
122+
project_id = api_key_record.project_id
123+
124+
return UserProjectOrg(
125+
**current_user.model_dump(),
126+
organization_id=organization_id,
127+
project_id=project_id,
128+
)
129+
130+
131+
CurrentUserOrgproject = Annotated[UserProjectOrg, Depends(get_current_user_org_project)]
132+
133+
110134
def get_current_active_superuser(current_user: CurrentUser) -> User:
111135
if not current_user.is_superuser:
112136
raise HTTPException(

backend/app/api/routes/collections.py

Lines changed: 51 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from pydantic import BaseModel, Field, HttpUrl
1212
from sqlalchemy.exc import NoResultFound, MultipleResultsFound, SQLAlchemyError
1313

14-
from app.api.deps import CurrentUser, SessionDep
14+
from app.api.deps import CurrentUser, SessionDep, CurrentUserOrgproject
1515
from app.core.cloud import AmazonCloudStorage
1616
from app.core.config import settings
1717
from app.core.util import now, raise_from_unknown, post_callback
@@ -169,65 +169,59 @@ def _backout(crud: OpenAIAssistantCrud, assistant_id: str):
169169

170170
def do_create_collection(
171171
session: SessionDep,
172-
current_user: CurrentUser,
172+
current_user: CurrentUserOrgproject,
173173
request: CreationRequest,
174174
payload: ResponsePayload,
175175
):
176176
client = OpenAI(api_key=settings.OPENAI_API_KEY)
177-
if request.callback_url is None:
178-
callback = SilentCallback(payload)
179-
else:
180-
callback = WebHookCallback(request.callback_url, payload)
181-
182-
#
183-
# Create the assistant and vector store
184-
#
177+
callback = (
178+
SilentCallback(payload)
179+
if request.callback_url is None
180+
else WebHookCallback(request.callback_url, payload)
181+
)
185182

186183
vector_store_crud = OpenAIVectorStoreCrud(client)
187-
try:
188-
vector_store = vector_store_crud.create()
189-
except OpenAIError as err:
190-
callback.fail(str(err))
191-
return
192-
184+
assistant_crud = OpenAIAssistantCrud(client)
193185
storage = AmazonCloudStorage(current_user)
194186
document_crud = DocumentCrud(session, current_user.id)
195-
assistant_crud = OpenAIAssistantCrud(client)
187+
collection_crud = CollectionCrud(session, current_user.id)
196188

197-
docs = request(document_crud)
198-
kwargs = dict(request.extract_super_type(AssistantOptions))
199189
try:
190+
vector_store = vector_store_crud.create()
191+
192+
docs = request(document_crud)
200193
updates = vector_store_crud.update(vector_store.id, storage, docs)
201194
documents = list(updates)
195+
196+
kwargs = dict(request.extract_super_type(AssistantOptions))
202197
assistant = assistant_crud.create(vector_store.id, **kwargs)
203-
except Exception as err: # blanket to handle SQL and OpenAI errors
204-
logging.error(f"File Search setup error: {err} ({type(err).__name__})")
205-
vector_store_crud.delete(vector_store.id)
206-
callback.fail(str(err))
207-
return
208198

209-
#
210-
# Store the results
211-
#
199+
# 3. Read and update collection with assistant info
200+
collection = collection_crud.read_one(UUID(payload.key))
201+
collection.llm_service_id = assistant.id
202+
collection.llm_service_name = request.model
203+
collection.status = "successfull"
204+
collection.updated_at = now()
212205

213-
collection_crud = CollectionCrud(session, current_user.id)
214-
collection = Collection(
215-
id=UUID(payload.key),
216-
llm_service_id=assistant.id,
217-
llm_service_name=request.model,
218-
)
219-
try:
220-
collection_crud.create(collection, documents)
221-
except SQLAlchemyError as err:
222-
_backout(assistant_crud, assistant.id)
223-
callback.fail(str(err))
224-
return
206+
dc_crud = DocumentCollectionCrud(session)
207+
dc_crud.create(collection, documents)
225208

226-
#
227-
# Send back successful response
228-
#
209+
collection_crud._update(collection)
229210

230-
callback.success(collection.model_dump(mode="json"))
211+
callback.success({"id": payload.key})
212+
except Exception as err:
213+
logging.error(f"[CollectionTask] Failed: {err} ({type(err).__name__})")
214+
215+
# 4. On failure, update collection status only
216+
try:
217+
collection = collection_crud.read_one(UUID(payload.key))
218+
collection.status = "failed"
219+
collection.updated_at = now()
220+
collection_crud._update(collection)
221+
except Exception as suberr:
222+
logging.error(f"Failed to update collection status: {suberr}")
223+
224+
callback.fail(str(err))
231225

232226

233227
@router.post(
@@ -236,14 +230,27 @@ def do_create_collection(
236230
)
237231
def create_collection(
238232
session: SessionDep,
239-
current_user: CurrentUser,
233+
current_user: CurrentUserOrgproject,
240234
request: CreationRequest,
241235
background_tasks: BackgroundTasks,
242236
):
243237
this = inspect.currentframe()
244238
route = router.url_path_for(this.f_code.co_name)
245239
payload = ResponsePayload("processing", route)
246240

241+
# 1. Create initial collection record
242+
collection = Collection(
243+
id=UUID(payload.key),
244+
owner_id=current_user.id,
245+
organization_id=current_user.organization_id,
246+
project_id=current_user.project_id,
247+
status="processing",
248+
)
249+
250+
collection_crud = CollectionCrud(session, current_user.id)
251+
collection_crud.create(collection, documents=[])
252+
253+
# 2. Launch background task
247254
background_tasks.add_task(
248255
do_create_collection,
249256
session,

backend/app/models/collection.py

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,46 @@
11
from uuid import UUID, uuid4
22
from datetime import datetime
3+
from typing import Optional
34

45
from sqlmodel import Field, Relationship, SQLModel
56

67
from app.core.util import now
78
from .user import User
9+
from .organization import Organization
10+
from .project import Project
11+
from enum import Enum
812

913

1014
class Collection(SQLModel, table=True):
11-
id: UUID = Field(
12-
default_factory=uuid4,
13-
primary_key=True,
14-
)
15+
id: UUID = Field(default_factory=uuid4, primary_key=True)
16+
1517
owner_id: int = Field(
1618
foreign_key="user.id",
1719
nullable=False,
1820
ondelete="CASCADE",
1921
)
20-
llm_service_id: str
21-
llm_service_name: str
22-
created_at: datetime = Field(
23-
default_factory=now,
22+
23+
organization_id: int = Field(
24+
foreign_key="organization.id",
25+
nullable=False,
26+
ondelete="CASCADE",
27+
)
28+
29+
project_id: int = Field(
30+
foreign_key="project.id",
31+
nullable=True,
32+
ondelete="SET NULL",
2433
)
25-
deleted_at: datetime | None
34+
35+
llm_service_id: Optional[str] = Field(default=None, nullable=True)
36+
llm_service_name: Optional[str] = Field(default=None, nullable=True)
37+
38+
status: Optional[str] = None
39+
40+
created_at: datetime = Field(default_factory=now)
41+
updated_at: datetime = Field(default_factory=now)
42+
deleted_at: Optional[datetime] = None
2643

2744
owner: User = Relationship(back_populates="collections")
45+
organization: Organization = Relationship(back_populates="collections")
46+
project: Project = Relationship(back_populates="collections")

backend/app/models/organization.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from .project import Project
1111
from .api_key import APIKey
1212
from .assistants import Assistant
13+
from .collection import Collection
1314

1415

1516
# Shared properties for an Organization
@@ -48,6 +49,9 @@ class Organization(OrganizationBase, table=True):
4849
assistants: list["Assistant"] = Relationship(
4950
back_populates="organization", sa_relationship_kwargs={"cascade": "all, delete"}
5051
)
52+
collections: list["Collection"] = Relationship(
53+
back_populates="organization", sa_relationship_kwargs={"cascade": "all, delete"}
54+
)
5155

5256

5357
# Properties to return via API

backend/app/models/project.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ class Project(ProjectBase, table=True):
4444
back_populates="project", sa_relationship_kwargs={"cascade": "all, delete"}
4545
)
4646
organization: Optional["Organization"] = Relationship(back_populates="project")
47+
collections: list["Collection"] = Relationship(
48+
back_populates="project", sa_relationship_kwargs={"cascade": "all, delete"}
49+
)
4750

4851

4952
# Properties to return via API

0 commit comments

Comments
 (0)