feat(phase7): add asset classification workflow
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
from .asset_library_repository import SQLAlchemyAssetLibraryRepository
|
||||
from .asset_repository import SQLAlchemyAssetRepository
|
||||
from .classification_job_repository import SQLAlchemyClassificationJobRepository
|
||||
from .ingest_job_repository import SQLAlchemyIngestJobRepository
|
||||
from .project_repository import SQLAlchemyProjectRepository
|
||||
from .session import Base, build_engine, build_session_factory, ensure_database_exists, initialize_database
|
||||
@@ -10,6 +11,7 @@ __all__ = [
|
||||
"Base",
|
||||
"SQLAlchemyAssetLibraryRepository",
|
||||
"SQLAlchemyAssetRepository",
|
||||
"SQLAlchemyClassificationJobRepository",
|
||||
"SQLAlchemyIngestJobRepository",
|
||||
"SQLAlchemyProjectRepository",
|
||||
"build_engine",
|
||||
|
||||
@@ -11,34 +11,59 @@ class SQLAlchemyAssetRepository:
|
||||
self.session = session
|
||||
|
||||
def list_by_library(self, library_id: str) -> list[Asset]:
|
||||
models = self.session.query(AssetModel).filter(AssetModel.library_id == library_id).all()
|
||||
return [
|
||||
Asset(
|
||||
id=model.id,
|
||||
workspace_id=model.workspace_id,
|
||||
project_id=model.project_id,
|
||||
library_id=model.library_id,
|
||||
name=model.name,
|
||||
storage_key=model.storage_key,
|
||||
mime_type=model.mime_type,
|
||||
metadata=json.loads(model.metadata_json),
|
||||
created_at=model.created_at,
|
||||
)
|
||||
for model in models
|
||||
]
|
||||
models = self.session.query(AssetModel).filter(AssetModel.asset_library_id == library_id).all()
|
||||
return [self._to_domain(model) for model in models]
|
||||
|
||||
def get(self, asset_id: str) -> Asset | None:
|
||||
model = self.session.query(AssetModel).filter(AssetModel.id == asset_id).first()
|
||||
if model is None:
|
||||
return None
|
||||
return self._to_domain(model)
|
||||
|
||||
def create(self, asset: Asset) -> Asset:
|
||||
model = AssetModel(
|
||||
id=asset.id,
|
||||
workspace_id=asset.workspace_id,
|
||||
project_id=asset.project_id,
|
||||
library_id=asset.library_id,
|
||||
asset_library_id=asset.library_id,
|
||||
name=asset.name,
|
||||
storage_key=asset.storage_key,
|
||||
mime_type=asset.mime_type,
|
||||
metadata_json=json.dumps(asset.metadata),
|
||||
file_type=asset.mime_type.split('/')[0] if '/' in asset.mime_type else asset.mime_type,
|
||||
file_size=0,
|
||||
file_url=asset.storage_key,
|
||||
uploaded_by_user_id='system',
|
||||
classification_result=json.dumps(asset.metadata),
|
||||
created_at=asset.created_at,
|
||||
updated_at=asset.created_at,
|
||||
)
|
||||
self.session.add(model)
|
||||
self.session.commit()
|
||||
return asset
|
||||
|
||||
def update(self, asset: Asset) -> Asset:
|
||||
model = self.session.query(AssetModel).filter(AssetModel.id == asset.id).first()
|
||||
if model is None:
|
||||
raise ValueError(f"Asset {asset.id} not found")
|
||||
model.name = asset.name
|
||||
model.classification_result = json.dumps(asset.metadata)
|
||||
model.updated_at = asset.created_at
|
||||
self.session.commit()
|
||||
return asset
|
||||
|
||||
def _to_domain(self, model: AssetModel) -> Asset:
|
||||
metadata = {}
|
||||
if model.classification_result:
|
||||
try:
|
||||
metadata = json.loads(model.classification_result)
|
||||
except Exception:
|
||||
metadata = {}
|
||||
return Asset(
|
||||
id=model.id,
|
||||
workspace_id=model.workspace_id,
|
||||
project_id=model.project_id,
|
||||
library_id=model.asset_library_id,
|
||||
name=model.name,
|
||||
storage_key=model.file_url,
|
||||
mime_type=model.file_type,
|
||||
metadata=metadata,
|
||||
created_at=model.created_at,
|
||||
)
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from packages.adapters.sqlalchemy_impl.models import ClassificationJobModel
|
||||
from packages.domain import ClassificationJob, ClassificationJobStatus
|
||||
|
||||
|
||||
class SQLAlchemyClassificationJobRepository:
|
||||
def __init__(self, session: Session):
|
||||
self.session = session
|
||||
|
||||
def create(self, job: ClassificationJob) -> ClassificationJob:
|
||||
model = ClassificationJobModel(
|
||||
id=job.id,
|
||||
workspace_id=job.workspace_id,
|
||||
project_id=job.project_id,
|
||||
asset_id=job.asset_id,
|
||||
status=job.status.value,
|
||||
classification=job.classification,
|
||||
confidence=job.confidence,
|
||||
error_message=job.error_message,
|
||||
created_at=job.created_at,
|
||||
updated_at=job.updated_at,
|
||||
)
|
||||
self.session.add(model)
|
||||
self.session.commit()
|
||||
return job
|
||||
|
||||
def get(self, job_id: str) -> ClassificationJob | None:
|
||||
model = self.session.query(ClassificationJobModel).filter(ClassificationJobModel.id == job_id).first()
|
||||
if model is None:
|
||||
return None
|
||||
return ClassificationJob(
|
||||
id=model.id,
|
||||
workspace_id=model.workspace_id,
|
||||
project_id=model.project_id,
|
||||
asset_id=model.asset_id,
|
||||
status=ClassificationJobStatus(model.status),
|
||||
classification=model.classification,
|
||||
confidence=model.confidence,
|
||||
error_message=model.error_message,
|
||||
created_at=model.created_at,
|
||||
updated_at=model.updated_at,
|
||||
)
|
||||
|
||||
def update(self, job: ClassificationJob) -> ClassificationJob:
|
||||
model = self.session.query(ClassificationJobModel).filter(ClassificationJobModel.id == job.id).first()
|
||||
if model is None:
|
||||
raise ValueError(f"ClassificationJob {job.id} not found")
|
||||
model.status = job.status.value
|
||||
model.classification = job.classification
|
||||
model.confidence = job.confidence
|
||||
model.error_message = job.error_message
|
||||
model.updated_at = job.updated_at
|
||||
self.session.commit()
|
||||
return job
|
||||
@@ -70,6 +70,21 @@ class IngestJobModel(Base):
|
||||
updated_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))
|
||||
|
||||
|
||||
class ClassificationJobModel(Base):
|
||||
__tablename__ = "classification_jobs"
|
||||
|
||||
id = Column(String(32), primary_key=True)
|
||||
workspace_id = Column(String(32), nullable=False, index=True)
|
||||
project_id = Column(String(32), nullable=False, index=True)
|
||||
asset_id = Column(String(32), nullable=False, index=True)
|
||||
status = Column(String(20), nullable=False, default="pending")
|
||||
classification = Column(String(50), nullable=False, default="")
|
||||
confidence = Column(Float, nullable=False, default=0.0)
|
||||
error_message = Column(Text, nullable=False, default="")
|
||||
created_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))
|
||||
updated_at = Column(DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))
|
||||
|
||||
|
||||
class TaskModel(Base):
|
||||
__tablename__ = "tasks"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user