archive.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. from datetime import datetime
  2. from pydantic import BaseModel
  3. class ArchiveBase(BaseModel):
  4. print_name: str | None = None
  5. is_favorite: bool | None = None
  6. tags: str | None = None
  7. notes: str | None = None
  8. cost: float | None = None
  9. failure_reason: str | None = None
  10. class ArchiveUpdate(ArchiveBase):
  11. printer_id: int | None = None
  12. project_id: int | None = None
  13. status: str | None = None # Allow changing status (e.g., clearing failed flag)
  14. class ArchiveDuplicate(BaseModel):
  15. """Reference to a duplicate archive."""
  16. id: int
  17. print_name: str | None
  18. created_at: datetime
  19. match_type: str # "exact" (hash match) or "similar" (name match)
  20. class ArchiveResponse(BaseModel):
  21. id: int
  22. printer_id: int | None
  23. project_id: int | None = None
  24. project_name: str | None = None # Included for convenience
  25. filename: str
  26. file_path: str
  27. file_size: int
  28. content_hash: str | None
  29. thumbnail_path: str | None
  30. timelapse_path: str | None
  31. source_3mf_path: str | None = None # Original project 3MF from slicer
  32. # Duplicate detection
  33. duplicates: list[ArchiveDuplicate] | None = None
  34. duplicate_count: int = 0 # Quick count for list views
  35. print_name: str | None
  36. print_time_seconds: int | None # Estimated time from slicer
  37. actual_time_seconds: int | None = None # Computed from started_at/completed_at
  38. time_accuracy: float | None = None # Percentage: 100 = perfect, >100 = faster than estimated
  39. filament_used_grams: float | None
  40. filament_type: str | None
  41. filament_color: str | None
  42. layer_height: float | None
  43. total_layers: int | None = None
  44. nozzle_diameter: float | None
  45. bed_temperature: int | None
  46. nozzle_temperature: int | None
  47. status: str
  48. started_at: datetime | None
  49. completed_at: datetime | None
  50. extra_data: dict | None
  51. makerworld_url: str | None
  52. designer: str | None
  53. is_favorite: bool
  54. tags: str | None
  55. notes: str | None
  56. cost: float | None
  57. photos: list | None
  58. failure_reason: str | None
  59. # Energy tracking
  60. energy_kwh: float | None = None
  61. energy_cost: float | None = None
  62. created_at: datetime
  63. class Config:
  64. from_attributes = True
  65. class ArchiveStats(BaseModel):
  66. total_prints: int
  67. successful_prints: int
  68. failed_prints: int
  69. total_print_time_hours: float
  70. total_filament_grams: float
  71. total_cost: float
  72. prints_by_filament_type: dict
  73. prints_by_printer: dict
  74. # Time accuracy stats
  75. average_time_accuracy: float | None = None # Average across all prints with data
  76. time_accuracy_by_printer: dict | None = None # Per-printer accuracy
  77. # Energy stats
  78. total_energy_kwh: float = 0.0
  79. total_energy_cost: float = 0.0
  80. class ProjectPageImage(BaseModel):
  81. """Image embedded in 3MF project page."""
  82. name: str
  83. path: str # Path within 3MF
  84. url: str # API URL to fetch image
  85. class ProjectPageResponse(BaseModel):
  86. """Project page data extracted from 3MF file."""
  87. # Model info
  88. title: str | None = None
  89. description: str | None = None # HTML content
  90. designer: str | None = None
  91. designer_user_id: str | None = None
  92. license: str | None = None
  93. copyright: str | None = None
  94. creation_date: str | None = None
  95. modification_date: str | None = None
  96. origin: str | None = None # "original" or "remix"
  97. # Profile info
  98. profile_title: str | None = None
  99. profile_description: str | None = None
  100. profile_cover: str | None = None
  101. profile_user_id: str | None = None
  102. profile_user_name: str | None = None
  103. # MakerWorld info
  104. design_model_id: str | None = None
  105. design_profile_id: str | None = None
  106. design_region: str | None = None
  107. # Images
  108. model_pictures: list[ProjectPageImage] = []
  109. profile_pictures: list[ProjectPageImage] = []
  110. thumbnails: list[ProjectPageImage] = []
  111. class ProjectPageUpdate(BaseModel):
  112. """Update project page data in 3MF file."""
  113. title: str | None = None
  114. description: str | None = None
  115. designer: str | None = None
  116. license: str | None = None
  117. copyright: str | None = None
  118. profile_title: str | None = None
  119. profile_description: str | None = None