Compare commits

...
Author SHA1 Message Date
CrossPr0duct 6c96f21bd7 Merge branch 'main' into feature/bugfixes 2025-06-11 13:42:28 -04:00
CrossPr0duct 245409de08 Fixed one off issue. 2025-06-11 13:25:27 -04:00
CrossPr0duct 90d0f15176 Wired ContextMenu debugging small issue. 2025-06-11 13:06:07 -04:00
CrossPr0duct 257db9b892 render order is now correct. 2025-06-10 20:29:52 -04:00
CrossPr0duct 70348a922a Z indicies for paint seem to be ignored. 2025-06-10 17:39:10 -04:00
CrossPr0duct 95e724e4bd Fixed outline problem 2025-06-10 12:37:20 -04:00
BFlat df0b98ec63 drag and drop gallery 3d objects to 3d scene feature (#666)
- can now drag and drop 3d models onto the editor scene from the gallery
modal
2025-06-10 12:48:44 +07:00
BFlat f214577af1 2D canvas gallery image drop feature (#665)
- now you can drag and drop onto the 2D canvas from the gallery modal
2025-06-10 12:24:28 +07:00
ArEnScandCrossPr0duct 3efe9db4ca Create Menus and Bug Fixes (#664)
Removed:
Save and Load Scene for later.
Added undo and redo as button.
Hide Generate Image
Added a menu ( still needs logic code )
Fixed Opacity on brush.

---------

Co-authored-by: CrossPr0duct <alicextensor@gmail.com>
2025-06-09 17:36:16 -04:00
CrossPr0duct 21ea7d05e2 Fixed brush 2025-06-09 17:07:16 -04:00
CrossPr0duct e8305bd112 Add in redo and undo and hide a few components. 2025-06-09 14:55:07 -04:00
Brandon Thomas 8208206e5a missing 2025-06-09 12:20:21 -04:00
Tanish Manku 4f33e74e3a Make 3D state save and load on tab change (#661) 2025-06-06 22:50:47 -07:00
Brandon Thomas f75b210dcd end-to-end fal in artcraft backend (#663) 2025-06-06 21:37:06 -04:00
Brandon ThomasandMichael Chung 7a07f196d1 Fix Safari issue (#662)
Co-authored-by: Michael Chung <michaelchung@mac.home>
2025-06-06 20:26:30 -04:00
a609282d8a Feature/page draw (#659)
Co-authored-by: CrossPr0duct <alicextensor@gmail.com>
Co-authored-by: BFlat <bombayapirat@gmail.com>
2025-06-06 12:03:09 -04:00
BFlat 0a32e06cd5 reusable model selector (#660)
- reusable model selector component
- uses zustand with separated states for each tab

Image model list:
- GPT Image 1 (GPT-4o)
- Flux Pro Ultra
- Recraft 3
- Flux.1 Kontext

Video model list:
- Kling 2.0
- Runway
2025-06-06 17:31:36 +07:00
Brandon Thomas f1563feb91 codegen db 2025-06-05 09:24:06 -04:00
Brandon Thomas cc73ffab5d mark fal jobs complete (#658) 2025-06-05 09:19:38 -04:00
Brandon Thomas d374d9339c codegen db 2025-06-05 00:20:34 -04:00
Brandon Thomas 53681eac3f hunyuan2 image-to-3d (#657) 2025-06-05 00:15:13 -04:00
Brandon Thomas f22369ea4a update artcraft website with download links 2025-06-04 22:01:22 -04:00
Brandon Thomas f7060c0278 classify cloudflare errors 2025-06-04 20:33:27 -04:00
Brandon Thomas 2af8fbd9e1 npm install verbose flags 2025-06-04 20:10:05 -04:00
BFlat a4eb74292f login and popup modals (#652)
- moved artcraft login to first step before sora login
- made sora login skippable
- added pop up to block generation if sora session is not found
2025-06-04 19:47:27 -04:00
Tanish Manku 78b8c56066 Make 2D, 3D, image, video conditionally render (#654) 2025-06-04 14:47:39 -07:00
Brandon Thomas 221aa347bf forgot to commit these 2025-06-04 09:31:34 -04:00
Brandon Thomas 14a27ee803 fal endpoints: kling video 1.6 (#656) 2025-06-04 09:27:26 -04:00
Brandon Thomas 36e35dab0b fal on the backend (#653) 2025-06-03 14:59:28 -04:00
Brandon Thomas cb868c7275 add migrations and materialized final schema 2025-06-02 18:00:04 +05:30
Brandon Thomas b756f81421 vendor in fal-rs so we can hack in webhook support (then upstream it) (#650) 2025-06-02 01:43:18 -04:00
Brandon Thomas 0a1ad3d814 less flux-y generated images as background 2025-06-01 19:13:09 -04:00
Brandon Thomas 9df8c981cd fix api docs 2025-06-01 16:16:50 -04:00
Brandon Thomas e7622318c4 deprecate old endpoints (don't remove yet) (#649) 2025-06-01 15:51:37 -04:00
Brandon Thomas 352c7517cc openart client (maybe we won't do this just yet) (#648) 2025-05-30 19:39:41 -04:00
bflatastic 010a2f043a Remove old unused SettingsModal component 2025-05-30 16:09:25 +07:00
bflatastic cbb32f8275 Fix vertical line color in AssetModal and SettingsModal 2025-05-30 16:08:45 +07:00
bflatastic 0aecc97ede Update TopBar component: correct label for video tab from "Prompt to Video" to "Image to Video" 2025-05-30 15:44:43 +07:00
bflatastic 72a1bb07e0 Update command in windows_frontend_dev.ps1 to use 'npx' for executing nx dev 2025-05-30 13:05:06 +07:00
Brandon Thomas 6a01e4bba0 we don't need to spam the logs with the challenge html 2025-05-30 00:22:01 -04:00
Brandon Thomas 90d741323c check cloudflare challenges 2025-05-30 00:03:48 -04:00
Brandon Thomas 066d1c8bfb emit version to logging, add old sora cookie name 2025-05-29 21:38:07 -04:00
Brandon Thomas 3536736f53 better logging of sora session issues 2025-05-29 20:42:33 -04:00
Brandon Thomas 76d1f65164 more better alerts (#647) 2025-05-29 05:28:16 -04:00
Brandon Thomas ab72551ee7 better events (#646) 2025-05-29 05:03:32 -04:00
Brandon Thomas 9cf87cda5b start phasing fields out from our OpenAI client. These are a liability
It's smarter to just dump the fields we don't care about. That is less
of a chance that we got things wrong or things become incongruent at
runtime in the field.
2025-05-28 20:26:07 -04:00
Brandon Thomas 5163f357af fix nullable type in sora api 2025-05-28 12:15:08 -04:00
BFlat 42dfa9263d artcraft site landing update (#645) 2025-05-28 15:14:35 +07:00
Brandon Thomas f4d9385668 Fix package.lock (#644) 2025-05-28 01:20:09 -04:00
Brandon Thomas 189d6a6df8 refactor response types 2025-05-27 23:37:34 -04:00
Brandon Thomas 89cdc8492f tabs refactor (#643) 2025-05-27 22:54:04 -04:00
BFlat 46d2944823 background gallery for image tab (#638)
- reduced image size
- a more performant css only animation
2025-05-27 22:25:27 -04:00
ArEnScandMichael Chung 216e091257 Fixing build issue with button-link. (#642)
Co-authored-by: Michael Chung <michaelchung@mac.home>
2025-05-27 19:27:24 -04:00
Brandon Thomas f8bfa3ab2b fix nx builds (#641) 2025-05-27 18:58:47 -04:00
Brandon Thomas 569622bcc0 make frontend/clean_modules.sh take the nuclear option 2025-05-27 16:52:12 -04:00
Brandon Thomas 7aad79d16b timestamp when build finishes 2025-05-27 15:14:45 -04:00
Brandon Thomas d70f8ac41e fix circular deps in nx (#639) 2025-05-27 14:25:57 -04:00
ArEnSc 7097144e19 Removals (#636)
Co-authored-by: CrossPr0duct <alicextensor@gmail.com>
Co-authored-by: Michael Chung <michaelchung@mac.home>
Co-authored-by: bflatastic <bombayapirat@gmail.com>
Co-authored-by: Tanish Manku <tanish2k09.dev@gmail.com>
Good work every one =)
2025-05-27 12:00:35 -04:00
Brandon Thomas 709af560a5 enqueue gpt-4o images too 2025-05-26 23:46:05 -04:00
Brandon Thomas 0f1cf93252 add fal image generation end-to-end (recraft, etc.) (#637) 2025-05-26 21:33:21 -04:00
bflatastic 4a10581e9a fix drag and drop logic for 3D and 2D tabs in PageEditor component 2025-05-26 23:31:47 +07:00
bflatastic 447a70b890 differentiate tabs to drop amd set up place for drag and drop on 2d 2025-05-26 23:26:13 +07:00
Brandon Thomas f4e998d945 cleanup deps (#635) 2025-05-26 01:38:27 -04:00
Brandon Thomas a954859ac2 cleanup dead dependencies 2025-05-25 23:55:15 -04:00
Brandon Thomas 2d8e835401 standardize actix versions in root Cargo.toml 2025-05-25 23:47:12 -04:00
Brandon Thomas c23380af90 codegen db 2025-05-25 23:22:10 -04:00
Brandon Thomas c34f75d071 cleanup hakari packages 2025-05-25 23:15:32 -04:00
Brandon Thomas 8a886e9033 cleanup scripts (2) 2025-05-25 22:57:01 -04:00
Brandon Thomas 3101df8211 cleanup scripts 2025-05-25 22:53:40 -04:00
Brandon Thomas a4c264ebbf cleanup packages, fixup storyteller-web 2025-05-25 22:50:45 -04:00
Brandon Thomas 3d807fdeb2 refactor database crates 2025-05-25 22:33:18 -04:00
Brandon Thomas b3a62cce64 refactor packages 2025-05-25 22:09:59 -04:00
Brandon Thomas 42ccc25e4d fix video enqueue 2025-05-25 21:31:56 -04:00
Brandon Thomas 6595518b35 add detailed build info in an about settings pane (#634) 2025-05-25 14:45:50 -04:00
ArEnSc 618cbc8f0e Feature/clean (#633)
Clean up the TS work unify and the app
2025-05-24 23:31:25 -04:00
BFlat b31a152c1a text to image tab (commented out) (#632) 2025-05-24 10:57:28 +07:00
BFlat 0e2169b902 updated topbar menu icons with tooltip (#631)
- animated on hover
- to accommodate more pages
2025-05-23 23:20:09 +07:00
Michael Chung 0ee9b7c442 fix: remove DialogTitle from DialogEditText 2025-05-23 11:33:48 -04:00
bflatastic 17495276e7 Refactor GalleryModal refresh logic and add refresh button
- Simplified the refresh logic by extracting it into a separate `refreshGallery` function.
- Added a refresh button with a tooltip to allow users to manually refresh the gallery items.
- Updated the useEffect to call the new refresh function when the modal opens, ensuring the gallery is always up-to-date.
2025-05-23 20:47:29 +07:00
bflatastic 2d78fd5a6f library always refreshed on open 2025-05-23 20:39:40 +07:00
BFlat 98e513e917 gallery dnd code refactor (#630)
- cleaner code + reusable image drop function for later 2d image drop
implementation
2025-05-23 09:21:43 +07:00
ArEnScandMichael Chung 97eb1c65ca Fix cors allow all urls for now, since there isn't really a way to ha… (#628)
…ck the app lol.

Co-authored-by: Michael Chung <michaelchung@mac.home>
2025-05-22 18:43:59 -04:00
bflatastic ba82a438dd image not dropping at correct position fix 2025-05-23 02:11:54 +07:00
bflatastic de7b990ec5 bug fix: select mode library modal not closing on X click 2025-05-23 01:35:50 +07:00
BFlat 7b90c59675 library modal signals bug fix (#627)
- fixed weird behavior with library modal not opening
- image drag and drop more accurate position (production drag and drop
still doesnt work - looking into it)
2025-05-23 01:31:49 +07:00
Brandon Thomas 11f1a5f41a sora aspect ratios (#626) 2025-05-22 00:09:59 -04:00
BFlat b92cd58f81 Enhance GalleryModal UX with Filters, Drag-and-Drop, Pagination, and UI Improvements (#625)
**✨ Features & Enhancements:**
- GalleryModal Filters: Replaced tab-based navigation with a more
scalable filter system.
- Image Fit Toggle: Allows toggling image fit display mode for better
previewing.
- Pagination & Infinite Scroll: Improved item loading performance using
soft refresh and infinite scroll logic.
- Drag-and-drop setup for gallery items
- Prevented dragging for video items
- Added support for image drop in PageEditor (3D)
- "My Library" Label Updates
2025-05-21 23:29:06 +07:00
Brandon Thomas 914c26b4c6 classify gateway timeout 2025-05-21 11:04:32 -04:00
Brandon Thomas fe8939a0f6 incomplete runwayml implementation (pausing for now) (#624) 2025-05-20 23:39:34 -04:00
Tanish Manku c809ff88fa Add save/load support for character poses (#623) 2025-05-20 20:13:04 -04:00
bflatastic 86675568a8 Update modal components for improved drag functionality and styling
- Increased the height of the drag handle in AssetModal and GalleryModal for better usability.
- Adjusted z-index properties for elements within AssetModal to ensure proper layering.
- Enhanced the modal's drag behavior to allow overflow beyond viewport edges, improving user experience when repositioning.
2025-05-21 02:32:20 +07:00
bflatastic a8927cc78d Refactor expand button in modal component for improved styling and functionality
- Updated the ExpandButton component to accept size props for better responsiveness.
- Replaced SVG icons with FontAwesome icons for a more consistent design.
- Adjusted the GalleryModal layout to include a gap between buttons for enhanced usability.
2025-05-21 02:17:17 +07:00
bflatastic 0e8dd19ecf Enhance modal functionality with draggable support and expand button
- Added draggable functionality to the modal, allowing users to reposition it.
- Introduced an expand button to toggle full-screen mode for the modal.
- Updated modal backdrop to support interaction options and improved styling.
- Adjusted AssetModal and GalleryModal components to utilize new modal features.
2025-05-21 02:06:51 +07:00
bflatastic b32a2e79b9 promptbox height bug fix 2025-05-20 22:47:38 +07:00
bflatastic a662c5809d lightbox videos fix 2025-05-20 22:31:27 +07:00
Michael Chung 7498720674 Fixing the gallery modal to show videos and images. 2025-05-20 11:14:36 -04:00
ArEnScandMichael Chung c8a4490b52 Feature/add to scene video 2 (#621)
Co-authored-by: Michael Chung <michaelchung@michaels-mbp-2.home>
2025-05-20 09:22:46 -04:00
Brandon Thomas c4e30e6dc7 swap out the background (#620) 2025-05-19 23:01:33 -04:00
ArEnScandMichael Chung 12070f14ad Feature/add to scene video 2 (#619)
Adding videos to scene via signal.

---------

Co-authored-by: Michael Chung <michaelchung@michaels-mbp-2.home>
2025-05-19 02:19:31 -04:00
BFlat 77a103de06 gallery videos tab (#617)
- 16/9 ratio grid items
- lightbox for videos will only show download button
2025-05-19 10:58:34 +07:00
BFlat 82f5805f24 image-to-video generation page with background gallery and UI components (#616) 2025-05-19 09:51:52 +07:00
f7c9ebfaa3 Feature/video addition (#615)
Co-authored-by: Michael Chung <michaelchung@Michaels-MacBook-Pro-2.local>
Co-authored-by: Michael Chung <michaelchung@michaels-mbp-2.home>
2025-05-18 20:38:12 -04:00
Brandon Thomas 76cd00cc13 add fal hunyuan image-to-3d (#614) 2025-05-18 15:37:55 -04:00
Brandon Thomas cb64f45b48 refactor artcraft crates to organize by service (module reorg) (#613) 2025-05-18 00:53:00 -04:00
Brandon Thomas 6751ab0b60 fal video integration (#612) 2025-05-17 19:47:40 -04:00
ArEnScandMichael Chung 9827a3efc5 Feature/add scene (#611)
Co-authored-by: Michael Chung <michaelchung@michaels-mbp-2.home>
2025-05-15 22:09:38 -04:00
Brandon Thomas 93b53d84cd remove some dead code + fix missing "dev" assets (#610) 2025-05-15 18:32:03 -04:00
Brandon Thomas a7794f6338 don't need to build for editor2d anymore 2025-05-15 17:20:56 -04:00
ArEnScandMichael Chung ef03e292c3 Add scene to 2d Lightbox modal. (#609)
Co-authored-by: Michael Chung <michaelchung@michaels-mbp-2.home>
2025-05-14 12:11:19 -04:00
BFlat 0e8c1fa3e7 Update landing2 mobile videos fix 2025-05-14 12:07:07 +07:00
BFlat af08834de7 artcraft landing 2 (#608) 2025-05-14 02:28:05 +07:00
Brandon Thomas e728806c04 more csp fixes 2025-05-13 14:18:29 -04:00
Brandon Thomas 3e605e7b18 add google analytics to CSP 2025-05-13 14:03:31 -04:00
Brandon Thomas d244524abc fal api integration in tauri + frontend controls + background removal (#607) 2025-05-13 13:12:49 -04:00
bflatastic 8e455e27a9 fixed: Artcraft login in onboarding shown when already logged into Artcraft 2025-05-13 11:55:44 +07:00
Brandon Thomas e0df1644a5 switch order of 2d/3d 2025-05-12 19:11:29 -04:00
Brandon Thomas 736d033ebf status alerts on 2d side 2025-05-12 18:54:42 -04:00
Brandon Thomas af3f0baa63 handle sora logged out state after app starts 2025-05-12 18:44:54 -04:00
Brandon Thomas a438dd13dc add Google Analytics GA4 2025-05-12 18:10:23 -04:00
Tanish Manku f7b76a7abe Add manual mouse support in Safari and AppleWebkit (#606) 2025-05-12 15:02:56 -07:00
Tanish Manku 9435af3e2a Change the relative pathing from base config (#605) 2025-05-12 14:23:09 -07:00
Tanish Manku 77efda1d66 Make 2D and 3D mount at the same time (#604) 2025-05-12 14:15:02 -07:00
Brandon Thomas fdc27b6ccd surface non-onboarding; do not retry non-onboarded requests 2025-05-12 17:00:25 -04:00
Brandon Thomas e3abd500db Explicit CSP on Mac instead of wildcards; this works on production Mac but may not fix Windows (#603) 2025-05-12 15:32:49 -04:00
Brandon Thomas ee4de4126d timeouts for uploads / remix (#602) 2025-05-12 12:26:41 -04:00
Brandon Thomas 4810ed30ae cache sora stats 2025-05-11 04:41:51 -04:00
Brandon Thomas 0b6593a063 fix preferences 2025-05-11 04:00:25 -04:00
Brandon Thomas b0e2dce140 fix event listeners for toasts; extra sounds (#601) 2025-05-11 03:41:14 -04:00
Brandon Thomas c4f401923b various sora / generate improvements (#600) 2025-05-11 01:02:00 -04:00
Brandon Thomas 24559a3554 username error 2025-05-09 19:00:28 -04:00
ArEnScandMichael Chung 5a26aed728 The bug was due to forggeting to bind this to the snapShotOfCurrentFr… (#599)
fix the generation problem

---------

Co-authored-by: Michael Chung <michaelchung@michaels-mbp-2.home>
2025-05-09 18:07:55 -04:00
Tanish Manku 95773c1c23 Point 3D tsconfig to the right subdirectory (#598) 2025-05-09 14:27:13 -07:00
Michael Chung 2d01073434 Remove tab selector 2025-05-09 13:56:00 -04:00
BFlat 1c62092d94 fix 3d resizing bug (#597) 2025-05-09 13:13:53 -04:00
bflatastic 5e22e17dfb popover width fix 2025-05-09 22:49:05 +07:00
bflatastic 611da775a9 bug fix: add image fix 2025-05-09 22:23:42 +07:00
bflatastic 6fc3f73579 artcraft block color update 2025-05-09 22:10:53 +07:00
BFlat 562cb99c51 2d editor fixes (#596)
- left toolbar now updates properly
- modals open properly
- styling fixes
- adjusted canvas center positioning to accommodate top header bar
2025-05-09 21:53:58 +07:00
bflatastic 67d280df84 remove old demo modal 2025-05-09 20:38:05 +07:00
8ccc8927a9 Feature/merge 2d 3d diverge (#593)
Co-authored-by: Michael Chung <michaelchung@michaels-mbp-2.home>
Co-authored-by: Tanish Manku <tanish2k09.dev@gmail.com>
2025-05-08 23:46:30 -04:00
Brandon Thomas a21e7331cc persist window position to disk and restore it 2025-05-08 22:54:58 -04:00
Brandon Thomas 0f0f8eb39c window size heuristic to keep dev tools from resizing window 2025-05-08 22:32:02 -04:00
Brandon Thomas b64ed411b1 artcraft account login/logout (#595) 2025-05-08 21:33:38 -04:00
ArEnScandMichael Chung a155b419e1 Fix 3d editor menu buttons hide the scene saving and loading. (#594)
Co-authored-by: Michael Chung <michaelchung@michaels-mbp-2.home>
2025-05-08 18:53:04 -04:00
Brandon Thomas e6177005df never block the prompt box 2025-05-08 17:59:32 -04:00
Brandon Thomas 1c78e17565 events for enqueue success / fail + more sounds and toasts (#592) 2025-05-08 17:43:12 -04:00
Brandon Thomas 0769bfad28 sora logout handler 2025-05-08 14:00:14 -04:00
BFlat 183946a943 Bflat/settings pane update (#591) 2025-05-08 17:40:54 +07:00
BFlat d43ee0f6c9 login modal and settings panel update (#590)
- login now flows automatically smoothly to the next step after login
- settings modal: misc/audio panes styling and toggle switch
- account settings disconnect sora account button

remaining TODO: 
- link logout sora endpoint
2025-05-08 14:21:01 +07:00
Brandon Thomas eec59c218d add login success event 2025-05-08 01:07:33 -04:00
Brandon Thomas 5c1e72f8f4 rename package 2025-05-07 23:59:44 -04:00
Brandon Thomas d91243b1f5 success and failure toasts; less discord info spam 2025-05-07 23:47:30 -04:00
Brandon Thomas 83cecad280 build script for mac 2025-05-07 23:13:23 -04:00
Brandon Thomas 06313f54a5 update settings panes (#588) 2025-05-07 22:52:47 -04:00
Brandon Thomas ef3ca88054 sound playing restored 2025-05-07 22:02:38 -04:00
Brandon Thomas cfcf7ab5aa refactor events: centrally located in rust for better discoverability 2025-05-07 21:15:13 -04:00
Brandon Thomas 4cc215495a slower polling 2025-05-07 19:11:19 -04:00
Brandon Thomas f1d14ab73f better scripts for unix development 2025-05-07 17:59:49 -04:00
Brandon Thomas 5cb8f5b93a cloudflare 524 2025-05-07 17:35:38 -04:00
Brandon Thomas 9decf8bf88 fix windows builds 2025-05-07 15:35:28 -04:00
Brandon Thomas 63a7f99c53 fix windows build issue 2025-05-07 14:55:48 -04:00
Brandon Thomas 9dd16f2e80 windows production build script 2025-05-07 14:42:40 -04:00
Brandon Thomas abe2d2a093 Windows scripts for running dev mode 2025-05-07 14:31:07 -04:00
bflatastic 552d5553c0 uncommented login modal and added temp next button 2025-05-07 23:15:59 +07:00
BFlat 0d33358ead upload flow update (#587)
- changed and moved the main upload asset button to the left sidebar
above the categories for better visibility
- added individual upload buttons to all the category pages except
skybox - they open the same upload modal but sepcific to its category
only.
- flow update: once an upload succeeds the upload modal closes itself
and automatically reopens the asset modal to the mine tab and previously
uploaded category (so users don't have to have a hard time finding or
navigating to it)
2025-05-07 16:18:45 +07:00
Brandon Thomas 908ff43be3 fix sora / chatgpt login, enhance login flow (#586) 2025-05-07 03:33:53 -04:00
Brandon Thomas 196e1c4615 fix broken package (#585) 2025-05-06 17:54:34 -04:00
bflatastic 8f321f06d0 thumnail to always load in img tag even if there's error 2025-05-06 22:30:27 +07:00
bflatastic 0b338f3886 login logic fixed 2025-05-06 14:26:49 +07:00
BFlat de76fc6c36 login modal on 3D (#584)
- login modal is a shared component that
- finished but needs checking session if openai/sora logged in or not
- replaced video for 3d (it had a black screen at the end)
2025-05-06 13:15:05 +07:00
bflatastic 9fb0ca2dab fixed logo being squished 2025-05-06 10:36:09 +07:00
Brandon Thomas 42965dfcfa modal settings menu (#583) 2025-05-05 23:06:32 -04:00
ArEnScandTanish Manku 8c7b358534 Feature/2d integration (#581)
Co-authored-by: Tanish Manku <-h>
2025-05-05 16:00:12 -04:00
ArEnScandMichael Chung d8851abf24 Removing lower panel and timeline files too much stuff, builds and wo… (#580)
…rks fine.

Co-authored-by: Michael Chung <michaelchung@michaels-mbp-2.home>
2025-05-05 15:06:28 -04:00
bflatastic 2c8254e50f updated artcraft site to show carter's thunderbolts video 2025-05-05 22:33:49 +07:00
bflatastic 15348f7b0e draw attention to add 3d object with bouncing tooltip 2025-05-05 22:08:16 +07:00
Brandon Thomas 6071dda4f9 Settings system backend (#579) 2025-05-04 16:02:54 -04:00
Brandon Thomas 1f6416856a rename tauri-artcraft to artcraft because it impacts exe name 2025-05-04 00:37:59 -04:00
Brandon Thomas 1370ab63d9 sora cloudflare 502s 2025-05-04 00:28:30 -04:00
Brandon Thomas 1e0f31ed8d move installation of tauri events (temporary) 2025-05-03 23:47:16 -04:00
Brandon Thomas fd4f284af6 set up packages to play sounds on events (more desktop feel) 2025-05-03 22:20:22 -04:00
Brandon Thomas 51a114a699 storyteller-web tauri cors 2025-05-02 23:27:12 -04:00
Brandon Thomas 75621ea85a emit task success / failure 2025-05-02 22:18:31 -04:00
Brandon Thomas e003e94e54 fix more cors issues 2025-05-02 20:49:17 -04:00
Brandon Thomas 0d1bd6b014 build script more friendly for windows 2025-05-02 19:29:14 -04:00
Brandon Thomas 9861263b08 remove objc/mac libs from tauri app 2025-05-02 19:05:23 -04:00
Brandon Thomas 9fa73c6e06 fix tauri conf - no more require-corp CORS 2025-05-02 19:02:31 -04:00
Brandon Thomas caada00cd9 remove cors require-corp from frontend 2025-05-02 18:59:41 -04:00
ArEnScandMichael Chung df8d999ed7 Feature/download click listen (#578)
Co-authored-by: Michael Chung <michaelchung@michaels-mbp-2.home>
2025-05-02 18:06:17 -04:00
Brandon Thomas 3f94e48f12 fix headers on mac 2025-05-02 17:31:37 -04:00
Brandon Thomas 68e57bd601 don't require objc - this won't work for cors anyway 2025-05-02 17:29:02 -04:00
Brandon Thomas e65011cd51 fix cors in dev and production mac builds 2025-05-02 12:22:33 -04:00
ArEnScandMichael Chung b2f989b0b7 Add icons for all platforms for the desktop app artcraft (#577)
Co-authored-by: Michael Chung <michaelchung@michaels-mbp-2.home>
2025-05-02 10:19:38 -04:00
Brandon Thomas 233d61d7a1 production build script 2025-05-02 09:21:50 -04:00
Brandon Thomas ab412c6f10 WIP unsafe hack to modify webkit 2025-05-02 07:41:36 -04:00
bflatastic 9d6b31200e top right buttons styling fixes and tooltip (profile dropdown/activity/settings) 2025-05-02 12:12:18 +07:00
bflatastic a1aacad7dd removed marquee error (unused) 2025-05-02 11:57:57 +07:00
Brandon Thomas 6436de9f44 unsafe CSP - will this help load images? 2025-05-01 23:31:36 -04:00
Brandon Thomas 116782e6ed enqueue sora gens from production app works 2025-05-01 23:31:36 -04:00
Michael Chung 431f2efcf0 Fix login and signup back button links 2025-05-01 23:30:05 -04:00
ArEnScandMichael Chung 7c64da88da Navigation Fixes (#576)
Added Navigation

---------

Co-authored-by: Michael Chung <michaelchung@michaels-mbp-2.home>
2025-05-01 22:52:46 -04:00
ArEnScandMichael Chung 93eb78da91 When the desktop app is running, the profile dropdown should not be w… (#575)
…hite.

Co-authored-by: Michael Chung <michaelchung@michaels-mbp-2.home>
2025-05-01 22:32:55 -04:00
Brandon Thomas f96e79ff49 use "@storyteller/api" for snapshots and prompting 2025-05-01 22:20:21 -04:00
Brandon Thomas 39e6f4511f use new media files client for importing objects in 3D 2025-05-01 21:41:31 -04:00
Brandon Thomas 4c0d062d76 production build + production origin host fix 2025-05-01 20:57:59 -04:00
Michael Chung 7da40d5177 Moved all the prompting specific code into a separate file lib/PromptsApi.ts 2025-05-01 19:27:49 -04:00
Brandon Thomas f06b5098e2 remove dead package from package lock 2025-05-01 18:52:29 -04:00
Tanish Manku eac503af46 Use shared lightbox component in 3D 2025-05-01 15:48:59 -07:00
Tanish Manku 16932374f5 Some project config improvements (nx + tsconfig) (#561) 2025-05-01 15:09:46 -07:00
ArEnScandMichael Chung 35940a4a63 Fix lightbox modal referrer policy (#574)
Co-authored-by: Michael Chung <michaelchung@michaels-mbp-2.home>
2025-05-01 18:03:33 -04:00
ArEnScandMichael Chung 55543b3735 Launch editor3d in the background and delete myapp (#573)
Co-authored-by: Michael Chung <michaelchung@michaels-mbp-2.home>
2025-05-01 17:52:31 -04:00
Brandon Thomas 3d44e6e29e "fix cors" 2025-05-01 17:44:39 -04:00
Brandon Thomas 3244b802fa cors headers for vite dev 2025-05-01 17:30:05 -04:00
Brandon Thomas 5e7a5d2cff fixing cors mixed with other refactoring 2025-05-01 17:18:39 -04:00
ArEnScandMichael Chung ecb73e4f80 Gallery fixes using thumbnail template. (#572)
Co-authored-by: Michael Chung <michaelchung@michaels-mbp-2.home>
2025-05-01 16:45:15 -04:00
ArEnScandMichael Chung 39092fa866 Fix image gallery data mapping (#571)
Co-authored-by: Michael Chung <michaelchung@michaels-mbp-2.home>
2025-05-01 16:36:16 -04:00
ArEnScandMichael Chung ca80275d28 Fix image gallery data mapping (#570)
Co-authored-by: Michael Chung <michaelchung@michaels-mbp-2.home>
2025-05-01 16:35:58 -04:00
Brandon Thomas 8c192b17f1 (messy) upload sora media files end-to-end 2025-05-01 16:30:44 -04:00
Brandon Thomas 40da6f6500 (messy) uploading to storyteller backend works, sans creds 2025-05-01 16:30:44 -04:00
ArEnScandMichael Chung 2a3982aa5a Feature/fix desktop 3d run (#569)
Co-authored-by: Michael Chung <michaelchung@michaels-mbp-2.home>
2025-05-01 15:43:12 -04:00
Brandon Thomas a1c2b4f5c8 revert script, add copy for michael 2025-05-01 15:17:32 -04:00
ArEnScandMichael Chung 213d3f7bd2 Feature/fix desktop 2d run (#568)
added a quick runner in 2d editor and 3d editor

---------

Co-authored-by: Michael Chung <michaelchung@michaels-mbp-2.home>
2025-05-01 15:11:23 -04:00
Brandon Thomas 0788e98b54 pass storyteller creds manager 2025-05-01 15:08:31 -04:00
Brandon Thomas 65c8ddfa91 sync creds now 2025-05-01 15:08:31 -04:00
ArEnScandMichael Chung a60e20c0b4 Added run run_desktop_3d (#567)
Co-authored-by: Michael Chung <michaelchung@michaels-mbp-2.home>
2025-05-01 14:16:49 -04:00
Brandon Thomas 54d417f4c5 use vendored tauri-plugin-http from tauri app 2025-05-01 14:02:05 -04:00
Brandon Thomas 98a74e3a96 Begin vendoring in tauri-plugin-http @ 144461bd (see notes)
From fork of plugins here:
https://github.com/tauri-apps/tauri-plugin-http

SHA: 144461bd068300f7436db25c6c7ad952dbefdb21

The original upstream is here:

https://github.com/tauri-apps/plugins-workspace
2025-05-01 13:50:05 -04:00
Michael Chung b537223ffa Fix issue with the 3d editor developer experience kill dev server 2025-05-01 13:47:03 -04:00
Brandon Thomas 8001f24195 fix request proxying 2025-05-01 13:35:04 -04:00
BFlat 778a4e72c8 posthog fix editor 3d? (#566) 2025-05-01 23:54:54 +07:00
bflatastic 083680232c editor2d posthog api key as env variable 2025-05-01 23:29:41 +07:00
Brandon Thomas b1b44ceb60 proxy requests through tauri to avoid 3rd party cookie ban (#565) 2025-05-01 04:04:06 -04:00
Brandon Thomas d988acbf6e document in code 2025-05-01 02:16:21 -04:00
Brandon Thomas 6e05b7a1b5 this seemingly avoids the startup race condition (see details)
There's an issue when the "main window thread" inquires about the
webview cookies shortly after app startup. When it attempts to dump the
cookies within a few milliseconds of app launch, it deadlocks and the
app never launches correctly. The entire webview goes blank and the app
freezes.

The timed waiting seems to fix this entirely.
2025-05-01 02:13:27 -04:00
Brandon Thomas 8a364605cf bug is still present, might be a race condition 2025-05-01 01:10:45 -04:00
Brandon Thomas 30a8e72efe comment out broken thread 2025-05-01 00:32:55 -04:00
Brandon Thomas ff1a83898b correct persistence behavior for window / storyteller cookies ? 2025-05-01 00:01:21 -04:00
Brandon Thomas f1b9299e46 memory store utilties to reuse 2025-04-30 23:43:24 -04:00
Brandon Thomas 2eefaaf7a1 storyteller cookie saving; temporarily broke window size persist 2025-04-30 22:31:20 -04:00
Brandon Thomas a21b4a4275 storyteller credentials store 2025-04-30 22:31:20 -04:00
ArEnScandMichael Chung e4c561eb41 Fixing imports and removing unused code and working on scene management. (#563)
Co-authored-by: Michael Chung <michaelchung@michaels-mbp-2.home>
2025-04-30 22:01:12 -04:00
Tanish Manku 420a23d359 Disable pointer lock controls if we detect safari webkit (#562) 2025-04-30 18:10:18 -07:00
Brandon Thomas 9cd3b493c6 command with info on platform 2025-04-30 20:13:12 -04:00
Tanish Manku bbd5953000 Use arrow keys to rotate cam (#560) 2025-04-30 16:41:08 -07:00
Brandon Thomas b346750968 intellij default project settings 2025-04-30 18:42:13 -04:00
Brandon Thomas e5749f0e77 storyteller api credentials WIP, but need to switch gears 2025-04-30 18:32:52 -04:00
bflatastic 826cf00cbb new videos for 2d and 3d 2025-04-30 16:52:55 +07:00
bflatastic 6b7d034068 added tauri2.conf.json 2025-04-30 15:39:18 +07:00
Brandon Thomas 7bd3f6f8c6 remove core-foundation for breaking windows 2025-04-30 03:42:32 -04:00
bflatastic 0c550fcb1a fixed empty snapshot data string 2025-04-30 14:11:41 +07:00
Brandon Thomas 3b2b7ede18 open sora login dialog on 3d 2025-04-30 03:10:29 -04:00
Brandon Thomas 782b68e9a2 move credentials dir 2025-04-30 02:58:57 -04:00
Brandon Thomas 5c23568646 refactor directory support 2025-04-30 02:41:51 -04:00
Brandon Thomas 43e781571f save window size between runs (super annoying to not have this) 2025-04-29 23:38:32 -04:00
Brandon Thomas 84361eb93e polling works 2025-04-29 21:59:00 -04:00
Brandon Thomas 38ab84d52e rename script 2025-04-29 20:07:06 -04:00
Brandon Thomas 82e87fa883 much better way to launch tauri dev (this was annoying to discover) 2025-04-29 20:04:56 -04:00
Brandon Thomas de5daa3f92 it's hard to build tauri in dev mode without it stepping on our feet 2025-04-29 19:37:19 -04:00
Brandon Thomas fc0fba7573 task draining / filtering 2025-04-29 17:34:49 -04:00
Brandon Thomas b199738ee0 auto-healing task polling, beginnings of a task polling thread 2025-04-29 16:29:08 -04:00
Tanish MankuandTanish Manku aa76113e8c Fix 3D performance decay after generation (#559)
Use 3JS size api instead of direct domElement access (avoids implicit
pixel density scaling)

Co-authored-by: Tanish Manku <-h>
2025-04-29 01:29:24 -07:00
Brandon Thomas bfe02a7880 dispatch to tauri or web on 3D 2025-04-29 00:29:36 -04:00
Brandon Thomas ac81de6a48 artcraft desktop: report discord status 2025-04-28 23:13:26 -04:00
Brandon Thomas 2c2a63e80b nit: fix metadata 2025-04-28 21:55:23 -04:00
Michael Chung 3521f73142 Fix ux issue with prompt box when enqueueing 2025-04-28 20:58:55 -04:00
ArEnScandMichael Chung 88fd732eec Ok fixed some minor issues. (#558)
Co-authored-by: Michael Chung <michaelchung@michaels-mbp-2.home>
2025-04-28 20:02:36 -04:00
Brandon Thomas 490915a3e7 artcraft website build configs 2025-04-28 18:24:36 -04:00
bflatastic 1802b0939e fix object highlight, camera speed, after delete character hide and toggle out of FK mode 2025-04-28 22:53:33 +07:00
bflatastic 36b6aa78f8 fix visible fps lag on higher refresh rate screens 2025-04-28 22:28:04 +07:00
bflatastic 499c07548c bug fix: undefined fetch on page load 2025-04-28 22:07:06 +07:00
Kasisnu 65580ec502 small tweaks to imagen callback 2025-04-28 20:15:30 +05:30
bflatastic 5d5b782760 only update camera when there's change 2025-04-28 21:36:35 +07:00
BFlat 09d0ae263f freecam camera smoothing (#556) 2025-04-28 15:39:59 +07:00
Kasisnu c3509d770f updated sqlx migrations 2025-04-28 13:11:38 +05:30
bflatastic ee1043f92c add button styling fix 2025-04-28 14:30:51 +07:00
ArEnScandMichael Chung e88b6ce39b Feature/UI sign in (#555)
Co-authored-by: Michael Chung <michaelchung@michaels-mbp-2.home>
2025-04-27 22:42:34 -04:00
Brandon Thomas 0e535e52ad update job state from endpoint 2025-04-27 02:41:00 -04:00
Brandon Thomas aa594b773e upload media files from gpt-image-1 2025-04-27 02:17:53 -04:00
Brandon Thomas ac209f8f4f builder for media file records 2025-04-27 00:19:54 -04:00
Brandon Thomas 66abfd18ba simple image medadata functions 2025-04-26 21:42:38 -04:00
Brandon Thomas 79cf730270 bundled mimetype / file extension detection 2025-04-26 20:44:31 -04:00
Brandon Thomas 698351f2a3 stub endpoint for updating gpt image job statuses 2025-04-26 03:20:45 -04:00
Brandon Thomas fc4eaff7f6 info -> debug logging 2025-04-25 04:30:00 -04:00
Brandon Thomas dadf14dbf4 accept reference images 2025-04-25 03:52:44 -04:00
Brandon Thomas ff695d7af6 more logging 2025-04-25 03:45:12 -04:00
Brandon Thomas a5e9bf2262 more logging 2025-04-25 02:39:23 -04:00
Brandon Thomas b49da80762 stop logging this in production 2025-04-25 02:19:24 -04:00
Brandon Thomas a0db62f0fd don't use this thing 2025-04-24 23:00:22 -04:00
Brandon Thomas ebc0f1ae42 auto-healing credentials in all pathways 2025-04-24 22:56:28 -04:00
Brandon Thomas dc5f5c5906 auto-renewing image gen 2025-04-24 20:20:20 -04:00
Brandon Thomas 98b7042192 much better session behavior on desktop app (large refactor) (#553) 2025-04-24 19:16:45 -04:00
bflatastic 76db001f59 updated button component to support href links 2025-04-24 23:11:16 +07:00
bflatastic 60637394d6 artcraft website: discord CTA and videos section from youtube 2025-04-24 23:02:27 +07:00
BFlatandTanish Manku f3b5a77475 working shared gallery component for both 2d and 3d (#551)
shared gallery component for 2d and 3d editor.
prompt box reference images are working too.

---------

Co-authored-by: Tanish Manku <-h>
2025-04-24 20:40:01 +07:00
Tanish MankuandTanish Manku d3e1d7fab9 Fix api lib (ApiManager) imports (#552)
Co-authored-by: Tanish Manku <-h>
2025-04-24 00:10:55 -07:00
bflatastic e34f9cad68 change favicon for all projects 2025-04-24 13:08:23 +07:00
bflatastic 37f29e2e48 artcraft website: responsive fixes 2025-04-24 13:00:26 +07:00
Brandon Thomas f2a2aa6e28 upgrade / refresh tokens 2025-04-23 12:08:18 -04:00
bflatastic 76a639a045 artcraft website favicon update 2025-04-23 22:08:40 +07:00
Brandon Thomas 4fd69c2439 refactor sora client packages so we can make a "recipes" auto-refreshing client 2025-04-23 10:41:45 -04:00
Brandon Thomas 64948e82a6 JWT claims from Sora parsed 2025-04-23 10:25:12 -04:00
Kasisnu 878763c987 ci-test: include macos runner for tauri builds 2025-04-23 14:11:43 +05:30
BFlat 959bdcd918 artcraft website (#550)
landing page and download for artcraft tauri app
2025-04-23 13:22:30 +07:00
Brandon Thomas a9967f0e76 resetting bearer token fails 2025-04-22 23:47:17 -04:00
Brandon Thomas cd680ac319 refactor 2025-04-22 23:29:17 -04:00
Brandon Thomas 3eebb7fec9 download and upload media files with sora remix requests 2025-04-22 20:43:14 -04:00
Brandon Thomas 63753c878a fix decode 2025-04-22 19:15:16 -04:00
Brandon Thomas 769ee07d69 Storyteller Rust API client 2025-04-22 18:55:30 -04:00
bflatastic 2fee3e12d5 editor3d: font fix 2025-04-22 22:40:51 +07:00
Kasisnu 5eb1e256e7 oai-client: basic method for getting a bearer token against a cookie 2025-04-22 20:39:43 +05:30
BFlat 46b687aca2 reusable demo modal + 3d demo video (#548)
- made the demo modal a shared component
2025-04-22 19:25:47 +07:00
Tanish MankuandTanish Manku df07e1f1e9 Hotfix rerendering spam - Outliner and Promptbox (#547)
Could be done better, but this works just as well under time
constraints.

For future reference: The freecam movement speed logic should be moved
to React land instead of processing the update every frame using the
time delta. Just use performance.now() in a useEffect or something.

---------

Co-authored-by: Tanish Manku <-h>
2025-04-22 01:26:49 -07:00
bflatastic bb78fb389f updated demo video 2025-04-22 12:46:00 +07:00
bflatastic 5015cd30a1 Merge branch 'main' of https://github.com/storytold/storyteller-rust 2025-04-22 11:02:45 +07:00
bflatastic 33699a16ef bug fix: WASD moving scene on promptbox focus + make prompt box highlighted on textarea focus 2025-04-22 11:02:42 +07:00
Brandon Thomas 9e54e9b864 another failure condition 2025-04-21 23:50:37 -04:00
bflatastic d11c30c914 bug fix: cannot type letter "b" in asset modal when open 2025-04-22 10:40:18 +07:00
Brandon Thomas fe9dfbb63a better credential behavior 2025-04-21 22:52:18 -04:00
Brandon Thomas aca784042e detect tauri vs browser (#546) 2025-04-21 19:19:41 -04:00
ArEnScandMichael Chung a2e14aaea3 PromptBox (#545)
Co-authored-by: Michael Chung <michaelchung@michaels-mbp-2.home>
2025-04-21 18:46:55 -04:00
Brandon Thomas ab97e73279 storyteller-web wasn't logging due to this ommission 2025-04-21 18:30:15 -04:00
Brandon Thomas 4313ccc980 storyteller-web cors for localhost 2d/3d 2025-04-21 18:18:50 -04:00
Tanish Manku 397172e036 Fix "forearm" filter due to "ear" (#544) 2025-04-21 15:14:37 -07:00
Tanish Manku d7566dd7ab Add a blacklist filter for the FK bones (#543) 2025-04-21 15:06:28 -07:00
ArEnScandMichael Chung acf5852acc PromptBox (#542)
Co-authored-by: Michael Chung <michaelchung@michaels-mbp-2.home>
2025-04-21 17:54:16 -04:00
Brandon Thomas d5e2a222b5 threadsafe credential holder, sora endpoints 2025-04-21 17:40:29 -04:00
ArEnScandMichael Chung 06ca3be4f5 Used Aspect Ratio to fix. (#541)
Prompt box handles both web and desktop.

Co-authored-by: Michael Chung <michaelchung@michaels-mbp-2.home>
2025-04-21 16:59:20 -04:00
Brandon Thomas a4e7a785d7 new sora tauri endpoints 2025-04-21 16:13:37 -04:00
Brandon Thomas dd8b03692a refactor sora module naming 2025-04-21 15:45:27 -04:00
bflatastic 638f453cb8 tsconfig and package lock update 2025-04-22 02:16:01 +07:00
bflatastic 5e5da8c95b added shared tooltip component + asset modal to use new shared components 2025-04-22 02:14:57 +07:00
bflatastic e39a7f0360 bug fix: asset modal flickers when items are drag and dropped too fast 2025-04-22 01:47:03 +07:00
bflatastic 5ea90154b1 bug fix: selecting object in scene crashes (Headless UI Transition component bug) 2025-04-22 01:29:51 +07:00
bflatastic f627da6d8f updated readme: ui component import 2025-04-22 01:19:30 +07:00
ArEnScandMichael Chung 682f11c79e Tauri and login for open ai (#540)
Co-authored-by: Michael Chung <michaelchung@michaels-mbp-2.home>
2025-04-21 14:15:14 -04:00
BFlat 0bdbb5214b settings modal (#539)
new shared components:
- button
- close button
- input
- label
- modal
- select
- settings modal
2025-04-22 01:00:58 +07:00
Brandon Thomas 94f2d2ec68 fix tauri build configs 2025-04-21 13:13:23 -04:00
Michael Chung 384b841528 Add a scale factor to the capture canvas
just use a hack to get it released
2025-04-21 12:55:02 -04:00
Michael Chung 62f97317ff Add component information into README 2025-04-21 09:23:30 -04:00
BFlat 8210a9f063 update headless ui version (#538) 2025-04-21 14:36:55 +07:00
BFlat b4d603098d working upload 3d asset modal (#537)
![image](https://github.com/user-attachments/assets/01df49cd-82a2-4f67-a02c-8adec34d1794)
2025-04-21 12:23:46 +07:00
Brandon Thomas ffd86f896c this configuration can launch the 2d app 2025-04-20 15:52:41 -04:00
Brandon Thomas 30b77afb23 fixup tauri scripts (wip) 2025-04-20 01:55:48 -04:00
Brandon Thomas 0d879af3a4 Refactor, clean up tauri builds 2025-04-20 01:24:25 -04:00
Brandon Thomas 4ac71a18c5 fix tauri build 2025-04-20 01:06:37 -04:00
Brandon Thomas 81e1fce6a0 cleanup and delete old scripts and configs (#536) 2025-04-20 00:52:42 -04:00
Brandon Thomas 855ddbdf2d Refactor editor3d pathing (#535) 2025-04-20 00:38:29 -04:00
Brandon Thomas 0a7d3028c9 ignore more vim temp files 2025-04-19 23:03:55 -04:00
Brandon Thomas c5aebaffb9 Ingore files from VSCode/Cursor 2025-04-19 23:01:20 -04:00
Brandon Thomasandbflatastic 931304887f Restore Bombay's toaster PR (#533)
Co-authored-by: bflatastic <bombayapirat@gmail.com>
2025-04-19 22:56:22 -04:00
bflatastic 3dcec8bc85 editor3d: login and sign up page styling fixes 2025-04-20 08:44:43 +07:00
Brandon Thomas af30eea6f7 start removing remix (#531) 2025-04-19 14:40:58 -04:00
bflatastic df7db6b35d editor2d: link to 3d editor 2025-04-19 20:07:33 +07:00
bflatastic d228a43baf editor3d: link to go to editor2d 2025-04-19 19:49:29 +07:00
bflatastic ebcc52dd1a margin fix login and signup pages 2025-04-19 15:59:45 +07:00
bflatastic 726206fd0c editor2d: login and sign up pages restyled 2025-04-19 15:58:07 +07:00
BFlat ac896fd93a editor2d demo video on open (#532)
- demo video modal opens at first load
2025-04-19 14:30:19 +07:00
Brandon Thomas 85a4ff5c55 Revert "shared toaster component (#528)" (#530)
This reverts commit e3f15b0d93.
2025-04-18 18:42:50 -04:00
BFlat e3f15b0d93 shared toaster component (#528) 2025-04-18 14:57:51 +07:00
4149 changed files with 165930 additions and 31179 deletions
+63
View File
@@ -0,0 +1,63 @@
name: 'publish'
on:
push:
branches:
- tauri-prod-release
# This workflow will trigger on each push to the `release` branch to create or update a GitHub release, build your app, and upload the artifacts to the release.
jobs:
publish-tauri:
permissions:
contents: write
strategy:
fail-fast: false
matrix:
include:
- platform: 'macos-latest' # for Arm based macs (M1 and above).
args: '--target aarch64-apple-darwin'
# - platform: 'macos-latest' # for Intel based macs.
# args: '--target x86_64-apple-darwin'
# - platform: 'ubuntu-22.04' # for Tauri v1 you could replace this with ubuntu-20.04.
# args: ''
# - platform: 'windows-latest'
# args: ''
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v4
- name: setup node
uses: actions/setup-node@v4
with:
node-version: lts/*
- name: install Rust stable
uses: dtolnay/rust-toolchain@stable
with:
# Those targets are only used on macos runners so it's in an `if` to slightly speed up windows and linux builds.
targets: ${{ matrix.platform == 'macos-latest' && 'aarch64-apple-darwin,x86_64-apple-darwin' || '' }}
- name: install dependencies (ubuntu only)
if: matrix.platform == 'ubuntu-22.04' # This must match the platform value defined above.
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.0-dev libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf
# webkitgtk 4.0 is for Tauri v1 - webkitgtk 4.1 is for Tauri v2.
# You can remove the one that doesn't apply to your app to speed up the workflow a bit.
- name: install frontend dependencies
run: cd ./crates/desktop/artcraft && yarn install # change this to npm, pnpm or bun depending on which one you use.
- uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
projectPath: ./crates/desktop/artcraft
tagName: app-v__VERSION__ # the action automatically replaces \_\_VERSION\_\_ with the app version.
releaseName: 'App v__VERSION__'
releaseBody: 'See the assets to download this version and install.'
releaseDraft: true
prerelease: false
args: ${{ matrix.args }}
+13
View File
@@ -0,0 +1,13 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<codeStyleSettings language="Rust">
<option name="RIGHT_MARGIN" value="180" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="ALIGN_MULTILINE_PARAMETERS_IN_CALLS" value="false" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
</code_scheme>
</component>
+5
View File
@@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>
@@ -0,0 +1,12 @@
{
"db_name": "MySQL",
"query": "\nINSERT INTO generic_inference_jobs\nSET\n token = ?,\n uuid_idempotency_token = ?,\n\n job_type = ?,\n\n maybe_external_third_party = ?,\n maybe_external_third_party_id = ?,\n\n product_category = ?,\n inference_category = ?,\n\n maybe_model_type = NULL,\n maybe_model_token = NULL,\n\n maybe_input_source_token = NULL,\n maybe_input_source_token_type = NULL,\n\n maybe_download_url = NULL,\n maybe_cover_image_media_file_token = NULL,\n\n maybe_raw_inference_text = NULL,\n\n maybe_inference_args = ?,\n\n maybe_creator_user_token = ?,\n maybe_creator_anonymous_visitor_token = ?,\n creator_ip_address = ?,\n creator_set_visibility = ?,\n\n priority_level = 0,\n is_keepalive_required = FALSE,\n max_duration_seconds = 0,\n\n is_debug_request = FALSE,\n maybe_routing_tag = NULL,\n\n status = ?\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 13
},
"nullable": []
},
"hash": "0fa824822cd94024dce21243f41e69e4a3e8685c4de676834a7c0ee14982c976"
}
@@ -0,0 +1,12 @@
{
"db_name": "MySQL",
"query": "\nUPDATE generic_inference_jobs\nSET\n status = \"complete_success\",\n on_success_result_entity_type = ?,\n on_success_result_entity_token = ?,\n failure_reason = NULL,\n internal_debugging_failure_reason = NULL,\n success_execution_millis = ?,\n success_inference_execution_millis = ?,\n retry_at = NULL,\n successfully_completed_at = NOW()\nWHERE token = ?\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 5
},
"nullable": []
},
"hash": "2bd7a5b886c9624ae48533ddac409cfca0668f30ab1f7016c412876b5904168b"
}
@@ -0,0 +1,113 @@
{
"db_name": "MySQL",
"query": "\nSELECT\n jobs.token as `job_token: tokens::tokens::generic_inference_jobs::InferenceJobToken`,\n\n jobs.status as `status: enums::common::job_status_plus::JobStatusPlus`,\n \n jobs.maybe_external_third_party as `external_third_party: enums::by_table::generic_inference_jobs::inference_job_external_third_party::InferenceJobExternalThirdParty`,\n jobs.maybe_external_third_party_id as `external_third_party_id`,\n\n jobs.maybe_creator_user_token as `maybe_creator_user_token: tokens::tokens::users::UserToken`,\n jobs.maybe_creator_anonymous_visitor_token as `maybe_creator_anonymous_visitor_token: tokens::tokens::anonymous_visitor_tracking::AnonymousVisitorTrackingToken`,\n jobs.creator_ip_address,\n\n jobs.created_at,\n jobs.updated_at\n\nFROM generic_inference_jobs as jobs\n\nWHERE jobs.maybe_external_third_party = ?\nAND jobs.maybe_external_third_party_id = ?\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "job_token: tokens::tokens::generic_inference_jobs::InferenceJobToken",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 1,
"name": "status: enums::common::job_status_plus::JobStatusPlus",
"type_info": {
"type": "String",
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | ENUM",
"char_set": 224,
"max_size": 76
}
},
{
"ordinal": 2,
"name": "external_third_party: enums::by_table::generic_inference_jobs::inference_job_external_third_party::InferenceJobExternalThirdParty",
"type_info": {
"type": "VarString",
"flags": "MULTIPLE_KEY | BINARY",
"char_set": 224,
"max_size": 64
}
},
{
"ordinal": 3,
"name": "external_third_party_id",
"type_info": {
"type": "VarString",
"flags": "MULTIPLE_KEY | BINARY",
"char_set": 224,
"max_size": 256
}
},
{
"ordinal": 4,
"name": "maybe_creator_user_token: tokens::tokens::users::UserToken",
"type_info": {
"type": "VarString",
"flags": "MULTIPLE_KEY | BINARY",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 5,
"name": "maybe_creator_anonymous_visitor_token: tokens::tokens::anonymous_visitor_tracking::AnonymousVisitorTrackingToken",
"type_info": {
"type": "VarString",
"flags": "MULTIPLE_KEY | BINARY",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 6,
"name": "creator_ip_address",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 160
}
},
{
"ordinal": 7,
"name": "created_at",
"type_info": {
"type": "Timestamp",
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | TIMESTAMP",
"char_set": 63,
"max_size": 19
}
},
{
"ordinal": 8,
"name": "updated_at",
"type_info": {
"type": "Timestamp",
"flags": "NOT_NULL | BINARY | TIMESTAMP | ON_UPDATE_NOW",
"char_set": 63,
"max_size": 19
}
}
],
"parameters": {
"Right": 2
},
"nullable": [
false,
false,
true,
true,
true,
true,
false,
false,
false
]
},
"hash": "64dfacc1f0552d539f009fea91e902a2fe296c06ad539808596bbf2c8fc9eaa0"
}
@@ -48,7 +48,7 @@
"name": "maybe_creator_anonymous_visitor_token: tokens::tokens::anonymous_visitor_tracking::AnonymousVisitorTrackingToken",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"flags": "MULTIPLE_KEY | BINARY",
"char_set": 224,
"max_size": 128
}
@@ -1,12 +1,12 @@
{
"db_name": "MySQL",
"query": "\n INSERT INTO media_files\n SET\n token = ?,\n\n media_class = ?,\n media_type = ?,\n\n is_user_upload = ?,\n is_intermediate_system_file = ?,\n\n origin_category = ?, \n origin_product_category = ?, \n maybe_origin_model_type = ?, \n maybe_origin_model_token = ?, \n maybe_origin_filename = ?,\n\n is_batch_generated = ?,\n maybe_batch_token = ?,\n\n maybe_mime_type = ?,\n file_size_bytes = ?,\n maybe_duration_millis = ?,\n maybe_audio_encoding = ?, \n maybe_video_encoding = ?, \n maybe_frame_width = ?, \n maybe_frame_height = ?,\n maybe_prompt_token = ?,\n checksum_sha2 = ?,\n\n maybe_title = ?,\n maybe_text_transcript = ?,\n\n maybe_scene_source_media_file_token = ?,\n\n public_bucket_directory_hash = ?, \n maybe_public_bucket_prefix = ?, \n maybe_public_bucket_extension = ?, \n\n maybe_creator_user_token = ?, \n maybe_creator_anonymous_visitor_token = ?, \n\n creator_ip_address = ?, \n creator_set_visibility = ?, \n\n maybe_creator_file_synthetic_id = ?, \n maybe_creator_category_synthetic_id = ?,\n\n extra_file_modification_info = ?,\n\n maybe_mod_user_token = ?, \n is_generated_on_prem = ?, \n generated_by_worker = ?, \n generated_by_cluster = ?\n ",
"query": "\n INSERT INTO media_files\n SET\n token = ?,\n\n media_class = ?,\n media_type = ?,\n\n is_user_upload = ?,\n is_intermediate_system_file = ?,\n\n origin_category = ?, \n origin_product_category = ?, \n maybe_origin_model_type = ?, \n maybe_origin_model_token = ?, \n maybe_origin_filename = ?,\n\n is_batch_generated = ?,\n maybe_batch_token = ?,\n\n maybe_mime_type = ?,\n file_size_bytes = ?,\n maybe_duration_millis = ?,\n maybe_audio_encoding = ?, \n maybe_video_encoding = ?, \n maybe_frame_width = ?, \n maybe_frame_height = ?,\n maybe_prompt_token = ?,\n checksum_sha2 = ?,\n \n maybe_engine_category = ?,\n\n maybe_title = ?,\n maybe_text_transcript = ?,\n\n maybe_scene_source_media_file_token = ?,\n\n public_bucket_directory_hash = ?, \n maybe_public_bucket_prefix = ?, \n maybe_public_bucket_extension = ?, \n\n maybe_creator_user_token = ?, \n maybe_creator_anonymous_visitor_token = ?, \n\n creator_ip_address = ?, \n creator_set_visibility = ?, \n\n maybe_creator_file_synthetic_id = ?, \n maybe_creator_category_synthetic_id = ?,\n\n extra_file_modification_info = ?,\n\n maybe_mod_user_token = ?, \n is_generated_on_prem = ?, \n generated_by_worker = ?, \n generated_by_cluster = ?\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 38
"Right": 39
},
"nullable": []
},
"hash": "c58f414b5e4d0f0420d1894e2f40311e5613919f49f3ac91f81f5fc2bef1bea8"
"hash": "b4470e607c005421dd8504b9f1d695080a581936ac6ce00b6f437b2764e741be"
}
@@ -0,0 +1,12 @@
{
"db_name": "MySQL",
"query": "\nUPDATE generic_inference_jobs\nSET\n status = ?,\n on_success_result_entity_type = ?,\n on_success_result_entity_token = ?,\n failure_reason = NULL,\n internal_debugging_failure_reason = NULL,\n success_execution_millis = NULL,\n success_inference_execution_millis = NULL,\n retry_at = NULL,\n successfully_completed_at = NOW()\nWHERE token = ?\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 4
},
"nullable": []
},
"hash": "f68a8917e639418a0bb952bef606c96299001e143c745ee30df99b72d1235d35"
}
+15
View File
@@ -0,0 +1,15 @@
{
"files.exclude": {
"**/*~": true,
".sqlx/**": true,
"_elasticsearch/**": true,
"_sql/**": true,
"frontend_old/**": true,
"includes/**": true,
"target/**": true,
"test_data/**": true,
"tmp/**": true,
"virtualenv/**": true,
"windows_dlls/**": true,
}
}
Generated
+1421 -2996
View File
File diff suppressed because it is too large Load Diff
+85 -34
View File
@@ -4,13 +4,6 @@ resolver = "2"
# This block defines the workspace members.
# When we add a library or binary crate, it needs an entry here.
members = [
# Types: common strongly-typed tokens, ids, payloads, etc.
"crates/_types/composite_identifiers",
"crates/_types/enums",
"crates/_types/enums_public",
"crates/_types/reusable_types", # TODO(bt, 2022-12-21): Deprecate
"crates/_types/tokens",
# CLI tools for operations, etc.
"crates/cli/devenv/dev-database-seed",
"crates/cli/devenv/dev-upload-media-file",
@@ -24,20 +17,25 @@ members = [
"crates/cli/production/migration-tool",
# Desktop apps
"crates/desktop/tauri-4o",
"crates/desktop/tauri-realtime",
"crates/desktop/artcraft",
# Shared libraries
"crates/lib/actix_cors_configs",
"crates/lib/actix_helpers",
"crates/lib/api_clients/cloud_storage",
"crates/lib/api_clients/fal_client",
"crates/lib/api_clients/google_drive_common",
"crates/lib/api_clients/google_sign_in",
"crates/lib/api_clients/openai_sora_client",
"crates/lib/api_clients/openart_client",
"crates/lib/api_clients/runwayml_client",
"crates/lib/api_clients/storyteller_client",
"crates/lib/api_clients/thumbnail_generator",
"crates/lib/bootstrap",
"crates/lib/bucket_paths",
"crates/lib/build_metadata",
"crates/lib/caching/memory_caching",
"crates/lib/caching/memory_store",
"crates/lib/caching/redis_caching",
"crates/lib/concurrency",
"crates/lib/cookies",
@@ -49,10 +47,10 @@ members = [
"crates/lib/deprecated/http_server_common", # TODO(bt, 2023-03-20): Move useful pieces to actix_helpers
"crates/lib/dimensions",
"crates/lib/easyenv", # NB: Vendored version of https://github.com/echelon/easyenv.rs that we'll improve.
"crates/lib/elasticsearch_schema",
"crates/lib/email_sender",
"crates/lib/errors",
"crates/lib/files/archives",
"crates/lib/files/file_to_base64_url",
"crates/lib/files/filesys",
"crates/lib/files/hashing",
"crates/lib/files/images",
@@ -62,16 +60,13 @@ members = [
"crates/lib/idempotency",
"crates/lib/image_algorithms",
"crates/lib/jobs_common",
"crates/lib/jwt_light",
"crates/lib/logging",
"crates/lib/machine_learning/ml_models",
"crates/lib/machine_learning/ml_weights_registry",
"crates/lib/machine_learning/prompt_engineering",
"crates/lib/markdown",
"crates/lib/migration",
"crates/lib/mysql_queries",
"crates/lib/password",
"crates/lib/redis_common",
"crates/lib/redis_schema",
"crates/lib/server_environment",
"crates/lib/shared_service_components",
"crates/lib/sqlx_mysql_helpers",
@@ -83,7 +78,22 @@ members = [
"crates/lib/user_input_common",
"crates/lib/web_scrapers",
#"crates/lib/api_clients/fakeyou_client",
#"crates/lib/sqlite_queries",
#"crates/lib/machine_learning/ml_models",
# Schema (database): queries, database layouts, Redis keys, etc.
"crates/schema/database/elasticsearch_schema",
"crates/schema/database/mysql_queries",
"crates/schema/database/redis_common",
"crates/schema/database/redis_schema",
#"crates/schema/database/sqlite_queries",
# Schema (public): common strongly-typed tokens, ids, payloads, etc.
"crates/schema/public/api/artcraft_api_defs",
"crates/schema/public/composite_identifiers",
"crates/schema/public/enums",
"crates/schema/public/enums_public",
"crates/schema/public/reusable_types", # TODO(bt, 2022-12-21): Deprecate
"crates/schema/public/tokens",
# Services: API servers, jobs, workers, etc.
"crates/service/job/analytics_job",
@@ -104,18 +114,23 @@ members = [
"crates/service/plugins/user_traits_component",
# Vendored code
"crates/vendor/candle/candle-core",
"crates/vendor/candle/candle-datasets",
"crates/vendor/candle/candle-examples",
"crates/vendor/candle/candle-flash-attn",
"crates/vendor/candle/candle-kernels",
"crates/vendor/candle/candle-metal-kernels",
"crates/vendor/candle/candle-nn",
"crates/vendor/candle/candle-onnx",
"crates/vendor/candle/candle-pyo3",
"crates/vendor/candle/candle-transformers",
"crates/vendor/candle/tensor-tools",
"crates/vendor/fal-rs",
"crates/vendor/fal-rs/fal-derive",
"crates/vendor/fal-rs/generate",
"crates/vendor/limitation",
"crates/vendor/tauri-plugin-http",
# NB(bt,2025-05-25): Too many failures on Mac. Disable for now.
#"crates/vendor/candle/candle-core",
#"crates/vendor/candle/candle-datasets",
#"crates/vendor/candle/candle-examples",
#"crates/vendor/candle/candle-flash-attn",
#"crates/vendor/candle/candle-kernels",
#"crates/vendor/candle/candle-metal-kernels",
#"crates/vendor/candle/candle-nn",
#"crates/vendor/candle/candle-onnx",
#"crates/vendor/candle/candle-pyo3",
#"crates/vendor/candle/candle-transformers",
#"crates/vendor/candle/tensor-tools",
# NB(bt,2023-12-12): Newrelic keeps breaking with upgrades. Kill for now.
#"crates/vendor/newrelic-telemetry-sdk-rust",
@@ -146,34 +161,70 @@ publish = false
# - tauri-runtime-wry
# - tauri-utils
#
# Broken on Windows:
# - core-foundation
# - core-foundation-sys
#
workspace-build-acceleration = { path = "crates/workspace-build-acceleration" }
# External libs
# Centrally pinned versions so that we can uniformly upgrade/downgrade versions across the workspace
# If a crate needs to use an older/newer version, the dependency should be managed in that crate's own Cargo.toml
anyhow = "1.0.97"
actix = "0.13.5"
actix-cors = "0.6.4" # TODO(bt): Carefully upgrade this. CORS broke last time.
actix-http = "3.7.0"
actix-multipart = "0.6.2"
actix-rt = "2.10.0"
actix-service = "2.0.3"
actix-utils = "3.0.1"
actix-web = "4.7.0" # TODO(bt): We're behind and need to bump versions.
actix-web-actors = "4.3.1+deprecated"
actix-web-lab = "0.20.2"
anyhow = "1.0.98"
base64 = "0.22.1"
chrono = { version = "0.4.40", features = ["serde"] }
bytes = "1.10.1"
chrono = { version = "0.4.41", features = ["serde"] }
cookie = "0.18.1"
futures = { version = "0.3.31" }
hex-literal = "1.0.0"
indexmap = "2.9.0"
log = "0.4.27"
once_cell = "1.21.3"
rand = "0.9.0"
rand = "0.9.1"
regex = "1.11.1"
reqwest = { version = "0.12.15", features = ["json", "cookies"] }
serde = { version = "1.0.219", features = ["derive"] }
serde_derive = "1.0.219"
serde_json = "1.0.140"
serde_yaml = "0.9.1"
serde_yaml = "0.9.34+deprecated"
sha3 = "0.10.8"
thiserror = "2"
toml = "0.7.4"
url = "2.5.4"
tauri = { version = "2.4.1", features = ["unstable", "devtools"] } # NB: "devtools" prevents App Store distribution
tempdir = "0.3.7"
tempfile = "3.20.0"
thiserror = "2.0.12"
tokio = { version = "1.45.1", features = ["macros"] }
toml = "0.8.22"
url = { version = "2.5.4", features = ["serde"] }
# Internal libs
artcraft_api_defs = { path = "crates/schema/public/api/artcraft_api_defs" }
build_metadata = { path = "crates/lib/build_metadata" }
crockford = { path = "crates/lib/data/crockford" }
enums = { path = "crates/schema/public/enums" }
enums_public = { path = "crates/schema/public/enums_public" }
errors = { path = "crates/lib/errors" }
fal_client = { path = "crates/lib/api_clients/fal_client" }
file_to_base64_url = { path = "crates/lib/files/file_to_base64_url" }
filesys = { path = "crates/lib/files/filesys" }
idempotency = { path = "crates/lib/idempotency" }
images = { path = "crates/lib/files/images" }
jwt_light = { path = "crates/lib/jwt_light" }
memory_caching = { path = "crates/lib/caching/memory_caching" }
shared_service_components = { path = "crates/lib/shared_service_components" }
memory_store = { path = "crates/lib/caching/memory_store" }
mimetypes = { path = "crates/lib/files/mimetypes" }
openai_sora_client = { path = "crates/lib/api_clients/openai_sora_client" }
primitives = { path = "crates/lib/data/primitives" }
shared_service_components = { path = "crates/lib/shared_service_components" }
storyteller_client = { path = "crates/lib/api_clients/storyteller_client" }
subprocess_common = { path = "crates/lib/subprocess_common" }
tokens = { path = "crates/schema/public/tokens" }
@@ -0,0 +1,6 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
ALTER TABLE generic_inference_jobs DROP COLUMN maybe_external_third_party_id;
ALTER TABLE generic_inference_jobs DROP COLUMN maybe_external_third_party;
@@ -0,0 +1,9 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
ALTER TABLE generic_inference_jobs
ADD COLUMN maybe_external_third_party VARCHAR(16) DEFAULT NULL;
ALTER TABLE generic_inference_jobs
ADD COLUMN maybe_external_third_party_id VARCHAR(64) DEFAULT NULL;
@@ -0,0 +1,9 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
DROP INDEX `index_maybe_external_third_party_id`
ON `generic_inference_jobs`;
DROP INDEX `index_maybe_external_third_party_and_id`
ON `generic_inference_jobs`;
@@ -0,0 +1,11 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
ALTER TABLE generic_inference_jobs
ADD UNIQUE INDEX index_maybe_external_third_party_and_id (maybe_external_third_party, maybe_external_third_party_id),
ALGORITHM=INPLACE, LOCK=NONE;
ALTER TABLE generic_inference_jobs
ADD INDEX index_maybe_external_third_party_id (maybe_external_third_party_id),
ALGORITHM=INPLACE, LOCK=NONE;
@@ -39,8 +39,20 @@ CREATE TABLE generic_inference_jobs (
-- Examples (may not be up to date):
-- * text_to_speech
-- * voice_conversion
-- * image_generation
-- * video_generation
-- * background_removal
inference_category VARCHAR(32) NOT NULL,
-- If the job is externally enqueued, this is the third-party service
-- responsible for the job. Typically, we won't run an inference job for
-- jobs being run on a third party.
maybe_external_third_party VARCHAR(16) DEFAULT NULL,
-- If the job is externally enqueued, this is the ID the third-party
-- service uses.
maybe_external_third_party_id VARCHAR(64) DEFAULT NULL,
-- There is an index on this column.
-- NB: See notes on inference_category. This is becoming a problematic field. We're using
-- this to load the container spin-up arguments and dependencies, but the former is being
@@ -287,11 +299,13 @@ CREATE TABLE generic_inference_jobs (
PRIMARY KEY (id),
UNIQUE KEY (token),
UNIQUE KEY (uuid_idempotency_token),
UNIQUE KEY (maybe_external_third_party, maybe_external_third_party_id),
KEY index_job_type (job_type),
KEY index_product_category (product_category),
KEY index_inference_category (inference_category),
KEY index_maybe_model_type_and_maybe_model_token (maybe_model_type, maybe_model_token),
KEY index_maybe_model_type (maybe_model_type),
KEY index_maybe_external_third_party_id (maybe_external_third_party_id),
KEY fk_maybe_model_token (maybe_model_token),
KEY fk_maybe_input_source_token (maybe_input_source_token),
KEY fk_maybe_input_source_token_and_type (maybe_input_source_token, maybe_input_source_token_type),
@@ -16,23 +16,23 @@ path = "src/main.rs"
normal = ["workspace-build-acceleration"]
[dependencies]
# Workspace hack (faster compile times)
workspace-build-acceleration = { workspace = true }
# Internal
bucket_paths = { path = "../../../lib/bucket_paths" }
cloud_storage = { path = "../../../lib/api_clients/cloud_storage" }
config = { path = "../../../lib/deprecated/config" }
easyenv = { path = "../../../lib/easyenv" }
enums = { path = "../../../_types/enums" }
enums = { path = "../../../schema/public/enums" }
errors = { path = "../../../lib/errors" }
filesys = { path = "../../../lib/files/filesys" }
hashing = { path = "../../../lib/files/hashing" }
idempotency = { path = "../../../lib/idempotency" }
mimetypes = { path = "../../../lib/files/mimetypes" }
mysql_queries = { path = "../../../lib/mysql_queries" }
mysql_queries = { path = "../../../schema/database/mysql_queries" }
storyteller_root = { path = "../../../lib/storyteller_root" }
tokens = { path = "../../../_types/tokens" }
# Workspace hack (faster compile times)
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
tokens = { path = "../../../schema/public/tokens" }
# External
log = "0.4.14"
@@ -16,20 +16,20 @@ path = "src/main.rs"
normal = ["workspace-build-acceleration"]
[dependencies]
# Workspace hack (faster compile times)
workspace-build-acceleration = { workspace = true }
# Internal
bucket_paths = { path = "../../../lib/bucket_paths" }
cloud_storage = { path = "../../../lib/api_clients/cloud_storage" }
config = { path = "../../../lib/deprecated/config" }
easyenv = { path = "../../../lib/easyenv" }
enums = { path = "../../../_types/enums" }
enums = { path = "../../../schema/public/enums" }
errors = { path = "../../../lib/errors" }
filesys = { path = "../../../lib/files/filesys" }
mimetypes = { path = "../../../lib/files/mimetypes" }
mysql_queries = { path = "../../../lib/mysql_queries" }
tokens = { path = "../../../_types/tokens" }
# Workspace hack (faster compile times)
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
mysql_queries = { path = "../../../schema/database/mysql_queries" }
tokens = { path = "../../../schema/public/tokens" }
# External
clap = "4.4.8"
+2 -3
View File
@@ -16,14 +16,13 @@ path = "src/main.rs"
normal = ["workspace-build-acceleration"]
[dependencies]
# Workspace hack (faster compile times)
workspace-build-acceleration = { workspace = true }
# Internal
errors = { path = "../../../lib/errors" }
web_scrapers = { path = "../../../lib/web_scrapers" }
# Workspace hack (faster compile times)
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
# External
clap = "4.4.8"
tokio = { version = "1.38.0", features = ["macros"] }
+4 -4
View File
@@ -17,15 +17,15 @@ normal = ["workspace-build-acceleration"]
[dependencies]
# Workspace hack (faster compile times)
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
workspace-build-acceleration = { workspace = true }
# Internal
datetimes = { path = "../../../lib/data/datetimes" }
easyenv = { path = "../../../lib/easyenv" }
enums = { path = "../../../_types/enums" }
enums = { path = "../../../schema/public/enums" }
errors = { path = "../../../lib/errors" }
mysql_queries = { path = "../../../lib/mysql_queries" }
tokens = { path = "../../../_types/tokens" }
mysql_queries = { path = "../../../schema/database/mysql_queries" }
tokens = { path = "../../../schema/public/tokens" }
# External
anyhow = "1.0.86"
+3 -7
View File
@@ -16,20 +16,16 @@ path = "src/main.rs"
normal = ["workspace-build-acceleration"]
[dependencies]
# Workspace hack (faster compile times)
workspace-build-acceleration = { workspace = true }
# Internal
easyenv = { path = "../../../lib/easyenv" }
errors = { path = "../../../lib/errors" }
# Workspace hack (faster compile times)
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
# External
anyhow = "1.0.86"
# TODO/NB: Commenting out clap4 as it prevents windows builds
# NB: clap4 = { package = "clap", version = "4.0" }
dotenv = "0.15.0"
log = "0.4.14"
# Serialization
serde = "1.0.125"
serde_derive = "1.0.125"
+6 -6
View File
@@ -16,17 +16,17 @@ path = "src/main.rs"
normal = ["workspace-build-acceleration"]
[dependencies]
# Workspace hack (faster compile times)
workspace-build-acceleration = { workspace = true }
# Internal
bucket_paths = { path = "../../../lib/bucket_paths" }
easyenv = { path = "../../../lib/easyenv" }
enums = { path = "../../../_types/enums" }
enums = { path = "../../../schema/public/enums" }
errors = { path = "../../../lib/errors" }
mysql_queries = { path = "../../../lib/mysql_queries" }
mysql_queries = { path = "../../../schema/database/mysql_queries" }
storyteller_root = { path = "../../../lib/storyteller_root" }
tokens = { path = "../../../_types/tokens" }
# Workspace hack (faster compile times)
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
tokens = { path = "../../../schema/public/tokens" }
# External
clap = "4.4.8"
@@ -16,20 +16,20 @@ path = "src/main.rs"
normal = ["workspace-build-acceleration"]
[dependencies]
# Workspace hack (faster compile times)
workspace-build-acceleration = { workspace = true }
# Internal
bucket_paths = { path = "../../../lib/bucket_paths" }
config = { path = "../../../lib/deprecated/config" }
easyenv = { path = "../../../lib/easyenv" }
elasticsearch_schema = { path = "../../../lib/elasticsearch_schema" }
enums = { path = "../../../_types/enums" }
elasticsearch_schema = { path = "../../../schema/database/elasticsearch_schema" }
enums = { path = "../../../schema/public/enums" }
errors = { path = "../../../lib/errors" }
mysql_queries = { path = "../../../lib/mysql_queries" }
mysql_queries = { path = "../../../schema/database/mysql_queries" }
primitives = { path = "../../../lib/data/primitives" }
storyteller_root = { path = "../../../lib/storyteller_root" }
tokens = { path = "../../../_types/tokens" }
# Workspace hack (faster compile times)
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
tokens = { path = "../../../schema/public/tokens" }
# External
clap = "4.4.8"
@@ -16,14 +16,14 @@ path = "src/main.rs"
normal = ["workspace-build-acceleration"]
[dependencies]
# Workspace hack (faster compile yytimes)
workspace-build-acceleration = { workspace = true }
# Internal
config = { path = "../../../lib/deprecated/config" }
easyenv = { path = "../../../lib/easyenv" }
errors = { path = "../../../lib/errors" }
# Workspace hack (faster compile yytimes)
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
# External
log = "0.4.20"
once_cell = "1.18.0"
@@ -16,13 +16,13 @@ path = "src/main.rs"
normal = ["workspace-build-acceleration"]
[dependencies]
# Workspace hack (faster compile times)
workspace-build-acceleration = { workspace = true }
# Internal
errors = { path = "../../../lib/errors" }
logging = { path = "../../../lib/logging" }
# Workspace hack (faster compile times)
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
# External
clap = { version = "4.4.8", features = ["derive"] }
walkdir = "2.4.0"
@@ -16,21 +16,21 @@ path = "src/main.rs"
normal = ["workspace-build-acceleration"]
[dependencies]
# Workspace hack (faster compile times)
workspace-build-acceleration = { workspace = true }
# Internal
bucket_paths = { path = "../../../lib/bucket_paths" }
cloud_storage = { path = "../../../lib/api_clients/cloud_storage" }
config = { path = "../../../lib/deprecated/config" }
easyenv = { path = "../../../lib/easyenv" }
enums = { path = "../../../_types/enums" }
enums = { path = "../../../schema/public/enums" }
errors = { path = "../../../lib/errors" }
filesys = { path = "../../../lib/files/filesys" }
hashing = { path = "../../../lib/files/hashing" }
mysql_queries = { path = "../../../lib/mysql_queries" }
mysql_queries = { path = "../../../schema/database/mysql_queries" }
storyteller_root = { path = "../../../lib/storyteller_root" }
tokens = { path = "../../../_types/tokens" }
# Workspace hack (faster compile times)
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
tokens = { path = "../../../schema/public/tokens" }
# External
clap = "4.4.8"
@@ -12,7 +12,7 @@ publish = false
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
name = "app_lib"
name = "artcraft_app_lib"
crate-type = ["staticlib", "cdylib", "rlib"]
[build-dependencies]
@@ -23,45 +23,55 @@ tauri-build = { version = "2.1.1", features = [] }
workspace-build-acceleration = { workspace = true }
# Internal
crockford = { workspace = true }
artcraft_api_defs = { workspace = true }
build_metadata = { workspace = true }
errors = { workspace = true }
fal_client = { workspace = true }
filesys = { workspace = true }
memory_caching = { workspace = true }
idempotency = { workspace = true }
memory_store = { workspace = true }
mimetypes = { workspace = true }
openai_sora_client = { workspace = true }
primitives = { workspace = true }
subprocess_common = { workspace = true }
storyteller_client = { workspace = true }
tokens = { workspace = true }
# External
#openssl = { version = "0.10", features = ["vendored"] }
# NB(bt,2025-03-10): default-features = false on Windows while I debug openssl / rustls
anyhow = { workspace = true }
base64 = "0.22.1"
bytes = "1.10"
base64 = { workspace = true }
bytes = "1.10.1"
chrono = { workspace = true }
const_format = "0.2.34"
directories = "6.0.0"
dirs = "6.0.0"
futures = "0.3"
image = "0.25.5"
indexmap = { workspace = true }
log = { workspace = true }
once_cell = { workspace = true }
rand = { workspace = true }
reqwest = { workspace = true, features = ["multipart", "stream"], default-features = false }
reqwest = { workspace = true, features = ["multipart", "stream"], default-features = false } # NB(bt,2025-03-10): default-features = false on Windows while I debug openssl / rustls
serde = { workspace = true }
serde_derive = { workspace = true }
serde_json = { workspace = true }
serde_yaml = { workspace = true }
tauri = { version = "2.4.1", features = ["unstable"] }
tauri = { workspace = true }
tauri-plugin-log = "2.3.1"
tempdir = "0.3.7"
tempfile = "3.18.0"
tauri-plugin-upload = "2.2.1"
tempdir = { workspace = true }
tempfile = { workspace = true }
tokio = { version = "1.42", features = ["rt", "rt-multi-thread", "fs"] }
tokio-util = { version = "0.7", features = ["codec"] }
url = { workspace = true }
# NB: We need to vendor this in so that we can access the cookies inside via the private API
tauri-plugin-http = { path = "../../vendor/tauri-plugin-http" }
# NB: The version of the `discord-rich-presence` crate (0.2.5) last published has non-Send/Sync error
# types and can't do threading. We need to wait for a new version to unpin from Git.
discord-rich-presence = { git = "https://github.com/vionya/discord-rich-presence" }
tauri-plugin-dialog = "2"
[dev-dependencies]
libloading = "0.8.6"
serial_test = "3.2.0"
assertor = "0.0.3"
[profile.dev]
incremental = true # Compile your binary in smaller steps.
@@ -0,0 +1,24 @@
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default",
"description": "enables the default permissions",
"windows": [
"main"
],
"permissions": [
"core:default",
"log:default",
"upload:allow-download",
"upload:default",
"http:allow-fetch",
{
"identifier": "http:default",
"allow": [
{
"url": "https://*"
}
]
},
"dialog:default"
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1023 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

@@ -0,0 +1,70 @@
use crate::core::state::app_preferences::app_preferences_manager::AppPreferencesManager;
use crate::core::state::app_preferences::preferred_download_directory::PreferredDownloadDirectory;
use errors::AnyhowResult;
use log::{error, info};
use serde_derive::Serialize;
use tauri::{AppHandle, State};
#[derive(Serialize)]
pub struct GetAppPreferencesResponse {
pub preferences: AppPreferencesPayload,
}
#[derive(Serialize)]
pub struct AppPreferencesPayload {
/// The downloads directory to use when a user downloads a file.
pub preferred_download_directory: PreferredDownloadDirectory,
/// Play sounds on events.
pub play_sounds: bool,
/// Key pointing to file; defined in the frontend code.
/// Defined for enqueue since image enqueue can be async
pub enqueue_success_sound: Option<String>,
/// Key pointing to file; defined in the frontend code.
/// Defined for enqueue since image enqueue can be async
pub enqueue_failure_sound: Option<String>,
/// Key pointing to file; defined in the frontend code.
pub generation_success_sound: Option<String>,
/// Key pointing to file; defined in the frontend code.
pub generation_failure_sound: Option<String>,
/// Key pointing to file; defined in the frontend code.
#[deprecated]
pub generation_enqueue_sound: Option<String>,
}
#[tauri::command]
pub async fn get_app_preferences_command(
app_prefs: State<'_, AppPreferencesManager>,
) -> Result<GetAppPreferencesResponse, String> {
info!("get_app_preferences_command called");
let result = get_prefs(&app_prefs)
.await
.map_err(|err| {
error!("Error getting app preferences: {:?}", err);
format!("Error getting app preferences: {:?}", err)
})?;
Ok(GetAppPreferencesResponse {
preferences: result,
})
}
async fn get_prefs(app_prefs: &AppPreferencesManager) -> AnyhowResult<AppPreferencesPayload> {
let prefs = app_prefs.get_clone()?;
Ok(AppPreferencesPayload {
preferred_download_directory: prefs.preferred_download_directory,
play_sounds: prefs.play_sounds,
enqueue_success_sound: prefs.enqueue_success_sound,
enqueue_failure_sound: prefs.enqueue_failure_sound,
generation_success_sound: prefs.generation_success_sound,
generation_failure_sound: prefs.generation_failure_sound,
generation_enqueue_sound: prefs.generation_enqueue_sound,
})
}
@@ -0,0 +1,2 @@
pub mod get_app_preferences_command;
pub mod update_app_preference_command;
@@ -0,0 +1,122 @@
use crate::core::state::app_preferences::app_preferences_manager::AppPreferencesManager;
use crate::core::state::app_preferences::preferred_download_directory::PreferredDownloadDirectory;
use crate::core::state::data_dir::app_data_root::AppDataRoot;
use anyhow::anyhow;
use errors::AnyhowResult;
use log::{error, info};
use openai_sora_client::sora_error::SoraError::AnyhowError;
use serde_derive::{Deserialize, Serialize};
use tauri::{AppHandle, State};
/// For now, we'll only update a single preference at a time.
#[derive(Deserialize)]
pub struct UpdateAppPreferencesRequest {
pub preference: PreferenceName,
/// We'll decode this with respect to the preference value.
pub value: Option<ValueType>,
}
#[derive(Deserialize, Debug)]
#[serde(untagged)]
pub enum ValueType {
Bool(bool),
String(String),
DownloadDirectory(PreferredDownloadDirectory),
}
#[derive(Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum PreferenceName {
PreferredDownloadDirectory,
PlaySounds,
EnqueueSuccessSound,
EnqueueFailureSound,
GenerationSuccessSound,
GenerationFailureSound,
}
#[derive(Serialize)]
pub struct UpdateAppPreferencesResponse {
pub success: bool,
}
#[tauri::command]
pub async fn update_app_preferences_command(
request: UpdateAppPreferencesRequest,
app_prefs: State<'_, AppPreferencesManager>,
app_data_root: State<'_, AppDataRoot>,
) -> Result<UpdateAppPreferencesResponse, String> {
info!("update_app_preferences_command called");
update_prefs(request, &app_prefs, &app_data_root)
.await
.map_err(|err| {
error!("Error getting app preferences: {:?}", err);
format!("Error getting app preferences: {:?}", err)
})?;
Ok(UpdateAppPreferencesResponse {
success: true,
})
}
async fn update_prefs(
request: UpdateAppPreferencesRequest,
app_prefs: &AppPreferencesManager,
app_data_root: &AppDataRoot,
) -> AnyhowResult<()> {
let mut prefs = app_prefs.get_clone()?;
info!("Value is: {:?}", request.value);
match request.preference {
PreferenceName::PreferredDownloadDirectory => {
match request.value {
Some(ValueType::DownloadDirectory(dir)) =>
prefs.preferred_download_directory = dir,
_ =>
return Err(anyhow!("Invalid value: {:?}", request.value)),
}
}
PreferenceName::PlaySounds => {
match request.value {
Some(ValueType::Bool(val)) =>
prefs.play_sounds = val,
_ =>
return Err(anyhow!("Invalid value: {:?}", request.value)),
}
}
PreferenceName::EnqueueSuccessSound => {
prefs.enqueue_success_sound = request.value
.map(|val| string_value(&val))
.transpose()?;
}
PreferenceName::EnqueueFailureSound => {
prefs.enqueue_failure_sound = request.value
.map(|val| string_value(&val))
.transpose()?;
}
PreferenceName::GenerationSuccessSound => {
prefs.generation_success_sound = request.value
.map(|val| string_value(&val))
.transpose()?;
}
PreferenceName::GenerationFailureSound => {
prefs.generation_failure_sound = request.value
.map(|val| string_value(&val))
.transpose()?;
}
}
app_prefs.set_clone(&prefs)?;
app_data_root.settings_dir().write_app_preferences(&prefs)?;
Ok(())
}
fn string_value(value: &ValueType) -> AnyhowResult<String> {
match value {
ValueType::String(val) => Ok(val.to_string()),
_ => Err(anyhow!("Invalid value type: {:?}", value)),
}
}
@@ -0,0 +1,184 @@
use crate::core::commands::enqueue::image::handle_fal::handle_fal;
use crate::core::commands::enqueue::image::handle_sora::handle_sora;
use crate::core::commands::enqueue::image::internal_image_error::InternalImageError;
use crate::core::commands::response::failure_response_wrapper::{CommandErrorResponseWrapper, CommandErrorStatus};
use crate::core::commands::response::shorthand::Response;
use crate::core::commands::response::success_response_wrapper::SerializeMarker;
use crate::core::events::sendable_event_trait::SendableEvent;
use crate::core::state::data_dir::app_data_root::AppDataRoot;
use crate::core::state::data_dir::trait_data_subdir::DataSubdir;
use crate::core::utils::download_media_file_to_temp_dir::download_media_file_to_temp_dir;
use crate::core::utils::get_url_file_extension::get_url_file_extension;
use crate::core::utils::save_base64_image_to_temp_dir::save_base64_image_to_temp_dir;
use crate::core::utils::simple_http_download::simple_http_download;
use crate::core::utils::simple_http_download_to_tempfile::simple_http_download_to_tempfile;
use crate::services::fal::state::fal_credential_manager::FalCredentialManager;
use crate::services::fal::state::fal_task_queue::FalTaskQueue;
use crate::services::sora::state::read_sora_credentials_from_disk::read_sora_credentials_from_disk;
use crate::services::sora::state::sora_credential_holder::SoraCredentialHolder;
use crate::services::sora::state::sora_credential_manager::SoraCredentialManager;
use crate::services::sora::state::sora_task_queue::SoraTaskQueue;
use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager;
use anyhow::anyhow;
use base64::prelude::BASE64_STANDARD;
use base64::{DecodeError, Engine};
use errors::{AnyhowError, AnyhowResult};
use fal_client::error::fal_error_plus::FalErrorPlus;
use fal_client::requests::queue::image_gen::enqueue_flux_pro_ultra_text_to_image::{enqueue_flux_pro_ultra_text_to_image, FluxProUltraTextToImageArgs};
use fal_client::requests::queue::image_gen::enqueue_recraft3_text_to_image::{enqueue_recraft3_text_to_image, Recraft3TextToImageArgs};
use filesys::file_read_bytes::file_read_bytes;
use image::codecs::png::{CompressionType, FilterType, PngEncoder};
use image::{DynamicImage, EncodableLayout, ImageReader};
use log::{debug, error, info, warn};
use mimetypes::mimetype_info::mimetype_info::MimetypeInfo;
use openai_sora_client::credentials::SoraCredentials;
use openai_sora_client::creds::credential_migration::CredentialMigrationRef;
use openai_sora_client::recipes::image_remix_with_session_auto_renew::{image_remix_with_session_auto_renew, ImageRemixAutoRenewRequest};
use openai_sora_client::recipes::image_upload_from_file_with_session_auto_renew::{image_upload_from_file_with_session_auto_renew, ImageUploadFromFileAutoRenewRequest};
use openai_sora_client::recipes::maybe_upgrade_or_renew_session::maybe_upgrade_or_renew_session;
use openai_sora_client::requests::image_gen::common::{ImageSize, NumImages};
use openai_sora_client::requests::image_gen::sora_image_gen_remix::{sora_image_gen_remix, SoraImageGenRemixRequest};
use openai_sora_client::requests::upload::upload_media_from_bytes::sora_media_upload_from_bytes;
use openai_sora_client::requests::upload::upload_media_from_file::sora_media_upload_from_file;
use openai_sora_client::sora_error::SoraError;
use reqwest::Url;
use serde_derive::{Deserialize, Serialize};
use std::fs::read_to_string;
use std::io::{Cursor, Read, Write};
use std::ops::Add;
use std::path::PathBuf;
use std::time::Duration;
use storyteller_client::error::api_error::ApiError;
use storyteller_client::error::api_error::ApiError::InternalServerError;
use storyteller_client::media_files::get_media_file::{get_media_file, GetMediaFileSuccessResponse};
use storyteller_client::media_files::upload_image_media_file_from_file::upload_image_media_file_from_file;
use storyteller_client::utils::api_host::ApiHost;
use tauri::{AppHandle, Emitter, Manager, State};
use tempfile::NamedTempFile;
#[derive(Deserialize)]
pub struct EnqueueTextToImageRequest {
/// Text prompt for the image generation. Required.
pub prompt: Option<String>,
/// The model to use.
pub model: Option<EnqueueTextToImageModel>,
}
#[derive(Deserialize, Debug, Copy, Clone)]
#[serde(rename_all = "snake_case")]
pub enum EnqueueTextToImageModel {
#[serde(rename = "flux_pro_ultra")]
FluxProUltra,
#[serde(rename = "gpt_image_1")]
GptImage1,
#[serde(rename = "recraft_3")]
Recraft3,
}
#[derive(Serialize)]
pub struct EnqueueTextToImageSuccessResponse {
}
impl SerializeMarker for EnqueueTextToImageSuccessResponse {}
#[derive(Serialize, Debug)]
#[serde(rename_all = "snake_case")]
pub enum EnqueueTextToImageErrorType {
/// Caller didn't specify a model
ModelNotSpecified,
/// Generic server error
ServerError,
/// No Fal API key available
NeedsFalApiKey,
/// Fal had an API error
FalError,
}
#[tauri::command]
pub async fn enqueue_text_to_image_command(
app: AppHandle,
request: EnqueueTextToImageRequest,
app_data_root: State<'_, AppDataRoot>,
fal_creds_manager: State<'_, FalCredentialManager>,
storyteller_creds_manager: State<'_, StorytellerCredentialManager>,
fal_task_queue: State<'_, FalTaskQueue>,
sora_creds_manager: State<'_, SoraCredentialManager>,
sora_task_queue: State<'_, SoraTaskQueue>,
) -> Response<EnqueueTextToImageSuccessResponse, EnqueueTextToImageErrorType, ()> {
info!("enqueue_text_to_image called");
let result = handle_request(
&app,
request,
&app_data_root,
&fal_creds_manager,
&storyteller_creds_manager,
&fal_task_queue,
&sora_creds_manager,
&sora_task_queue,
).await;
match result {
Err(err) => {
error!("error: {:?}", err);
let mut status = CommandErrorStatus::ServerError;
let mut error_type = EnqueueTextToImageErrorType::ServerError;
let mut error_message = "A server error occurred. Please try again. If it continues, please tell our staff about the problem.";
match err {
InternalImageError::NoModelSpecified => {
status = CommandErrorStatus::BadRequest;
error_type = EnqueueTextToImageErrorType::ModelNotSpecified;
error_message = "No model specified for image generation";
}
InternalImageError::NeedsFalApiKey => {
status = CommandErrorStatus::Unauthorized;
error_type = EnqueueTextToImageErrorType::NeedsFalApiKey;
error_message = "You need to set a FAL api key";
},
_ => {}, // Fall-through
}
Err(CommandErrorResponseWrapper {
status,
error_message: Some(error_message.to_string()),
error_type: Some(error_type),
error_details: None,
})
}
Ok(()) => {
Ok(EnqueueTextToImageSuccessResponse {}.into())
}
}
}
pub async fn handle_request(
app: &AppHandle,
request: EnqueueTextToImageRequest,
app_data_root: &AppDataRoot,
fal_creds_manager: &FalCredentialManager,
storyteller_creds_manager: &StorytellerCredentialManager,
fal_task_queue: &FalTaskQueue,
sora_creds_manager: &SoraCredentialManager,
sora_task_queue: &SoraTaskQueue,
) -> Result<(), InternalImageError> {
match request.model {
None => {
return Err(InternalImageError::NoModelSpecified);
}
Some(EnqueueTextToImageModel::FluxProUltra) | Some(EnqueueTextToImageModel::Recraft3) => {
handle_fal(&app, request, fal_creds_manager, fal_task_queue).await?;
},
Some(EnqueueTextToImageModel::GptImage1) => {
handle_sora(&app, request, sora_creds_manager, sora_task_queue).await?;
}
};
Ok(())
}
@@ -0,0 +1,111 @@
use crate::core::commands::enqueue::image::enqueue_text_to_image_command::{EnqueueTextToImageModel, EnqueueTextToImageRequest};
use crate::core::commands::enqueue::image::internal_image_error::InternalImageError;
use crate::core::events::basic_sendable_event_trait::BasicSendableEvent;
use crate::core::events::generation_events::common::{GenerationAction, GenerationServiceProvider};
use crate::core::events::generation_events::generation_enqueue_failure_event::GenerationEnqueueFailureEvent;
use crate::core::events::generation_events::generation_enqueue_success_event::GenerationEnqueueSuccessEvent;
use crate::core::state::data_dir::app_data_root::AppDataRoot;
use crate::services::fal::state::fal_credential_manager::FalCredentialManager;
use crate::services::fal::state::fal_task_queue::FalTaskQueue;
use crate::services::sora::state::sora_credential_manager::SoraCredentialManager;
use crate::services::sora::state::sora_task_queue::SoraTaskQueue;
use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager;
use anyhow::anyhow;
use fal_client::creds::fal_api_key::FalApiKey;
use fal_client::requests::queue::image_gen::enqueue_flux_pro_ultra_text_to_image::{enqueue_flux_pro_ultra_text_to_image, FluxProUltraTextToImageArgs};
use fal_client::requests::queue::image_gen::enqueue_recraft3_text_to_image::{enqueue_recraft3_text_to_image, Recraft3TextToImageArgs};
use log::{error, info, warn};
use tauri::AppHandle;
pub async fn handle_fal(
app: &AppHandle,
request: EnqueueTextToImageRequest,
fal_creds_manager: &FalCredentialManager,
fal_task_queue: &FalTaskQueue,
) -> Result<(), InternalImageError> {
let api_key = match fal_creds_manager.get_key()? {
Some(key) => key,
None => {
error!("No FAL API key is set. Can't perform action.");
let event =
GenerationEnqueueFailureEvent::no_fal_api_key(GenerationAction::GenerateImage);
if let Err(err) = event.send(&app) {
error!("Failed to emit event: {:?}", err); // Fail open.
}
return Err(InternalImageError::NeedsFalApiKey);
},
};
let api_key = fal_creds_manager.get_key_required()
.map_err(|err| {
error!("EnqueueTextToImage FAL api key required: {:?}", err);
InternalImageError::NeedsFalApiKey
})?;
let prompt = request.prompt.as_deref().unwrap_or("");
let result = match request.model {
None => {
return Err(InternalImageError::NoModelSpecified);
}
Some(EnqueueTextToImageModel::GptImage1) => {
return Err(InternalImageError::AnyhowError(anyhow!("wrong logic: fal is handling sora images")));
}
Some(EnqueueTextToImageModel::FluxProUltra) => {
info!("enqueue Flux Pro Ultra text-to-image with prompt: {}", prompt);
enqueue_flux_pro_ultra_text_to_image(FluxProUltraTextToImageArgs {
prompt,
api_key: &api_key,
}).await
}
Some(EnqueueTextToImageModel::Recraft3) => {
info!("enqueue Recraft v3 text-to-image with prompt: {}", prompt);
enqueue_recraft3_text_to_image(Recraft3TextToImageArgs {
prompt,
api_key: &api_key,
}).await
}
};
match result {
Ok(enqueued) => {
info!("Successfully enqueued text to image");
let event = GenerationEnqueueSuccessEvent {
action: GenerationAction::GenerateImage,
service: GenerationServiceProvider::Fal,
model: None,
};
if let Err(err) = event.send(app) {
error!("Failed to emit event: {:?}", err); // Fail open.
}
if let Err(err) = fal_task_queue.insert(&enqueued) {
error!("Failed to enqueue task: {:?}", err);
return Err(InternalImageError::AnyhowError(anyhow!("Failed to enqueue task: {:?}", err)));
}
}
Err(err) => {
error!("Failed to enqueue text to image: {:?}", err);
let event = GenerationEnqueueFailureEvent {
action: GenerationAction::GenerateImage,
service: GenerationServiceProvider::Fal,
model: None,
reason: None,
};
if let Err(err) = event.send(app) {
error!("Failed to emit event: {:?}", err); // Fail open.
}
return Err(InternalImageError::FalError(err));
}
}
Ok(())
}
@@ -0,0 +1,104 @@
use crate::core::commands::enqueue::image::enqueue_text_to_image_command::{EnqueueTextToImageModel, EnqueueTextToImageRequest};
use crate::core::commands::enqueue::image::internal_image_error::InternalImageError;
use crate::core::events::basic_sendable_event_trait::BasicSendableEvent;
use crate::core::events::generation_events::common::{GenerationAction, GenerationServiceProvider};
use crate::core::events::generation_events::generation_enqueue_failure_event::GenerationEnqueueFailureEvent;
use crate::core::events::generation_events::generation_enqueue_success_event::GenerationEnqueueSuccessEvent;
use crate::core::state::data_dir::app_data_root::AppDataRoot;
use crate::services::fal::state::fal_credential_manager::FalCredentialManager;
use crate::services::fal::state::fal_task_queue::FalTaskQueue;
use crate::services::sora::state::sora_credential_manager::SoraCredentialManager;
use crate::services::sora::state::sora_task_queue::SoraTaskQueue;
use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager;
use anyhow::anyhow;
use fal_client::requests::queue::image_gen::enqueue_flux_pro_ultra_text_to_image::{enqueue_flux_pro_ultra_text_to_image, FluxProUltraTextToImageArgs};
use fal_client::requests::queue::image_gen::enqueue_recraft3_text_to_image::{enqueue_recraft3_text_to_image, Recraft3TextToImageArgs};
use log::{error, info, warn};
use openai_sora_client::creds::sora_credential_set::SoraCredentialSet;
use openai_sora_client::recipes::image_remix_with_session_auto_renew::{image_remix_with_session_auto_renew, ImageRemixAutoRenewRequest};
use openai_sora_client::recipes::maybe_upgrade_or_renew_session::maybe_upgrade_or_renew_session;
use openai_sora_client::recipes::simple_image_gen_with_session_auto_renew::{simple_image_gen_with_session_auto_renew, SimpleImageGenAutoRenewRequest};
use openai_sora_client::requests::image_gen::common::{ImageSize, NumImages, SoraImageGenResponse};
use openai_sora_client::sora_error::SoraError;
use std::time::Duration;
use tauri::AppHandle;
const SORA_SIMPLE_IMAGE_GEN_TIMEOUT : Duration = Duration::from_millis(1000 * 30); // 30 seconds
pub async fn handle_sora(
app: &AppHandle,
request: EnqueueTextToImageRequest,
sora_creds_manager: &SoraCredentialManager,
sora_task_queue: &SoraTaskQueue,
) -> Result<(), InternalImageError> {
let mut creds = sora_creds_manager
.get_credentials_required()
.map_err(|err| {
error!("EnqueueTextToImage Sora creds required: {:?}", err);
InternalImageError::NeedsFalApiKey
})?;
let credential_updated = maybe_upgrade_or_renew_session(&mut creds)
.await
.map_err(|err| {
error!("Failed to upgrade or renew session: {:?}", err);
err
})?;
if credential_updated {
info!("Storing updated credentials");
sora_creds_manager.set_credentials(&creds)?;
}
let prompt = request.prompt.as_deref().unwrap_or("");
let result =
simple_image_gen_with_session_auto_renew(SimpleImageGenAutoRenewRequest {
prompt: prompt.to_string(),
num_images: NumImages::One,
image_size: ImageSize::Square,
credentials: &creds,
request_timeout: Some(SORA_SIMPLE_IMAGE_GEN_TIMEOUT),
}).await;
let (response, maybe_new_creds) =
match result {
Ok((response, maybe_new_creds)) => (response, maybe_new_creds),
Err(err) => {
let event = GenerationEnqueueFailureEvent {
action: GenerationAction::GenerateImage,
service: GenerationServiceProvider::Sora,
model: None,
reason: None,
};
if let Err(err) = event.send(app) {
error!("Failed to emit event: {:?}", err); // Fail open.
}
return Err(InternalImageError::SoraError(err));
}
};
if let Some(new_creds) = maybe_new_creds {
info!("Storing updated credentials.");
sora_creds_manager.set_credentials(&new_creds)?;
}
info!("New Sora Task ID: {:?} ", response.task_id);
sora_task_queue.insert(&response.task_id)?;
let event = GenerationEnqueueSuccessEvent {
action: GenerationAction::GenerateImage,
service: GenerationServiceProvider::Sora,
model: None,
};
if let Err(err) = event.send(app) {
error!("Failed to emit event: {:?}", err); // Fail open.
}
Ok(())
}
@@ -0,0 +1,54 @@
use base64::DecodeError;
use errors::AnyhowError;
use fal_client::error::fal_error_plus::FalErrorPlus;
use openai_sora_client::sora_error::SoraError;
use storyteller_client::error::api_error::ApiError;
#[derive(Debug)]
pub enum InternalImageError {
NoModelSpecified,
NeedsFalApiKey,
NeedsSoraCredentials,
FalError(FalErrorPlus),
SoraError(SoraError),
AnyhowError(AnyhowError),
StorytellerApiError(ApiError),
DecodeError(DecodeError),
IoError(std::io::Error),
}
impl From<AnyhowError> for InternalImageError {
fn from(value: AnyhowError) -> Self {
Self::AnyhowError(value)
}
}
impl From<FalErrorPlus> for InternalImageError {
fn from(value: FalErrorPlus) -> Self {
Self::FalError(value)
}
}
impl From<SoraError> for InternalImageError {
fn from(value: SoraError) -> Self {
Self::SoraError(value)
}
}
impl From<ApiError> for InternalImageError {
fn from(value: ApiError) -> Self {
Self::StorytellerApiError(value)
}
}
impl From<DecodeError> for InternalImageError {
fn from(value: DecodeError) -> Self {
Self::DecodeError(value)
}
}
impl From<std::io::Error> for InternalImageError {
fn from(value: std::io::Error) -> Self {
Self::IoError(value)
}
}
@@ -0,0 +1,4 @@
pub mod enqueue_text_to_image_command;
pub mod handle_fal;
pub mod handle_sora;
pub mod internal_image_error;
@@ -0,0 +1,2 @@
pub mod image;
pub mod object;
@@ -0,0 +1,179 @@
use crate::core::commands::enqueue::image::handle_fal::handle_fal;
use crate::core::commands::enqueue::image::handle_sora::handle_sora;
use crate::core::commands::enqueue::object::handle_object_fal::handle_object_fal;
use crate::core::commands::enqueue::object::internal_object_error::InternalObjectError;
use crate::core::commands::response::failure_response_wrapper::{CommandErrorResponseWrapper, CommandErrorStatus};
use crate::core::commands::response::shorthand::Response;
use crate::core::commands::response::success_response_wrapper::SerializeMarker;
use crate::core::events::sendable_event_trait::SendableEvent;
use crate::core::state::data_dir::app_data_root::AppDataRoot;
use crate::core::state::data_dir::trait_data_subdir::DataSubdir;
use crate::core::utils::download_media_file_to_temp_dir::download_media_file_to_temp_dir;
use crate::core::utils::get_url_file_extension::get_url_file_extension;
use crate::core::utils::save_base64_image_to_temp_dir::save_base64_image_to_temp_dir;
use crate::core::utils::simple_http_download::simple_http_download;
use crate::core::utils::simple_http_download_to_tempfile::simple_http_download_to_tempfile;
use crate::services::fal::state::fal_credential_manager::FalCredentialManager;
use crate::services::fal::state::fal_task_queue::FalTaskQueue;
use crate::services::sora::state::read_sora_credentials_from_disk::read_sora_credentials_from_disk;
use crate::services::sora::state::sora_credential_holder::SoraCredentialHolder;
use crate::services::sora::state::sora_credential_manager::SoraCredentialManager;
use crate::services::sora::state::sora_task_queue::SoraTaskQueue;
use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager;
use anyhow::anyhow;
use base64::prelude::BASE64_STANDARD;
use base64::{DecodeError, Engine};
use errors::{AnyhowError, AnyhowResult};
use fal_client::error::fal_error_plus::FalErrorPlus;
use fal_client::requests::queue::image_gen::enqueue_flux_pro_ultra_text_to_image::{enqueue_flux_pro_ultra_text_to_image, FluxProUltraTextToImageArgs};
use fal_client::requests::queue::image_gen::enqueue_recraft3_text_to_image::{enqueue_recraft3_text_to_image, Recraft3TextToImageArgs};
use filesys::file_read_bytes::file_read_bytes;
use image::codecs::png::{CompressionType, FilterType, PngEncoder};
use image::{DynamicImage, EncodableLayout, ImageReader};
use log::{debug, error, info, warn};
use mimetypes::mimetype_info::mimetype_info::MimetypeInfo;
use openai_sora_client::credentials::SoraCredentials;
use openai_sora_client::creds::credential_migration::CredentialMigrationRef;
use openai_sora_client::recipes::image_remix_with_session_auto_renew::{image_remix_with_session_auto_renew, ImageRemixAutoRenewRequest};
use openai_sora_client::recipes::image_upload_from_file_with_session_auto_renew::{image_upload_from_file_with_session_auto_renew, ImageUploadFromFileAutoRenewRequest};
use openai_sora_client::recipes::maybe_upgrade_or_renew_session::maybe_upgrade_or_renew_session;
use openai_sora_client::requests::image_gen::common::{ImageSize, NumImages};
use openai_sora_client::requests::image_gen::sora_image_gen_remix::{sora_image_gen_remix, SoraImageGenRemixRequest};
use openai_sora_client::requests::upload::upload_media_from_bytes::sora_media_upload_from_bytes;
use openai_sora_client::requests::upload::upload_media_from_file::sora_media_upload_from_file;
use openai_sora_client::sora_error::SoraError;
use reqwest::Url;
use serde_derive::{Deserialize, Serialize};
use std::fs::read_to_string;
use std::io::{Cursor, Read, Write};
use std::ops::Add;
use std::path::PathBuf;
use std::time::Duration;
use storyteller_client::error::api_error::ApiError;
use storyteller_client::error::api_error::ApiError::InternalServerError;
use storyteller_client::media_files::get_media_file::{get_media_file, GetMediaFileSuccessResponse};
use storyteller_client::media_files::upload_image_media_file_from_file::upload_image_media_file_from_file;
use storyteller_client::utils::api_host::ApiHost;
use tauri::{AppHandle, Emitter, Manager, State};
use tempfile::NamedTempFile;
use tokens::tokens::media_files::MediaFileToken;
use crate::core::commands::enqueue::object::handle_object_artcraft::handle_object_artcraft;
#[derive(Deserialize)]
pub struct EnqueueImageTo3dObjectRequest {
/// Image media file; the image to remove the background from.
/// TODO: In the future we may support base64 images, URLs, or file paths here.
pub image_media_token: Option<MediaFileToken>,
/// The model to use.
pub model: Option<EnqueueImageTo3dObjectModel>,
}
#[derive(Deserialize, Debug, Copy, Clone)]
#[serde(rename_all = "snake_case")]
pub enum EnqueueImageTo3dObjectModel {
#[serde(rename = "hunyuan_3d_2")]
Hunyuan3d2,
}
#[derive(Serialize)]
pub struct EnqueueImageTo3dObjectSuccessResponse {
}
impl SerializeMarker for EnqueueImageTo3dObjectSuccessResponse {}
#[derive(Serialize, Debug)]
#[serde(rename_all = "snake_case")]
pub enum EnqueueImageTo3dObjectErrorType {
/// Caller didn't specify a model
ModelNotSpecified,
/// Generic server error
ServerError,
/// No Fal API key available
NeedsFalApiKey,
/// Fal had an API error
FalError,
/// Needs to be logged into Artcraft
NeedsStorytellerCredentials,
}
#[tauri::command]
pub async fn enqueue_image_to_3d_object_command(
app: AppHandle,
request: EnqueueImageTo3dObjectRequest,
app_data_root: State<'_, AppDataRoot>,
fal_creds_manager: State<'_, FalCredentialManager>,
fal_task_queue: State<'_, FalTaskQueue>,
storyteller_creds_manager: State<'_, StorytellerCredentialManager>,
sora_task_queue: State<'_, SoraTaskQueue>,
) -> Response<EnqueueImageTo3dObjectSuccessResponse, EnqueueImageTo3dObjectErrorType, ()> {
info!("enqueue_image_to_3d_object_command called");
let result = handle_request(
&app,
request,
&app_data_root,
&fal_creds_manager,
&storyteller_creds_manager,
&fal_task_queue,
).await;
match result {
Err(err) => {
error!("error: {:?}", err);
let mut status = CommandErrorStatus::ServerError;
let mut error_type = EnqueueImageTo3dObjectErrorType::ServerError;
let mut error_message = "A server error occurred. Please try again. If it continues, please tell our staff about the problem.";
match err {
InternalObjectError::NoModelSpecified => {
status = CommandErrorStatus::BadRequest;
error_type = EnqueueImageTo3dObjectErrorType::ModelNotSpecified;
error_message = "No model specified for image generation";
}
InternalObjectError::NeedsFalApiKey => {
status = CommandErrorStatus::Unauthorized;
error_type = EnqueueImageTo3dObjectErrorType::NeedsFalApiKey;
error_message = "You need to set a FAL api key";
},
InternalObjectError::NeedsStorytellerCredentials => {
status = CommandErrorStatus::Unauthorized;
error_type = EnqueueImageTo3dObjectErrorType::NeedsStorytellerCredentials;
error_message = "You need to be logged into Artcraft.";
}
_ => {}, // Fall-through
}
Err(CommandErrorResponseWrapper {
status,
error_message: Some(error_message.to_string()),
error_type: Some(error_type),
error_details: None,
})
}
Ok(()) => {
Ok(EnqueueImageTo3dObjectSuccessResponse {}.into())
}
}
}
pub async fn handle_request(
app: &AppHandle,
request: EnqueueImageTo3dObjectRequest,
app_data_root: &AppDataRoot,
fal_creds_manager: &FalCredentialManager,
storyteller_creds_manager: &StorytellerCredentialManager,
fal_task_queue: &FalTaskQueue,
) -> Result<(), InternalObjectError> {
if fal_creds_manager.has_apparent_api_token()? {
handle_object_fal(&app, app_data_root, request, fal_creds_manager, fal_task_queue).await?;
} else {
handle_object_artcraft(request, &app, app_data_root, storyteller_creds_manager).await?;
}
Ok(())
}
@@ -0,0 +1,129 @@
use crate::core::commands::enqueue::image::enqueue_text_to_image_command::{EnqueueTextToImageModel, EnqueueTextToImageRequest};
use crate::core::commands::enqueue::object::enqueue_image_to_3d_object_command::{EnqueueImageTo3dObjectModel, EnqueueImageTo3dObjectRequest};
use crate::core::commands::enqueue::object::internal_object_error::InternalObjectError;
use crate::core::events::basic_sendable_event_trait::BasicSendableEvent;
use crate::core::events::generation_events::common::{GenerationAction, GenerationServiceProvider};
use crate::core::events::generation_events::generation_enqueue_failure_event::GenerationEnqueueFailureEvent;
use crate::core::events::generation_events::generation_enqueue_success_event::GenerationEnqueueSuccessEvent;
use crate::core::state::data_dir::app_data_root::AppDataRoot;
use crate::core::utils::download_media_file_to_temp_dir::download_media_file_to_temp_dir;
use crate::core::utils::save_base64_image_to_temp_dir::save_base64_image_to_temp_dir;
use crate::services::fal::state::fal_credential_manager::FalCredentialManager;
use crate::services::fal::state::fal_task_queue::FalTaskQueue;
use crate::services::sora::state::sora_credential_manager::SoraCredentialManager;
use crate::services::sora::state::sora_task_queue::SoraTaskQueue;
use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager;
use anyhow::anyhow;
use artcraft_api_defs::generate::object::generate_hunyuan_2_image_to_3d::GenerateHunyuan2ImageTo3dRequest;
use fal_client::creds::fal_api_key::FalApiKey;
use fal_client::requests::queue::enqueue_hunyuan2_image_to_3d::{enqueue_hunyuan2_image_to_3d, Hunyuan2Args};
use fal_client::requests::queue::image_gen::enqueue_flux_pro_ultra_text_to_image::{enqueue_flux_pro_ultra_text_to_image, FluxProUltraTextToImageArgs};
use fal_client::requests::queue::image_gen::enqueue_recraft3_text_to_image::{enqueue_recraft3_text_to_image, Recraft3TextToImageArgs};
use idempotency::uuid::generate_random_uuid;
use log::{error, info, warn};
use storyteller_client::generate::object::generate_hunyuan2_image_to_3d::generate_hunyuan2_image_to_3d;
use storyteller_client::utils::api_host::ApiHost;
use tauri::{AppHandle, State};
pub async fn handle_object_artcraft(
request: EnqueueImageTo3dObjectRequest,
app: &AppHandle,
app_data_root: &AppDataRoot,
storyteller_creds_manager: &StorytellerCredentialManager,
) -> Result<(), InternalObjectError> {
let creds = match storyteller_creds_manager.get_credentials()? {
Some(creds) => creds,
None => {
error!("No Artcraft credentials are set. Can't perform action.");
let event =
GenerationEnqueueFailureEvent::no_artcraft_credentials(GenerationAction::ImageTo3d);
if let Err(err) = event.send(&app) {
error!("Failed to emit event: {:?}", err); // Fail open.
}
return Err(InternalObjectError::NeedsStorytellerCredentials);
},
};
//let api_key = fal_creds_manager.get_key_required()
// .map_err(|err| {
// error!("EnqueueTextToImage FAL api key required: {:?}", err);
// InternalObjectError::NeedsFalApiKey
// })?;
info!("Calling Artcraft image to 3d ...");
let uuid_idempotency_token = generate_random_uuid();
let job_token = match request.model {
None => {
return Err(InternalObjectError::NoModelSpecified);
}
Some(EnqueueImageTo3dObjectModel::Hunyuan3d2) => {
info!("enqueue Hunyuan 3D 2.0");
let request = GenerateHunyuan2ImageTo3dRequest {
uuid_idempotency_token,
media_file_token: request.image_media_token,
};
let result = generate_hunyuan2_image_to_3d(
&ApiHost::Storyteller,
Some(&creds),
request,
).await;
match result {
Ok(enqueued) => {
info!("Successfully enqueued Artcraft Hunyuan 3D 2.0");
enqueued.inference_job_token
}
Err(err) => {
error!("Failed to use Artcraft Hunyuan 3D 2.0: {:?}", err);
return Err(InternalObjectError::StorytellerError(err));
}
}
}
};
info!("Successfully enqueued 3D generation");
let event = GenerationEnqueueSuccessEvent {
action: GenerationAction::ImageTo3d,
service: GenerationServiceProvider::Artcraft,
model: None,
};
if let Err(err) = event.send(app) {
error!("Failed to emit event: {:?}", err); // Fail open.
}
//if let Err(err) = fal_task_queue.insert(&enqueued) {
// error!("Failed to enqueue task: {:?}", err);
// return Err(InternalObjectError::AnyhowError(anyhow!("Failed to enqueue task: {:?}", err)));
//}
// match result {
// Ok(enqueued) => {
// }
// Err(err) => {
// error!("Failed to enqueue image to 3d: {:?}", err);
//
// let event = GenerationEnqueueFailureEvent {
// action: GenerationAction::ImageTo3d,
// service: GenerationServiceProvider::Fal,
// model: None,
// reason: None,
// };
//
// if let Err(err) = event.send(app) {
// error!("Failed to emit event: {:?}", err); // Fail open.
// }
//
// return Err(InternalObjectError::FalError(err));
// }
// }
Ok(())
}
@@ -0,0 +1,117 @@
use crate::core::commands::enqueue::image::enqueue_text_to_image_command::{EnqueueTextToImageModel, EnqueueTextToImageRequest};
use crate::core::commands::enqueue::object::enqueue_image_to_3d_object_command::{EnqueueImageTo3dObjectModel, EnqueueImageTo3dObjectRequest};
use crate::core::commands::enqueue::object::internal_object_error::InternalObjectError;
use crate::core::events::basic_sendable_event_trait::BasicSendableEvent;
use crate::core::events::generation_events::common::{GenerationAction, GenerationServiceProvider};
use crate::core::events::generation_events::generation_enqueue_failure_event::GenerationEnqueueFailureEvent;
use crate::core::events::generation_events::generation_enqueue_success_event::GenerationEnqueueSuccessEvent;
use crate::core::state::data_dir::app_data_root::AppDataRoot;
use crate::core::utils::download_media_file_to_temp_dir::download_media_file_to_temp_dir;
use crate::core::utils::save_base64_image_to_temp_dir::save_base64_image_to_temp_dir;
use crate::services::fal::state::fal_credential_manager::FalCredentialManager;
use crate::services::fal::state::fal_task_queue::FalTaskQueue;
use crate::services::sora::state::sora_credential_manager::SoraCredentialManager;
use crate::services::sora::state::sora_task_queue::SoraTaskQueue;
use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager;
use anyhow::anyhow;
use fal_client::creds::fal_api_key::FalApiKey;
use fal_client::requests::queue::enqueue_hunyuan2_image_to_3d::{enqueue_hunyuan2_image_to_3d, Hunyuan2Args};
use fal_client::requests::queue::image_gen::enqueue_flux_pro_ultra_text_to_image::{enqueue_flux_pro_ultra_text_to_image, FluxProUltraTextToImageArgs};
use fal_client::requests::queue::image_gen::enqueue_recraft3_text_to_image::{enqueue_recraft3_text_to_image, Recraft3TextToImageArgs};
use log::{error, info, warn};
use tauri::AppHandle;
pub async fn handle_object_fal(
app: &AppHandle,
app_data_root: &AppDataRoot,
request: EnqueueImageTo3dObjectRequest,
fal_creds_manager: &FalCredentialManager,
fal_task_queue: &FalTaskQueue,
) -> Result<(), InternalObjectError> {
let api_key = match fal_creds_manager.get_key()? {
Some(key) => key,
None => {
error!("No FAL API key is set. Can't perform action.");
let event =
GenerationEnqueueFailureEvent::no_fal_api_key(GenerationAction::GenerateImage);
if let Err(err) = event.send(&app) {
error!("Failed to emit event: {:?}", err); // Fail open.
}
return Err(InternalObjectError::NeedsFalApiKey);
},
};
//let api_key = fal_creds_manager.get_key_required()
// .map_err(|err| {
// error!("EnqueueTextToImage FAL api key required: {:?}", err);
// InternalObjectError::NeedsFalApiKey
// })?;
let mut temp_download;
if let Some(media_token) = request.image_media_token {
temp_download = download_media_file_to_temp_dir(&app_data_root, &media_token).await?;
} else {
return Err(InternalObjectError::AnyhowError(anyhow!("No image media token provided")));
}
info!("Calling FAL image to 3d ...");
let filename = temp_download.path().to_path_buf();
let result = match request.model {
None => {
return Err(InternalObjectError::NoModelSpecified);
}
Some(EnqueueImageTo3dObjectModel::Hunyuan3d2) => {
info!("enqueue Hunyuan 3D 2.0");
enqueue_hunyuan2_image_to_3d(Hunyuan2Args {
image_path: filename,
api_key: &api_key,
}).await
}
};
match result {
Ok(enqueued) => {
info!("Successfully enqueued text to image");
let event = GenerationEnqueueSuccessEvent {
action: GenerationAction::ImageTo3d,
service: GenerationServiceProvider::Fal,
model: None,
};
if let Err(err) = event.send(app) {
error!("Failed to emit event: {:?}", err); // Fail open.
}
if let Err(err) = fal_task_queue.insert(&enqueued) {
error!("Failed to enqueue task: {:?}", err);
return Err(InternalObjectError::AnyhowError(anyhow!("Failed to enqueue task: {:?}", err)));
}
}
Err(err) => {
error!("Failed to enqueue image to 3d: {:?}", err);
let event = GenerationEnqueueFailureEvent {
action: GenerationAction::ImageTo3d,
service: GenerationServiceProvider::Fal,
model: None,
reason: None,
};
if let Err(err) = event.send(app) {
error!("Failed to emit event: {:?}", err); // Fail open.
}
return Err(InternalObjectError::FalError(err));
}
}
Ok(())
}
@@ -0,0 +1,49 @@
use base64::DecodeError;
use errors::AnyhowError;
use fal_client::error::fal_error_plus::FalErrorPlus;
use storyteller_client::error::api_error::ApiError;
use storyteller_client::error::storyteller_error::StorytellerError;
#[derive(Debug)]
pub enum InternalObjectError {
NoModelSpecified,
NeedsFalApiKey,
NeedsSoraCredentials,
NeedsStorytellerCredentials,
FalError(FalErrorPlus),
AnyhowError(AnyhowError),
StorytellerError(StorytellerError),
StorytellerApiError(ApiError),
DecodeError(DecodeError),
IoError(std::io::Error),
}
impl From<AnyhowError> for InternalObjectError {
fn from(value: AnyhowError) -> Self {
Self::AnyhowError(value)
}
}
impl From<FalErrorPlus> for InternalObjectError {
fn from(value: FalErrorPlus) -> Self {
Self::FalError(value)
}
}
impl From<ApiError> for InternalObjectError {
fn from(value: ApiError) -> Self {
Self::StorytellerApiError(value)
}
}
impl From<DecodeError> for InternalObjectError {
fn from(value: DecodeError) -> Self {
Self::DecodeError(value)
}
}
impl From<std::io::Error> for InternalObjectError {
fn from(value: std::io::Error) -> Self {
Self::IoError(value)
}
}
@@ -0,0 +1,4 @@
pub mod enqueue_image_to_3d_object_command;
pub mod handle_object_artcraft;
pub mod handle_object_fal;
pub mod internal_object_error;
@@ -0,0 +1,40 @@
use crate::core::commands::response::shorthand::InfallibleResponse;
use crate::core::commands::response::success_response_wrapper::SerializeMarker;
use crate::core::state::os_platform::OsPlatform;
use crate::services::fal::commands::fal_background_removal_command::FalBackgroundRemovalSuccessResponse;
use base64::prelude::BASE64_STANDARD;
use base64::Engine;
use chrono::{DateTime, Utc};
use image::codecs::png::{CompressionType, FilterType, PngEncoder};
use image::ImageReader;
use log::info;
use serde_derive::Serialize;
use std::io::Cursor;
#[derive(Debug, Serialize)]
pub struct BuildInfoResponse {
pub build_timestamp: DateTime<Utc>,
pub git_commit_id: Option<String>,
pub git_commit_short_id: Option<String>,
pub git_commit_timestamp: Option<DateTime<Utc>>,
}
impl SerializeMarker for BuildInfoResponse {}
#[tauri::command]
pub fn get_build_info_command() -> InfallibleResponse<BuildInfoResponse> {
info!("get_build_info_command called...");
let build_timestamp = build_metadata::build_timestamp();
let git_commit_id = build_metadata::git_commit_id();
let git_commit_short_id = build_metadata::git_commit_short_id();
let git_commit_timestamp = build_metadata::git_commit_timestamp();
BuildInfoResponse {
build_timestamp,
git_commit_id: git_commit_id.map(|s| s.to_string()),
git_commit_short_id: git_commit_short_id.map(|s| s.to_string()),
git_commit_timestamp,
}.into()
}
@@ -0,0 +1,6 @@
pub mod app_preferences;
pub mod enqueue;
pub mod flip_image;
pub mod get_build_info_command;
pub mod platform_info_command;
pub mod response;
@@ -0,0 +1,67 @@
use crate::core::commands::response::shorthand::InfallibleResponse;
use crate::core::commands::response::success_response_wrapper::SerializeMarker;
use crate::core::state::os_platform::OsPlatform;
use base64::prelude::BASE64_STANDARD;
use base64::Engine;
use image::codecs::png::{CompressionType, FilterType, PngEncoder};
use image::ImageReader;
use log::info;
use serde_derive::Serialize;
use std::io::Cursor;
#[derive(Debug, Serialize)]
pub struct PlatformInfoResponse {
pub os_platform: DetectedOs,
pub webview_runtime: WebviewRuntime,
}
impl SerializeMarker for PlatformInfoResponse {}
#[derive(Copy, Clone, Debug, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum DetectedOs {
Windows,
#[serde(rename = "macos")]
MacOS,
Linux,
Unknown,
}
#[derive(Copy, Clone, Debug, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum WebviewRuntime {
#[serde(rename = "webkit_safari")]
WebkitSafari,
#[serde(rename = "webkit_gtk")]
WebkitGtk,
#[serde(rename = "edge_webview_2")]
EdgeWebview2,
Unknown,
}
#[tauri::command]
pub fn platform_info_command() -> InfallibleResponse<PlatformInfoResponse> {
info!("platform_info_command called...");
let os_platform = match OsPlatform::maybe_get() {
Some(OsPlatform::Linux) => DetectedOs::Linux,
Some(OsPlatform::MacOs) => DetectedOs::MacOS,
Some(OsPlatform::Windows) => DetectedOs::Windows,
None => DetectedOs::Unknown,
};
// These are the webviews that Tauri uses on each OS:
// https://tauri.app/reference/webview-versions/
let webview_runtime = match os_platform {
DetectedOs::Windows => WebviewRuntime::EdgeWebview2,
DetectedOs::MacOS => WebviewRuntime::WebkitSafari,
DetectedOs::Linux => WebviewRuntime::WebkitGtk,
DetectedOs::Unknown => WebviewRuntime::Unknown,
};
PlatformInfoResponse {
os_platform,
webview_runtime,
}.into()
}

Some files were not shown because too many files have changed in this diff Show More