slicer_presets.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. """Pydantic schemas for the unified slicer-presets endpoint.
  2. The SliceModal pulls printer/process/filament options from three sources, in
  3. priority order: cloud (the user's Bambu Cloud account), local (DB-backed
  4. imported profiles), and standard (slicer-bundled stock profiles). The endpoint
  5. returns all three lists with name-based dedup applied so each preset appears
  6. exactly once across the response.
  7. """
  8. from typing import Literal
  9. from pydantic import BaseModel
  10. CloudStatus = Literal["ok", "not_authenticated", "expired", "unreachable"]
  11. class UnifiedPreset(BaseModel):
  12. """A single printer/process/filament preset with its source.
  13. The ``id`` shape varies by source:
  14. - cloud → Bambu Cloud setting_id (e.g. ``"PFUS9ac902733670a9"``)
  15. - local → stringified DB row id from ``local_presets``
  16. - standard → preset name as written in the bundled JSON (the slicer
  17. resolves bundled profiles by name during inheritance walk)
  18. The frontend treats ``id`` as opaque; the slice dispatch path uses
  19. ``(source, id)`` to fetch / pass the preset content to the sidecar.
  20. ``filament_type`` and ``filament_colour`` are populated for the filament
  21. slot only — they let the SliceModal pre-pick a preset per plate slot in
  22. the multi-color flow by matching against the source 3MF's per-slot type
  23. and color. Populated when the underlying preset JSON exposes them; left
  24. as ``None`` on bundled profiles where colour is a runtime spool attribute.
  25. ``compatible_printers`` is the slicer's own list of printer-preset names a
  26. process / filament preset declares itself valid for. Populated for the
  27. local tier (stored at import time); left ``None`` for cloud (no per-preset
  28. detail is fetched — rate limits) and standard (the sidecar's bundled
  29. listing doesn't expose it). The SliceModal uses it to filter the
  30. process / filament dropdowns by the selected printer (#1325); when it is
  31. ``None`` the modal falls back to the user's uploaded Slicer Bundles, which
  32. map each printer to the presets it ships.
  33. """
  34. id: str
  35. name: str
  36. source: Literal["orca_cloud", "cloud", "local", "standard"]
  37. filament_type: str | None = None
  38. filament_colour: str | None = None
  39. compatible_printers: list[str] | None = None
  40. class UnifiedPresetsBySlot(BaseModel):
  41. """Three slots in the order Bambu Studio / OrcaSlicer use."""
  42. printer: list[UnifiedPreset] = []
  43. process: list[UnifiedPreset] = []
  44. filament: list[UnifiedPreset] = []
  45. class UnifiedPresetsResponse(BaseModel):
  46. """Each tier carries only the names that didn't appear in a higher tier.
  47. Priority order: ``orca_cloud > cloud > local > standard``. Orca Cloud is
  48. highest because it's the most-recently-explicitly-curated source for
  49. users who set up Orca sync (they did it on purpose; their Orca picks
  50. should outrank everything else). Bambu Cloud follows as the next-most-
  51. curated tier. Local imports beat the slicer's stock fallback.
  52. ``cloud_status`` / ``orca_cloud_status`` let the frontend show a banner
  53. explaining why a cloud tier is empty when the user expected to see it
  54. (signed out / token expired / network down). Each tier has its own
  55. status because they can fail independently.
  56. """
  57. orca_cloud: UnifiedPresetsBySlot = UnifiedPresetsBySlot()
  58. cloud: UnifiedPresetsBySlot = UnifiedPresetsBySlot()
  59. local: UnifiedPresetsBySlot = UnifiedPresetsBySlot()
  60. standard: UnifiedPresetsBySlot = UnifiedPresetsBySlot()
  61. cloud_status: CloudStatus = "ok"
  62. orca_cloud_status: CloudStatus = "ok"