enricher_templates.py 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. """API routes for enricher templates management."""
  2. from typing import List
  3. from uuid import UUID
  4. from fastapi import APIRouter, Depends, HTTPException, Query, status
  5. from flowsint_core.core.models import Profile
  6. from flowsint_core.core.postgre_db import get_db
  7. from flowsint_core.core.services import (
  8. ConflictError,
  9. NotFoundError,
  10. ValidationError,
  11. create_enricher_template_service,
  12. create_template_generator_service,
  13. )
  14. from flowsint_core.core.template_enricher import TemplateEnricher
  15. from flowsint_core.core.vault import Vault
  16. from flowsint_core.templates.types import Template
  17. from sqlalchemy.orm import Session
  18. from flowsint_types.registry import get_type as get_type_from_registry, load_all_types
  19. from app.api.deps import get_current_user
  20. from app.api.schemas.enricher_template import (
  21. EnricherTemplateCreate,
  22. EnricherTemplateGenerateRequest,
  23. EnricherTemplateGenerateResponse,
  24. EnricherTemplateList,
  25. EnricherTemplateRead,
  26. EnricherTemplateTestRequest,
  27. EnricherTemplateTestResponse,
  28. EnricherTemplateUpdate,
  29. )
  30. router = APIRouter()
  31. @router.post(
  32. "", response_model=EnricherTemplateRead, status_code=status.HTTP_201_CREATED
  33. )
  34. def create_template(
  35. template: EnricherTemplateCreate,
  36. db: Session = Depends(get_db),
  37. current_user: Profile = Depends(get_current_user),
  38. ):
  39. """Create a new enricher template."""
  40. content = template.content
  41. name = content.get("name", template.name)
  42. description = content.get("description", template.description)
  43. category = content.get("category", template.category)
  44. version = float(content.get("version", template.version))
  45. service = create_enricher_template_service(db)
  46. try:
  47. return service.create_template(
  48. name=name,
  49. description=description,
  50. category=category,
  51. version=version,
  52. content=content,
  53. is_public=template.is_public,
  54. owner_id=current_user.id,
  55. )
  56. except ConflictError as e:
  57. raise HTTPException(status_code=400, detail=str(e))
  58. @router.get("", response_model=List[EnricherTemplateList])
  59. def list_templates(
  60. category: str = Query(None, description="Filter by category"),
  61. include_public: bool = Query(
  62. True, description="Include public templates from other users"
  63. ),
  64. db: Session = Depends(get_db),
  65. current_user: Profile = Depends(get_current_user),
  66. ):
  67. """List enricher templates."""
  68. service = create_enricher_template_service(db)
  69. return service.list_templates(current_user.id, category, include_public)
  70. @router.post("/generate", response_model=EnricherTemplateGenerateResponse)
  71. async def generate_template(
  72. request: EnricherTemplateGenerateRequest,
  73. db: Session = Depends(get_db),
  74. current_user: Profile = Depends(get_current_user),
  75. ):
  76. """Generate an enricher template from a free-text description using AI."""
  77. load_all_types()
  78. input_schema = None
  79. output_schema = None
  80. if request.input_type:
  81. input_cls = get_type_from_registry(request.input_type, case_sensitive=True)
  82. if input_cls is None:
  83. raise HTTPException(
  84. status_code=422,
  85. detail=f"Unknown input type: '{request.input_type}'",
  86. )
  87. input_schema = input_cls.model_json_schema()
  88. if request.output_type:
  89. output_cls = get_type_from_registry(request.output_type, case_sensitive=True)
  90. if output_cls is None:
  91. raise HTTPException(
  92. status_code=422,
  93. detail=f"Unknown output type: '{request.output_type}'",
  94. )
  95. output_schema = output_cls.model_json_schema()
  96. service = create_template_generator_service(db)
  97. try:
  98. yaml_content = await service.generate(
  99. prompt=request.prompt,
  100. owner_id=current_user.id,
  101. input_type=request.input_type,
  102. input_schema=input_schema,
  103. output_type=request.output_type,
  104. output_schema=output_schema,
  105. )
  106. except ValidationError as e:
  107. raise HTTPException(status_code=422, detail=str(e))
  108. return EnricherTemplateGenerateResponse(yaml_content=yaml_content)
  109. @router.post("/{template_id}/test", response_model=EnricherTemplateTestResponse)
  110. async def test_template(
  111. template_id: UUID,
  112. test_request: EnricherTemplateTestRequest,
  113. db: Session = Depends(get_db),
  114. current_user: Profile = Depends(get_current_user),
  115. ):
  116. """Test an enricher template with a sample input value."""
  117. service = create_enricher_template_service(db)
  118. try:
  119. db_template = service.get_template(template_id, current_user.id)
  120. except NotFoundError:
  121. raise HTTPException(status_code=404, detail="Template not found")
  122. try:
  123. content = db_template.content
  124. template = Template(**content)
  125. vault = Vault(db=db, owner_id=current_user.id)
  126. enricher = TemplateEnricher(
  127. sketch_id="123", scan_id="123", template=template, vault=vault
  128. )
  129. await enricher.async_init()
  130. pre = enricher.preprocess([test_request.input_value])
  131. results = await enricher.scan(pre)
  132. data = {"results": results, "raw_results": enricher.get_raw_response()}
  133. return EnricherTemplateTestResponse(
  134. success=True, data=data, status_code=200, url=template.request.url
  135. )
  136. except Exception as e:
  137. raise HTTPException(status_code=500, detail=f"An error occured : {e}")
  138. @router.get("/{template_id}", response_model=EnricherTemplateRead)
  139. def get_template(
  140. template_id: UUID,
  141. db: Session = Depends(get_db),
  142. current_user: Profile = Depends(get_current_user),
  143. ):
  144. """Get a specific enricher template by ID."""
  145. service = create_enricher_template_service(db)
  146. try:
  147. return service.get_template(template_id, current_user.id)
  148. except NotFoundError:
  149. raise HTTPException(status_code=404, detail="Template not found")
  150. @router.put("/{template_id}", response_model=EnricherTemplateRead)
  151. def update_template(
  152. template_id: UUID,
  153. update_data: EnricherTemplateUpdate,
  154. db: Session = Depends(get_db),
  155. current_user: Profile = Depends(get_current_user),
  156. ):
  157. """Update an enricher template. Only the owner can update."""
  158. service = create_enricher_template_service(db)
  159. try:
  160. return service.update_template(
  161. template_id=template_id,
  162. owner_id=current_user.id,
  163. update_data=update_data.model_dump(exclude_unset=True),
  164. )
  165. except NotFoundError:
  166. raise HTTPException(status_code=404, detail="Template not found")
  167. except ConflictError as e:
  168. raise HTTPException(status_code=400, detail=str(e))
  169. @router.delete("/{template_id}", status_code=status.HTTP_204_NO_CONTENT)
  170. def delete_template(
  171. template_id: UUID,
  172. db: Session = Depends(get_db),
  173. current_user: Profile = Depends(get_current_user),
  174. ):
  175. """Delete an enricher template. Only the owner can delete."""
  176. service = create_enricher_template_service(db)
  177. try:
  178. service.delete_template(template_id, current_user.id)
  179. except NotFoundError:
  180. raise HTTPException(status_code=404, detail="Template not found")
  181. return None