@_vrsen/openswarm 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +152 -0
- package/bin/openswarm.js +38 -0
- package/config.py +34 -0
- package/data_analyst_agent/.cursor/rules/data_analyst.mdc +43 -0
- package/data_analyst_agent/__init__.py +3 -0
- package/data_analyst_agent/__pycache__/__init__.cpython-312.pyc +0 -0
- package/data_analyst_agent/__pycache__/data_analyst_agent.cpython-312.pyc +0 -0
- package/data_analyst_agent/data_analyst_agent.py +45 -0
- package/data_analyst_agent/instructions.md +173 -0
- package/data_analyst_agent/test_files/test_file.csv +21 -0
- package/data_analyst_agent/tools/__init__.py +6 -0
- package/deep_research/__init__.py +1 -0
- package/deep_research/__pycache__/__init__.cpython-312.pyc +0 -0
- package/deep_research/__pycache__/deep_research.cpython-312.pyc +0 -0
- package/deep_research/deep_research.py +27 -0
- package/deep_research/instructions.md +104 -0
- package/deep_research/tools/__init__.py +1 -0
- package/docs_agent/__init__.py +3 -0
- package/docs_agent/__pycache__/__init__.cpython-312.pyc +0 -0
- package/docs_agent/__pycache__/docs_agent.cpython-312.pyc +0 -0
- package/docs_agent/docs_agent.py +61 -0
- package/docs_agent/instructions.md +418 -0
- package/docs_agent/tools/ConvertDocument.py +323 -0
- package/docs_agent/tools/CreateDocument.py +287 -0
- package/docs_agent/tools/ListDocuments.py +134 -0
- package/docs_agent/tools/ModifyDocument.py +247 -0
- package/docs_agent/tools/RestoreDocument.py +79 -0
- package/docs_agent/tools/ViewDocument.py +153 -0
- package/docs_agent/tools/__init__.py +1 -0
- package/docs_agent/tools/__pycache__/ConvertDocument.cpython-312.pyc +0 -0
- package/docs_agent/tools/__pycache__/CreateDocument.cpython-312.pyc +0 -0
- package/docs_agent/tools/__pycache__/ListDocuments.cpython-312.pyc +0 -0
- package/docs_agent/tools/__pycache__/ModifyDocument.cpython-312.pyc +0 -0
- package/docs_agent/tools/__pycache__/RestoreDocument.cpython-312.pyc +0 -0
- package/docs_agent/tools/__pycache__/ViewDocument.cpython-312.pyc +0 -0
- package/docs_agent/tools/__pycache__/__init__.cpython-312.pyc +0 -0
- package/docs_agent/tools/utils/__init__.py +1 -0
- package/docs_agent/tools/utils/__pycache__/__init__.cpython-312.pyc +0 -0
- package/docs_agent/tools/utils/__pycache__/doc_file_utils.cpython-312.pyc +0 -0
- package/docs_agent/tools/utils/__pycache__/html_docx_blocks.cpython-312.pyc +0 -0
- package/docs_agent/tools/utils/__pycache__/html_docx_constants.cpython-312.pyc +0 -0
- package/docs_agent/tools/utils/__pycache__/html_docx_core.cpython-312.pyc +0 -0
- package/docs_agent/tools/utils/__pycache__/html_docx_css.cpython-312.pyc +0 -0
- package/docs_agent/tools/utils/__pycache__/html_docx_images.cpython-312.pyc +0 -0
- package/docs_agent/tools/utils/__pycache__/html_docx_page.cpython-312.pyc +0 -0
- package/docs_agent/tools/utils/__pycache__/html_docx_paragraphs.cpython-312.pyc +0 -0
- package/docs_agent/tools/utils/__pycache__/html_docx_playwright.cpython-312.pyc +0 -0
- package/docs_agent/tools/utils/__pycache__/html_docx_selectors.cpython-312.pyc +0 -0
- package/docs_agent/tools/utils/__pycache__/html_docx_shared.cpython-312.pyc +0 -0
- package/docs_agent/tools/utils/__pycache__/html_validation.cpython-312.pyc +0 -0
- package/docs_agent/tools/utils/doc_file_utils.py +29 -0
- package/docs_agent/tools/utils/html_docx_blocks.py +262 -0
- package/docs_agent/tools/utils/html_docx_constants.py +78 -0
- package/docs_agent/tools/utils/html_docx_core.py +138 -0
- package/docs_agent/tools/utils/html_docx_css.py +262 -0
- package/docs_agent/tools/utils/html_docx_images.py +293 -0
- package/docs_agent/tools/utils/html_docx_page.py +185 -0
- package/docs_agent/tools/utils/html_docx_paragraphs.py +342 -0
- package/docs_agent/tools/utils/html_docx_playwright.py +184 -0
- package/docs_agent/tools/utils/html_docx_selectors.py +196 -0
- package/docs_agent/tools/utils/html_docx_shared.py +23 -0
- package/docs_agent/tools/utils/html_docx_tables.py +942 -0
- package/docs_agent/tools/utils/html_validation.py +102 -0
- package/helpers.py +59 -0
- package/image_generation_agent/__init__.py +1 -0
- package/image_generation_agent/__pycache__/__init__.cpython-312.pyc +0 -0
- package/image_generation_agent/__pycache__/image_generation_agent.cpython-312.pyc +0 -0
- package/image_generation_agent/image_generation_agent.py +31 -0
- package/image_generation_agent/instructions.md +80 -0
- package/image_generation_agent/tools/CombineImages.py +211 -0
- package/image_generation_agent/tools/EditImages.py +200 -0
- package/image_generation_agent/tools/GenerateImages.py +184 -0
- package/image_generation_agent/tools/RemoveBackground.py +108 -0
- package/image_generation_agent/tools/__init__.py +2 -0
- package/image_generation_agent/tools/__pycache__/CombineImages.cpython-312.pyc +0 -0
- package/image_generation_agent/tools/__pycache__/EditImages.cpython-312.pyc +0 -0
- package/image_generation_agent/tools/__pycache__/GenerateImages.cpython-312.pyc +0 -0
- package/image_generation_agent/tools/__pycache__/RemoveBackground.cpython-312.pyc +0 -0
- package/image_generation_agent/tools/utils/__init__.py +2 -0
- package/image_generation_agent/tools/utils/__pycache__/__init__.cpython-312.pyc +0 -0
- package/image_generation_agent/tools/utils/__pycache__/image_io.cpython-312.pyc +0 -0
- package/image_generation_agent/tools/utils/image_io.py +308 -0
- package/onboard.py +325 -0
- package/orchestrator/__init__.py +3 -0
- package/orchestrator/__pycache__/__init__.cpython-312.pyc +0 -0
- package/orchestrator/__pycache__/orchestrator.cpython-312.pyc +0 -0
- package/orchestrator/instructions.md +90 -0
- package/orchestrator/orchestrator.py +33 -0
- package/package.json +49 -0
- package/patches/__init__.py +1 -0
- package/patches/__pycache__/__init__.cpython-312.pyc +0 -0
- package/patches/__pycache__/patch_agency_swarm_dual_comms.cpython-312.pyc +0 -0
- package/patches/__pycache__/patch_file_attachment_refs.cpython-312.pyc +0 -0
- package/patches/__pycache__/patch_ipython_interpreter_composio.cpython-312.pyc +0 -0
- package/patches/dom-to-pptx+1.1.5.patch +133440 -0
- package/patches/patch_agency_swarm_dual_comms.py +199 -0
- package/patches/patch_file_attachment_refs.py +74 -0
- package/patches/patch_ipython_interpreter_composio.py +54 -0
- package/pyproject.toml +67 -0
- package/run.py +343 -0
- package/server.py +26 -0
- package/shared_instructions.md +119 -0
- package/shared_tools/CopyFile.py +68 -0
- package/shared_tools/ExecuteTool.py +184 -0
- package/shared_tools/FindTools.py +101 -0
- package/shared_tools/ManageConnections.py +43 -0
- package/shared_tools/SearchTools.py +44 -0
- package/shared_tools/__init__.py +7 -0
- package/shared_tools/__pycache__/CopyFile.cpython-312.pyc +0 -0
- package/shared_tools/__pycache__/ExecuteTool.cpython-312.pyc +0 -0
- package/shared_tools/__pycache__/FindTools.cpython-312.pyc +0 -0
- package/shared_tools/__pycache__/ManageConnections.cpython-312.pyc +0 -0
- package/shared_tools/__pycache__/SearchTools.cpython-312.pyc +0 -0
- package/shared_tools/__pycache__/__init__.cpython-312.pyc +0 -0
- package/slides_agent/.cursor/rules/slides-agent-workflow.mdc +9 -0
- package/slides_agent/__init__.py +1 -0
- package/slides_agent/__pycache__/__init__.cpython-312.pyc +0 -0
- package/slides_agent/__pycache__/slides_agent.cpython-312.pyc +0 -0
- package/slides_agent/instructions.md +298 -0
- package/slides_agent/pptx/SKILL.md +528 -0
- package/slides_agent/pptx/html2pptx.md +625 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- package/slides_agent/pptx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
- package/slides_agent/pptx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
- package/slides_agent/pptx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
- package/slides_agent/pptx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
- package/slides_agent/pptx/ooxml/schemas/mce/mc.xsd +75 -0
- package/slides_agent/pptx/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
- package/slides_agent/pptx/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
- package/slides_agent/pptx/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
- package/slides_agent/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
- package/slides_agent/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
- package/slides_agent/pptx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- package/slides_agent/pptx/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
- package/slides_agent/pptx/ooxml/scripts/pack.py +169 -0
- package/slides_agent/pptx/ooxml/scripts/unpack.py +29 -0
- package/slides_agent/pptx/ooxml/scripts/validate.py +69 -0
- package/slides_agent/pptx/ooxml/scripts/validation/__init__.py +15 -0
- package/slides_agent/pptx/ooxml/scripts/validation/base.py +951 -0
- package/slides_agent/pptx/ooxml/scripts/validation/docx.py +274 -0
- package/slides_agent/pptx/ooxml/scripts/validation/pptx.py +315 -0
- package/slides_agent/pptx/ooxml/scripts/validation/redlining.py +279 -0
- package/slides_agent/pptx/ooxml.md +427 -0
- package/slides_agent/pptx/scripts/html2pptx.js +1092 -0
- package/slides_agent/pptx/scripts/inventory.py +1020 -0
- package/slides_agent/pptx/scripts/rearrange.py +231 -0
- package/slides_agent/pptx/scripts/replace.py +385 -0
- package/slides_agent/pptx/scripts/thumbnail.py +451 -0
- package/slides_agent/slides_agent.py +109 -0
- package/slides_agent/test_deck/_theme.css +92 -0
- package/slides_agent/test_deck/assets/placeholder.svg +11 -0
- package/slides_agent/test_deck/slide_01_title.html +10 -0
- package/slides_agent/test_deck/slide_02_image_split.html +23 -0
- package/slides_agent/test_deck/slide_03_kpi.html +21 -0
- package/slides_agent/tools/ApplyPptxTextReplacements.py +91 -0
- package/slides_agent/tools/BuildPptxFromHtmlSlides.py +221 -0
- package/slides_agent/tools/CheckSlide.py +218 -0
- package/slides_agent/tools/CheckSlideCanvasOverflow.py +221 -0
- package/slides_agent/tools/CreateImageMontage.py +261 -0
- package/slides_agent/tools/CreatePptxThumbnailGrid.py +168 -0
- package/slides_agent/tools/DeleteSlide.py +78 -0
- package/slides_agent/tools/DownloadImage.py +79 -0
- package/slides_agent/tools/EnsureRasterImage.py +157 -0
- package/slides_agent/tools/ExtractPptxTextInventory.py +104 -0
- package/slides_agent/tools/GenerateImage.py +189 -0
- package/slides_agent/tools/ImageSearch.py +127 -0
- package/slides_agent/tools/InsertNewSlides.py +393 -0
- package/slides_agent/tools/ManageTheme.py +112 -0
- package/slides_agent/tools/ModifySlide.py +563 -0
- package/slides_agent/tools/ReadSlide.py +26 -0
- package/slides_agent/tools/RearrangePptxSlidesFromTemplate.py +114 -0
- package/slides_agent/tools/RestoreSnapshot.py +89 -0
- package/slides_agent/tools/SlideScreenshot.py +66 -0
- package/slides_agent/tools/__init__.py +54 -0
- package/slides_agent/tools/__pycache__/ApplyPptxTextReplacements.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/BuildPptxFromHtmlSlides.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/CheckSlide.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/CheckSlideCanvasOverflow.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/CreateImageMontage.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/CreatePptxThumbnailGrid.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/DeleteSlide.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/DownloadImage.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/EnsureRasterImage.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/ExtractPptxTextInventory.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/GenerateImage.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/ImageSearch.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/InsertNewSlides.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/ManageTheme.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/ModifySlide.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/ReadSlide.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/RearrangePptxSlidesFromTemplate.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/RestoreSnapshot.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/SlideScreenshot.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/__init__.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/slide_file_utils.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/slide_html_utils.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/template_registry.cpython-312.pyc +0 -0
- package/slides_agent/tools/deck_utils.py +31 -0
- package/slides_agent/tools/html2pptx_runner.js +1183 -0
- package/slides_agent/tools/html_writer_instructions.md +149 -0
- package/slides_agent/tools/slide_file_utils.py +108 -0
- package/slides_agent/tools/slide_html_utils.py +354 -0
- package/slides_agent/tools/template_registry.py +55 -0
- package/swarm.py +82 -0
- package/video_generation_agent/__init__.py +1 -0
- package/video_generation_agent/__pycache__/__init__.cpython-312.pyc +0 -0
- package/video_generation_agent/__pycache__/video_generation_agent.cpython-312.pyc +0 -0
- package/video_generation_agent/instructions.md +178 -0
- package/video_generation_agent/tools/AddSubtitles.py +425 -0
- package/video_generation_agent/tools/CombineImages.py +166 -0
- package/video_generation_agent/tools/CombineVideos.py +113 -0
- package/video_generation_agent/tools/EditAudio.py +297 -0
- package/video_generation_agent/tools/EditImage.py +144 -0
- package/video_generation_agent/tools/EditVideoContent.py +369 -0
- package/video_generation_agent/tools/GenerateImage.py +133 -0
- package/video_generation_agent/tools/GenerateVideo.py +556 -0
- package/video_generation_agent/tools/TrimVideo.py +233 -0
- package/video_generation_agent/tools/__init__.py +1 -0
- package/video_generation_agent/tools/__pycache__/AddSubtitles.cpython-312.pyc +0 -0
- package/video_generation_agent/tools/__pycache__/CombineImages.cpython-312.pyc +0 -0
- package/video_generation_agent/tools/__pycache__/CombineVideos.cpython-312.pyc +0 -0
- package/video_generation_agent/tools/__pycache__/EditAudio.cpython-312.pyc +0 -0
- package/video_generation_agent/tools/__pycache__/EditImage.cpython-312.pyc +0 -0
- package/video_generation_agent/tools/__pycache__/EditVideoContent.cpython-312.pyc +0 -0
- package/video_generation_agent/tools/__pycache__/GenerateImage.cpython-312.pyc +0 -0
- package/video_generation_agent/tools/__pycache__/GenerateVideo.cpython-312.pyc +0 -0
- package/video_generation_agent/tools/__pycache__/TrimVideo.cpython-312.pyc +0 -0
- package/video_generation_agent/tools/utils/__init__.py +1 -0
- package/video_generation_agent/tools/utils/__pycache__/__init__.cpython-312.pyc +0 -0
- package/video_generation_agent/tools/utils/__pycache__/image_utils.cpython-312.pyc +0 -0
- package/video_generation_agent/tools/utils/__pycache__/video_utils.cpython-312.pyc +0 -0
- package/video_generation_agent/tools/utils/image_utils.py +174 -0
- package/video_generation_agent/tools/utils/video_utils.py +522 -0
- package/video_generation_agent/video_generation_agent.py +26 -0
- package/virtual_assistant/__init__.py +1 -0
- package/virtual_assistant/__pycache__/__init__.cpython-312.pyc +0 -0
- package/virtual_assistant/__pycache__/virtual_assistant.cpython-312.pyc +0 -0
- package/virtual_assistant/instructions.md +206 -0
- package/virtual_assistant/tools/AddLabelToEmail.py +154 -0
- package/virtual_assistant/tools/CheckEventsForDate.py +218 -0
- package/virtual_assistant/tools/CheckUnreadSlackMessages.py +216 -0
- package/virtual_assistant/tools/CreateCalendarEvent.py +261 -0
- package/virtual_assistant/tools/DeleteCalendarEvent.py +137 -0
- package/virtual_assistant/tools/DeleteDraft.py +95 -0
- package/virtual_assistant/tools/DraftEmail.py +239 -0
- package/virtual_assistant/tools/EditFile.py +113 -0
- package/virtual_assistant/tools/FindEmails.py +330 -0
- package/virtual_assistant/tools/GetCurrentTime.py +69 -0
- package/virtual_assistant/tools/GetSlackUserInfo.py +117 -0
- package/virtual_assistant/tools/ListDirectory.py +113 -0
- package/virtual_assistant/tools/ListSkills.py +94 -0
- package/virtual_assistant/tools/ManageLabels.py +295 -0
- package/virtual_assistant/tools/ProductSearch.py +254 -0
- package/virtual_assistant/tools/ReadEmail.py +251 -0
- package/virtual_assistant/tools/ReadFile.py +108 -0
- package/virtual_assistant/tools/ReadSlackMessages.py +191 -0
- package/virtual_assistant/tools/RemoveLabelFromEmail.py +137 -0
- package/virtual_assistant/tools/RescheduleCalendarEvent.py +227 -0
- package/virtual_assistant/tools/ScholarSearch.py +216 -0
- package/virtual_assistant/tools/SendDraft.py +101 -0
- package/virtual_assistant/tools/SendSlackMessage.py +148 -0
- package/virtual_assistant/tools/WriteFile.py +95 -0
- package/virtual_assistant/tools/__init__.py +1 -0
- package/virtual_assistant/tools/__pycache__/AddLabelToEmail.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/CheckEventsForDate.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/CheckUnreadSlackMessages.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/CreateCalendarEvent.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/DeleteCalendarEvent.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/DeleteDraft.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/DraftEmail.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/EditFile.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/FindEmails.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/GetCurrentTime.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/GetSlackUserInfo.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/ListDirectory.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/ListSkills.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/ManageLabels.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/ProductSearch.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/ReadEmail.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/ReadFile.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/ReadSlackMessages.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/RemoveLabelFromEmail.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/RescheduleCalendarEvent.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/ScholarSearch.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/SendDraft.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/SendSlackMessage.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/WriteFile.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/__init__.cpython-312.pyc +0 -0
- package/virtual_assistant/virtual_assistant.py +52 -0
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
"""Tool for trimming videos from start and/or end."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import subprocess
|
|
5
|
+
import asyncio
|
|
6
|
+
import cv2
|
|
7
|
+
from typing import Optional
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from pydantic import Field, field_validator, model_validator
|
|
11
|
+
from PIL import Image
|
|
12
|
+
|
|
13
|
+
from agency_swarm import BaseTool, ToolOutputText
|
|
14
|
+
|
|
15
|
+
from .utils.video_utils import (
|
|
16
|
+
get_videos_dir,
|
|
17
|
+
ensure_not_blank,
|
|
18
|
+
generate_spritesheet,
|
|
19
|
+
extract_last_frame,
|
|
20
|
+
create_image_output,
|
|
21
|
+
resolve_ffmpeg_executable,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class TrimVideo(BaseTool):
|
|
26
|
+
"""
|
|
27
|
+
Trim a video by removing seconds from the start and/or end.
|
|
28
|
+
|
|
29
|
+
Useful for removing unwanted intro/outro segments or adjusting video length.
|
|
30
|
+
|
|
31
|
+
Videos are saved to: mnt/{product_name}/generated_videos/
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
product_name: str = Field(
|
|
35
|
+
...,
|
|
36
|
+
description="Name of the product this video is for (e.g., 'Acme_Widget_Pro', 'Green_Tea_Extract'). Used to organize files into product-specific folders.",
|
|
37
|
+
)
|
|
38
|
+
input_video: str = Field(
|
|
39
|
+
...,
|
|
40
|
+
description=(
|
|
41
|
+
"The video to trim. Can be: "
|
|
42
|
+
"1) Video name without extension (searches generated_videos folder), "
|
|
43
|
+
"2) Full local path to video file."
|
|
44
|
+
),
|
|
45
|
+
)
|
|
46
|
+
output_name: str = Field(
|
|
47
|
+
...,
|
|
48
|
+
description="The name for the trimmed video file (without extension)",
|
|
49
|
+
)
|
|
50
|
+
trim_start: Optional[float] = Field(
|
|
51
|
+
default=None,
|
|
52
|
+
description="Seconds to trim from the start of the video (optional, defaults to 0.0 if not provided)",
|
|
53
|
+
)
|
|
54
|
+
trim_end: Optional[float] = Field(
|
|
55
|
+
default=None,
|
|
56
|
+
description="Seconds to trim from the end of the video (optional, defaults to 0.0 if not provided)",
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
@field_validator("input_video")
|
|
60
|
+
@classmethod
|
|
61
|
+
def _input_not_blank(cls, value: str) -> str:
|
|
62
|
+
return ensure_not_blank(value, "input_video")
|
|
63
|
+
|
|
64
|
+
@field_validator("output_name")
|
|
65
|
+
@classmethod
|
|
66
|
+
def _output_not_blank(cls, value: str) -> str:
|
|
67
|
+
return ensure_not_blank(value, "output_name")
|
|
68
|
+
|
|
69
|
+
@model_validator(mode='after')
|
|
70
|
+
def _validate_and_set_defaults(self):
|
|
71
|
+
"""Set defaults and validate that at least one trim parameter is provided (> 0)"""
|
|
72
|
+
# Set defaults
|
|
73
|
+
if self.trim_start is None:
|
|
74
|
+
self.trim_start = 0.0
|
|
75
|
+
if self.trim_end is None:
|
|
76
|
+
self.trim_end = 0.0
|
|
77
|
+
|
|
78
|
+
# Validate non-negative
|
|
79
|
+
if self.trim_start < 0:
|
|
80
|
+
raise ValueError("trim_start must be non-negative")
|
|
81
|
+
if self.trim_end < 0:
|
|
82
|
+
raise ValueError("trim_end must be non-negative")
|
|
83
|
+
|
|
84
|
+
# Ensure at least one is provided
|
|
85
|
+
if self.trim_start == 0.0 and self.trim_end == 0.0:
|
|
86
|
+
raise ValueError(
|
|
87
|
+
"At least one of trim_start or trim_end must be greater than 0. "
|
|
88
|
+
"Provide at least one trim value."
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
return self
|
|
92
|
+
|
|
93
|
+
async def run(self) -> list:
|
|
94
|
+
"""Trim the video and save with metadata."""
|
|
95
|
+
input_path = self._resolve_video_path()
|
|
96
|
+
videos_dir = get_videos_dir(self.product_name)
|
|
97
|
+
output_path = os.path.join(videos_dir, f"{self.output_name}.mp4")
|
|
98
|
+
|
|
99
|
+
loop = asyncio.get_event_loop()
|
|
100
|
+
await loop.run_in_executor(None, self._trim_video_blocking, input_path, output_path)
|
|
101
|
+
|
|
102
|
+
output = []
|
|
103
|
+
|
|
104
|
+
spritesheet_path = os.path.join(videos_dir, f"{self.output_name}_spritesheet.jpg")
|
|
105
|
+
spritesheet = await loop.run_in_executor(None, generate_spritesheet, output_path, spritesheet_path)
|
|
106
|
+
if spritesheet:
|
|
107
|
+
output.extend(create_image_output(spritesheet_path, f"{self.output_name}_spritesheet.jpg"))
|
|
108
|
+
|
|
109
|
+
thumbnail_path = os.path.join(videos_dir, f"{self.output_name}_thumbnail.jpg")
|
|
110
|
+
thumbnail = await loop.run_in_executor(None, self._extract_first_frame, output_path, thumbnail_path)
|
|
111
|
+
if thumbnail:
|
|
112
|
+
output.extend(create_image_output(thumbnail_path, f"{self.output_name}_thumbnail.jpg"))
|
|
113
|
+
|
|
114
|
+
last_frame_path = os.path.join(videos_dir, f"{self.output_name}_last_frame.jpg")
|
|
115
|
+
last_frame = await loop.run_in_executor(None, extract_last_frame, output_path, last_frame_path)
|
|
116
|
+
if last_frame:
|
|
117
|
+
output.extend(create_image_output(last_frame_path, f"{self.output_name}_last_frame.jpg"))
|
|
118
|
+
|
|
119
|
+
output.append(ToolOutputText(
|
|
120
|
+
type="text",
|
|
121
|
+
text=f"Video trimmed successfully!\nSaved to: `{self.output_name}.mp4`\nPath: {output_path}\nTrimmed: {self.trim_start}s from start, {self.trim_end}s from end"
|
|
122
|
+
))
|
|
123
|
+
|
|
124
|
+
return output
|
|
125
|
+
|
|
126
|
+
def _resolve_video_path(self) -> str:
|
|
127
|
+
"""Resolve input video to full path."""
|
|
128
|
+
# Try as full path first
|
|
129
|
+
path = Path(self.input_video).expanduser().resolve()
|
|
130
|
+
|
|
131
|
+
if path.exists():
|
|
132
|
+
return str(path)
|
|
133
|
+
|
|
134
|
+
# Try as video name without extension in generated_videos
|
|
135
|
+
videos_dir = get_videos_dir(self.product_name)
|
|
136
|
+
|
|
137
|
+
for ext in [".mp4", ".mov", ".avi", ".webm"]:
|
|
138
|
+
potential_path = os.path.join(videos_dir, f"{self.input_video}{ext}")
|
|
139
|
+
if os.path.exists(potential_path):
|
|
140
|
+
return potential_path
|
|
141
|
+
|
|
142
|
+
raise FileNotFoundError(
|
|
143
|
+
f"Video '{self.input_video}' not found in {videos_dir}. "
|
|
144
|
+
f"Tried extensions: .mp4, .mov, .avi, .webm"
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
def _trim_video_blocking(self, input_path: str, output_path: str) -> None:
|
|
148
|
+
"""Trim video using ffmpeg (blocking operation)."""
|
|
149
|
+
cap = cv2.VideoCapture(input_path)
|
|
150
|
+
fps = cap.get(cv2.CAP_PROP_FPS)
|
|
151
|
+
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
|
|
152
|
+
original_duration = total_frames / fps
|
|
153
|
+
cap.release()
|
|
154
|
+
|
|
155
|
+
output_duration = original_duration - self.trim_start - self.trim_end
|
|
156
|
+
|
|
157
|
+
if output_duration <= 0:
|
|
158
|
+
raise ValueError(
|
|
159
|
+
f"Invalid trim parameters: output duration would be {output_duration:.2f}s. "
|
|
160
|
+
f"Video duration is {original_duration:.2f}s. "
|
|
161
|
+
f"Reduce trim_start ({self.trim_start}s) and/or trim_end ({self.trim_end}s)."
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
# Using -ss (start time) and -t (duration) for precise trimming.
|
|
165
|
+
# -c copy would be fastest but may have keyframe issues, so we re-encode with H.264.
|
|
166
|
+
ffmpeg_executable = resolve_ffmpeg_executable()
|
|
167
|
+
ffmpeg_cmd = [
|
|
168
|
+
ffmpeg_executable,
|
|
169
|
+
"-y", # Overwrite output file if it exists
|
|
170
|
+
"-i", input_path, # Input file
|
|
171
|
+
"-ss", str(self.trim_start), # Start time
|
|
172
|
+
"-t", str(output_duration), # Duration
|
|
173
|
+
"-c:v", "libx264", # Video codec: H.264
|
|
174
|
+
"-preset", "medium", # Encoding preset (balance speed/quality)
|
|
175
|
+
"-crf", "23", # Constant Rate Factor (quality: 0-51, lower is better)
|
|
176
|
+
"-c:a", "aac", # Audio codec
|
|
177
|
+
"-b:a", "128k", # Audio bitrate
|
|
178
|
+
"-movflags", "+faststart", # Enable fast start for web playback
|
|
179
|
+
"-pix_fmt", "yuv420p", # Pixel format for compatibility
|
|
180
|
+
output_path
|
|
181
|
+
]
|
|
182
|
+
|
|
183
|
+
try:
|
|
184
|
+
subprocess.run(
|
|
185
|
+
ffmpeg_cmd,
|
|
186
|
+
stdout=subprocess.PIPE,
|
|
187
|
+
stderr=subprocess.PIPE,
|
|
188
|
+
text=True,
|
|
189
|
+
check=True
|
|
190
|
+
)
|
|
191
|
+
except subprocess.CalledProcessError as e:
|
|
192
|
+
raise RuntimeError(
|
|
193
|
+
f"ffmpeg failed to trim video. Error: {e.stderr}"
|
|
194
|
+
)
|
|
195
|
+
except FileNotFoundError:
|
|
196
|
+
raise RuntimeError(
|
|
197
|
+
"ffmpeg not found. Please install ffmpeg and ensure it's in your PATH. "
|
|
198
|
+
"Download from: https://ffmpeg.org/download.html"
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
def _extract_first_frame(self, video_path: str, output_path: str) -> Optional[object]:
|
|
202
|
+
"""Extract the first frame from video as thumbnail."""
|
|
203
|
+
cap = cv2.VideoCapture(video_path)
|
|
204
|
+
ret, frame = cap.read()
|
|
205
|
+
cap.release()
|
|
206
|
+
|
|
207
|
+
if not ret:
|
|
208
|
+
return None
|
|
209
|
+
|
|
210
|
+
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
|
211
|
+
thumbnail_image = Image.fromarray(frame_rgb)
|
|
212
|
+
thumbnail_image.save(output_path)
|
|
213
|
+
|
|
214
|
+
return thumbnail_image
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
if __name__ == "__main__":
|
|
218
|
+
# Example: Trim only from start (trim_end defaults to 0.0)
|
|
219
|
+
tool = TrimVideo(
|
|
220
|
+
product_name="Test_Product",
|
|
221
|
+
input_video="test_video", # Will look for test_video.mp4 in generated_videos
|
|
222
|
+
output_name="test_video_trimmed",
|
|
223
|
+
# trim_start=1.0, # Trim 1 second from start
|
|
224
|
+
trim_end=1.0
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
try:
|
|
228
|
+
result = asyncio.run(tool.run())
|
|
229
|
+
print("\nTrim complete!")
|
|
230
|
+
print(result)
|
|
231
|
+
except Exception as exc:
|
|
232
|
+
print(f"Video trim failed: {exc}")
|
|
233
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Tools for the video generation agent."""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Utility helpers for video generation tools."""
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import io
|
|
3
|
+
import base64
|
|
4
|
+
import logging
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
import asyncio
|
|
7
|
+
from PIL import Image
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
MODEL_NAME = "gemini-2.5-flash-image"
|
|
12
|
+
|
|
13
|
+
if os.path.isfile("/.dockerenv"):
|
|
14
|
+
MNT_DIR = Path("/app/mnt")
|
|
15
|
+
else:
|
|
16
|
+
MNT_DIR = Path(__file__).parent.parent.parent.parent / "mnt"
|
|
17
|
+
|
|
18
|
+
IMAGES_DIR = str(MNT_DIR / "generated_images")
|
|
19
|
+
|
|
20
|
+
OUTPUT_FORMAT = "png"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def get_images_dir(product_name: str) -> str:
|
|
24
|
+
"""Return (and create) the images directory for a specific product."""
|
|
25
|
+
images_dir = MNT_DIR / product_name / "generated_images"
|
|
26
|
+
images_dir.mkdir(parents=True, exist_ok=True)
|
|
27
|
+
return str(images_dir)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def create_filename(file_name, variant_num, num_variants, output_format):
|
|
31
|
+
if num_variants == 1:
|
|
32
|
+
image_name = file_name
|
|
33
|
+
else:
|
|
34
|
+
image_name = f"{file_name}_variant_{variant_num}"
|
|
35
|
+
filename = f"{image_name}.{output_format}"
|
|
36
|
+
return image_name, filename
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def load_image_by_name(image_name, images_dir, extensions=None):
|
|
40
|
+
"""Load an image by name, trying common extensions in order."""
|
|
41
|
+
if extensions is None:
|
|
42
|
+
extensions = ['.png', '.jpg', '.jpeg', '.webp']
|
|
43
|
+
|
|
44
|
+
for ext in extensions:
|
|
45
|
+
potential_path = os.path.join(images_dir, f"{image_name}{ext}")
|
|
46
|
+
if os.path.exists(potential_path):
|
|
47
|
+
try:
|
|
48
|
+
image = Image.open(potential_path)
|
|
49
|
+
return image, potential_path, None
|
|
50
|
+
except Exception as e:
|
|
51
|
+
return None, None, f"Error loading image {potential_path}: {str(e)}"
|
|
52
|
+
|
|
53
|
+
return None, None, f"Error: Image file not found: {image_name} (tried {', '.join(extensions)})"
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def extract_image_from_response(response):
|
|
57
|
+
"""Extract the first image and any text from a Gemini API response."""
|
|
58
|
+
image = None
|
|
59
|
+
text_output = ""
|
|
60
|
+
|
|
61
|
+
for part in response.candidates[0].content.parts:
|
|
62
|
+
if part.text is not None:
|
|
63
|
+
text_output += part.text
|
|
64
|
+
elif part.inline_data is not None:
|
|
65
|
+
image = Image.open(io.BytesIO(part.inline_data.data))
|
|
66
|
+
|
|
67
|
+
return image, text_output
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def extract_image_parts_from_response(response):
|
|
71
|
+
"""Extract raw image bytes from a Gemini API response."""
|
|
72
|
+
return [
|
|
73
|
+
part.inline_data.data
|
|
74
|
+
for part in response.candidates[0].content.parts
|
|
75
|
+
if part.inline_data
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def extract_usage_metadata(response):
|
|
80
|
+
usage_metadata = getattr(response, "usage_metadata", {}) or {}
|
|
81
|
+
if usage_metadata and not isinstance(usage_metadata, dict):
|
|
82
|
+
if hasattr(usage_metadata, "model_dump"):
|
|
83
|
+
usage_metadata = usage_metadata.model_dump()
|
|
84
|
+
elif hasattr(usage_metadata, "__dict__"):
|
|
85
|
+
usage_metadata = vars(usage_metadata)
|
|
86
|
+
else:
|
|
87
|
+
try:
|
|
88
|
+
usage_metadata = dict(usage_metadata)
|
|
89
|
+
except (TypeError, ValueError):
|
|
90
|
+
usage_metadata = {}
|
|
91
|
+
return usage_metadata
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def split_results_and_usage(raw_results):
|
|
95
|
+
results = []
|
|
96
|
+
total_prompt_tokens = 0.0
|
|
97
|
+
total_candidate_tokens = 0.0
|
|
98
|
+
|
|
99
|
+
for item in raw_results:
|
|
100
|
+
result = dict(item)
|
|
101
|
+
total_prompt_tokens += float(result.pop("prompt_tokens", 0.0) or 0.0)
|
|
102
|
+
total_candidate_tokens += float(result.pop("candidate_tokens", 0.0) or 0.0)
|
|
103
|
+
results.append(result)
|
|
104
|
+
|
|
105
|
+
usage_metadata = {
|
|
106
|
+
"prompt_token_count": total_prompt_tokens,
|
|
107
|
+
"candidates_token_count": total_candidate_tokens,
|
|
108
|
+
}
|
|
109
|
+
return results, usage_metadata
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def process_variant_result(variant_num, image, file_name, num_variants, compress_func, images_dir=None):
|
|
113
|
+
"""Save a variant image and return its result dict."""
|
|
114
|
+
save_dir = images_dir if images_dir is not None else IMAGES_DIR
|
|
115
|
+
image_name, filename = create_filename(file_name, variant_num, num_variants, OUTPUT_FORMAT)
|
|
116
|
+
filepath = os.path.join(save_dir, filename)
|
|
117
|
+
image.save(filepath, OUTPUT_FORMAT)
|
|
118
|
+
compressed_b64 = compress_func(image)
|
|
119
|
+
return {
|
|
120
|
+
"variant": variant_num,
|
|
121
|
+
"file_path": filepath,
|
|
122
|
+
"image_name": image_name,
|
|
123
|
+
"base64": compressed_b64,
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
async def run_parallel_variants(variant_func, num_variants):
|
|
128
|
+
"""Run variant_func for each variant concurrently in a thread pool."""
|
|
129
|
+
loop = asyncio.get_event_loop()
|
|
130
|
+
tasks = [loop.run_in_executor(None, variant_func, i + 1) for i in range(num_variants)]
|
|
131
|
+
completed = await asyncio.gather(*tasks, return_exceptions=True)
|
|
132
|
+
return [r for r in completed if r is not None and not isinstance(r, Exception)]
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def compress_image_for_base64(image: Image.Image, max_size: int = 1024) -> str:
|
|
136
|
+
"""Resize and JPEG-compress an image, returning a base64-encoded string."""
|
|
137
|
+
if image.mode in ("RGBA", "P"):
|
|
138
|
+
image = image.convert("RGB")
|
|
139
|
+
|
|
140
|
+
width, height = image.size
|
|
141
|
+
if max(width, height) > max_size:
|
|
142
|
+
if width > height:
|
|
143
|
+
new_width = max_size
|
|
144
|
+
new_height = int(height * (max_size / width))
|
|
145
|
+
else:
|
|
146
|
+
new_height = max_size
|
|
147
|
+
new_width = int(width * (max_size / height))
|
|
148
|
+
image = image.resize((new_width, new_height), Image.Resampling.LANCZOS)
|
|
149
|
+
|
|
150
|
+
buffer = io.BytesIO()
|
|
151
|
+
image.save(buffer, format="JPEG", quality=85)
|
|
152
|
+
return base64.b64encode(buffer.getvalue()).decode()
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def combine_image_parts(image_parts):
|
|
156
|
+
"""Combine multiple raw image parts into a single horizontally-stitched image."""
|
|
157
|
+
if not image_parts:
|
|
158
|
+
return None
|
|
159
|
+
|
|
160
|
+
images = [Image.open(io.BytesIO(part)) for part in image_parts]
|
|
161
|
+
|
|
162
|
+
if len(images) == 1:
|
|
163
|
+
return images[0]
|
|
164
|
+
|
|
165
|
+
total_width = sum(img.width for img in images)
|
|
166
|
+
max_height = max(img.height for img in images)
|
|
167
|
+
combined = Image.new('RGB', (total_width, max_height))
|
|
168
|
+
|
|
169
|
+
x_offset = 0
|
|
170
|
+
for img in images:
|
|
171
|
+
combined.paste(img, (x_offset, 0))
|
|
172
|
+
x_offset += img.width
|
|
173
|
+
|
|
174
|
+
return combined
|