ai-parrot 0.17.2__cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
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.
- agentui/.prettierrc +15 -0
- agentui/QUICKSTART.md +272 -0
- agentui/README.md +59 -0
- agentui/env.example +16 -0
- agentui/jsconfig.json +14 -0
- agentui/package-lock.json +4242 -0
- agentui/package.json +34 -0
- agentui/scripts/postinstall/apply-patches.mjs +260 -0
- agentui/src/app.css +61 -0
- agentui/src/app.d.ts +13 -0
- agentui/src/app.html +12 -0
- agentui/src/components/LoadingSpinner.svelte +64 -0
- agentui/src/components/ThemeSwitcher.svelte +159 -0
- agentui/src/components/index.js +4 -0
- agentui/src/lib/api/bots.ts +60 -0
- agentui/src/lib/api/chat.ts +22 -0
- agentui/src/lib/api/http.ts +25 -0
- agentui/src/lib/components/BotCard.svelte +33 -0
- agentui/src/lib/components/ChatBubble.svelte +63 -0
- agentui/src/lib/components/Toast.svelte +21 -0
- agentui/src/lib/config.ts +20 -0
- agentui/src/lib/stores/auth.svelte.ts +73 -0
- agentui/src/lib/stores/theme.svelte.js +64 -0
- agentui/src/lib/stores/toast.svelte.ts +31 -0
- agentui/src/lib/utils/conversation.ts +39 -0
- agentui/src/routes/+layout.svelte +20 -0
- agentui/src/routes/+page.svelte +232 -0
- agentui/src/routes/login/+page.svelte +200 -0
- agentui/src/routes/talk/[agentId]/+page.svelte +297 -0
- agentui/src/routes/talk/[agentId]/+page.ts +7 -0
- agentui/static/README.md +1 -0
- agentui/svelte.config.js +11 -0
- agentui/tailwind.config.ts +53 -0
- agentui/tsconfig.json +3 -0
- agentui/vite.config.ts +10 -0
- ai_parrot-0.17.2.dist-info/METADATA +472 -0
- ai_parrot-0.17.2.dist-info/RECORD +535 -0
- ai_parrot-0.17.2.dist-info/WHEEL +6 -0
- ai_parrot-0.17.2.dist-info/entry_points.txt +2 -0
- ai_parrot-0.17.2.dist-info/licenses/LICENSE +21 -0
- ai_parrot-0.17.2.dist-info/top_level.txt +6 -0
- crew-builder/.prettierrc +15 -0
- crew-builder/QUICKSTART.md +259 -0
- crew-builder/README.md +113 -0
- crew-builder/env.example +17 -0
- crew-builder/jsconfig.json +14 -0
- crew-builder/package-lock.json +4182 -0
- crew-builder/package.json +37 -0
- crew-builder/scripts/postinstall/apply-patches.mjs +260 -0
- crew-builder/src/app.css +62 -0
- crew-builder/src/app.d.ts +13 -0
- crew-builder/src/app.html +12 -0
- crew-builder/src/components/LoadingSpinner.svelte +64 -0
- crew-builder/src/components/ThemeSwitcher.svelte +149 -0
- crew-builder/src/components/index.js +9 -0
- crew-builder/src/lib/api/bots.ts +60 -0
- crew-builder/src/lib/api/chat.ts +80 -0
- crew-builder/src/lib/api/client.ts +56 -0
- crew-builder/src/lib/api/crew/crew.ts +136 -0
- crew-builder/src/lib/api/index.ts +5 -0
- crew-builder/src/lib/api/o365/auth.ts +65 -0
- crew-builder/src/lib/auth/auth.ts +54 -0
- crew-builder/src/lib/components/AgentNode.svelte +43 -0
- crew-builder/src/lib/components/BotCard.svelte +33 -0
- crew-builder/src/lib/components/ChatBubble.svelte +67 -0
- crew-builder/src/lib/components/ConfigPanel.svelte +278 -0
- crew-builder/src/lib/components/JsonTreeNode.svelte +76 -0
- crew-builder/src/lib/components/JsonViewer.svelte +24 -0
- crew-builder/src/lib/components/MarkdownEditor.svelte +48 -0
- crew-builder/src/lib/components/ThemeToggle.svelte +36 -0
- crew-builder/src/lib/components/Toast.svelte +67 -0
- crew-builder/src/lib/components/Toolbar.svelte +157 -0
- crew-builder/src/lib/components/index.ts +10 -0
- crew-builder/src/lib/config.ts +8 -0
- crew-builder/src/lib/stores/auth.svelte.ts +228 -0
- crew-builder/src/lib/stores/crewStore.ts +369 -0
- crew-builder/src/lib/stores/theme.svelte.js +145 -0
- crew-builder/src/lib/stores/toast.svelte.ts +69 -0
- crew-builder/src/lib/utils/conversation.ts +39 -0
- crew-builder/src/lib/utils/markdown.ts +122 -0
- crew-builder/src/lib/utils/talkHistory.ts +47 -0
- crew-builder/src/routes/+layout.svelte +20 -0
- crew-builder/src/routes/+page.svelte +539 -0
- crew-builder/src/routes/agents/+page.svelte +247 -0
- crew-builder/src/routes/agents/[agentId]/+page.svelte +288 -0
- crew-builder/src/routes/agents/[agentId]/+page.ts +7 -0
- crew-builder/src/routes/builder/+page.svelte +204 -0
- crew-builder/src/routes/crew/ask/+page.svelte +1052 -0
- crew-builder/src/routes/crew/ask/+page.ts +1 -0
- crew-builder/src/routes/integrations/o365/+page.svelte +304 -0
- crew-builder/src/routes/login/+page.svelte +197 -0
- crew-builder/src/routes/talk/[agentId]/+page.svelte +487 -0
- crew-builder/src/routes/talk/[agentId]/+page.ts +7 -0
- crew-builder/static/README.md +1 -0
- crew-builder/svelte.config.js +11 -0
- crew-builder/tailwind.config.ts +53 -0
- crew-builder/tsconfig.json +3 -0
- crew-builder/vite.config.ts +10 -0
- mcp_servers/calculator_server.py +309 -0
- parrot/__init__.py +27 -0
- parrot/__pycache__/__init__.cpython-310.pyc +0 -0
- parrot/__pycache__/version.cpython-310.pyc +0 -0
- parrot/_version.py +34 -0
- parrot/a2a/__init__.py +48 -0
- parrot/a2a/client.py +658 -0
- parrot/a2a/discovery.py +89 -0
- parrot/a2a/mixin.py +257 -0
- parrot/a2a/models.py +376 -0
- parrot/a2a/server.py +770 -0
- parrot/agents/__init__.py +29 -0
- parrot/bots/__init__.py +12 -0
- parrot/bots/a2a_agent.py +19 -0
- parrot/bots/abstract.py +3139 -0
- parrot/bots/agent.py +1129 -0
- parrot/bots/basic.py +9 -0
- parrot/bots/chatbot.py +669 -0
- parrot/bots/data.py +1618 -0
- parrot/bots/database/__init__.py +5 -0
- parrot/bots/database/abstract.py +3071 -0
- parrot/bots/database/cache.py +286 -0
- parrot/bots/database/models.py +468 -0
- parrot/bots/database/prompts.py +154 -0
- parrot/bots/database/retries.py +98 -0
- parrot/bots/database/router.py +269 -0
- parrot/bots/database/sql.py +41 -0
- parrot/bots/db/__init__.py +6 -0
- parrot/bots/db/abstract.py +556 -0
- parrot/bots/db/bigquery.py +602 -0
- parrot/bots/db/cache.py +85 -0
- parrot/bots/db/documentdb.py +668 -0
- parrot/bots/db/elastic.py +1014 -0
- parrot/bots/db/influx.py +898 -0
- parrot/bots/db/mock.py +96 -0
- parrot/bots/db/multi.py +783 -0
- parrot/bots/db/prompts.py +185 -0
- parrot/bots/db/sql.py +1255 -0
- parrot/bots/db/tools.py +212 -0
- parrot/bots/document.py +680 -0
- parrot/bots/hrbot.py +15 -0
- parrot/bots/kb.py +170 -0
- parrot/bots/mcp.py +36 -0
- parrot/bots/orchestration/README.md +463 -0
- parrot/bots/orchestration/__init__.py +1 -0
- parrot/bots/orchestration/agent.py +155 -0
- parrot/bots/orchestration/crew.py +3330 -0
- parrot/bots/orchestration/fsm.py +1179 -0
- parrot/bots/orchestration/hr.py +434 -0
- parrot/bots/orchestration/storage/__init__.py +4 -0
- parrot/bots/orchestration/storage/memory.py +100 -0
- parrot/bots/orchestration/storage/mixin.py +119 -0
- parrot/bots/orchestration/verify.py +202 -0
- parrot/bots/product.py +204 -0
- parrot/bots/prompts/__init__.py +96 -0
- parrot/bots/prompts/agents.py +155 -0
- parrot/bots/prompts/data.py +216 -0
- parrot/bots/prompts/output_generation.py +8 -0
- parrot/bots/scraper/__init__.py +3 -0
- parrot/bots/scraper/models.py +122 -0
- parrot/bots/scraper/scraper.py +1173 -0
- parrot/bots/scraper/templates.py +115 -0
- parrot/bots/stores/__init__.py +5 -0
- parrot/bots/stores/local.py +172 -0
- parrot/bots/webdev.py +81 -0
- parrot/cli.py +17 -0
- parrot/clients/__init__.py +16 -0
- parrot/clients/base.py +1491 -0
- parrot/clients/claude.py +1191 -0
- parrot/clients/factory.py +129 -0
- parrot/clients/google.py +4567 -0
- parrot/clients/gpt.py +1975 -0
- parrot/clients/grok.py +432 -0
- parrot/clients/groq.py +986 -0
- parrot/clients/hf.py +582 -0
- parrot/clients/models.py +18 -0
- parrot/conf.py +395 -0
- parrot/embeddings/__init__.py +9 -0
- parrot/embeddings/base.py +157 -0
- parrot/embeddings/google.py +98 -0
- parrot/embeddings/huggingface.py +74 -0
- parrot/embeddings/openai.py +84 -0
- parrot/embeddings/processor.py +88 -0
- parrot/exceptions.c +13868 -0
- parrot/exceptions.cpython-310-x86_64-linux-gnu.so +0 -0
- parrot/exceptions.pxd +22 -0
- parrot/exceptions.pxi +15 -0
- parrot/exceptions.pyx +44 -0
- parrot/generators/__init__.py +29 -0
- parrot/generators/base.py +200 -0
- parrot/generators/html.py +293 -0
- parrot/generators/react.py +205 -0
- parrot/generators/streamlit.py +203 -0
- parrot/generators/template.py +105 -0
- parrot/handlers/__init__.py +4 -0
- parrot/handlers/agent.py +861 -0
- parrot/handlers/agents/__init__.py +1 -0
- parrot/handlers/agents/abstract.py +900 -0
- parrot/handlers/bots.py +338 -0
- parrot/handlers/chat.py +915 -0
- parrot/handlers/creation.sql +192 -0
- parrot/handlers/crew/ARCHITECTURE.md +362 -0
- parrot/handlers/crew/README_BOTMANAGER_PERSISTENCE.md +303 -0
- parrot/handlers/crew/README_REDIS_PERSISTENCE.md +366 -0
- parrot/handlers/crew/__init__.py +0 -0
- parrot/handlers/crew/handler.py +801 -0
- parrot/handlers/crew/models.py +229 -0
- parrot/handlers/crew/redis_persistence.py +523 -0
- parrot/handlers/jobs/__init__.py +10 -0
- parrot/handlers/jobs/job.py +384 -0
- parrot/handlers/jobs/mixin.py +627 -0
- parrot/handlers/jobs/models.py +115 -0
- parrot/handlers/jobs/worker.py +31 -0
- parrot/handlers/models.py +596 -0
- parrot/handlers/o365_auth.py +105 -0
- parrot/handlers/stream.py +337 -0
- parrot/interfaces/__init__.py +6 -0
- parrot/interfaces/aws.py +143 -0
- parrot/interfaces/credentials.py +113 -0
- parrot/interfaces/database.py +27 -0
- parrot/interfaces/google.py +1123 -0
- parrot/interfaces/hierarchy.py +1227 -0
- parrot/interfaces/http.py +651 -0
- parrot/interfaces/images/__init__.py +0 -0
- parrot/interfaces/images/plugins/__init__.py +24 -0
- parrot/interfaces/images/plugins/abstract.py +58 -0
- parrot/interfaces/images/plugins/analisys.py +148 -0
- parrot/interfaces/images/plugins/classify.py +150 -0
- parrot/interfaces/images/plugins/classifybase.py +182 -0
- parrot/interfaces/images/plugins/detect.py +150 -0
- parrot/interfaces/images/plugins/exif.py +1103 -0
- parrot/interfaces/images/plugins/hash.py +52 -0
- parrot/interfaces/images/plugins/vision.py +104 -0
- parrot/interfaces/images/plugins/yolo.py +66 -0
- parrot/interfaces/images/plugins/zerodetect.py +197 -0
- parrot/interfaces/o365.py +978 -0
- parrot/interfaces/onedrive.py +822 -0
- parrot/interfaces/sharepoint.py +1435 -0
- parrot/interfaces/soap.py +257 -0
- parrot/loaders/__init__.py +8 -0
- parrot/loaders/abstract.py +1131 -0
- parrot/loaders/audio.py +199 -0
- parrot/loaders/basepdf.py +53 -0
- parrot/loaders/basevideo.py +1568 -0
- parrot/loaders/csv.py +409 -0
- parrot/loaders/docx.py +116 -0
- parrot/loaders/epubloader.py +316 -0
- parrot/loaders/excel.py +199 -0
- parrot/loaders/factory.py +55 -0
- parrot/loaders/files/__init__.py +0 -0
- parrot/loaders/files/abstract.py +39 -0
- parrot/loaders/files/html.py +26 -0
- parrot/loaders/files/text.py +63 -0
- parrot/loaders/html.py +152 -0
- parrot/loaders/markdown.py +442 -0
- parrot/loaders/pdf.py +373 -0
- parrot/loaders/pdfmark.py +320 -0
- parrot/loaders/pdftables.py +506 -0
- parrot/loaders/ppt.py +476 -0
- parrot/loaders/qa.py +63 -0
- parrot/loaders/splitters/__init__.py +10 -0
- parrot/loaders/splitters/base.py +138 -0
- parrot/loaders/splitters/md.py +228 -0
- parrot/loaders/splitters/token.py +143 -0
- parrot/loaders/txt.py +26 -0
- parrot/loaders/video.py +89 -0
- parrot/loaders/videolocal.py +218 -0
- parrot/loaders/videounderstanding.py +377 -0
- parrot/loaders/vimeo.py +167 -0
- parrot/loaders/web.py +599 -0
- parrot/loaders/youtube.py +504 -0
- parrot/manager/__init__.py +5 -0
- parrot/manager/manager.py +1030 -0
- parrot/mcp/__init__.py +28 -0
- parrot/mcp/adapter.py +105 -0
- parrot/mcp/cli.py +174 -0
- parrot/mcp/client.py +119 -0
- parrot/mcp/config.py +75 -0
- parrot/mcp/integration.py +842 -0
- parrot/mcp/oauth.py +933 -0
- parrot/mcp/server.py +225 -0
- parrot/mcp/transports/__init__.py +3 -0
- parrot/mcp/transports/base.py +279 -0
- parrot/mcp/transports/grpc_session.py +163 -0
- parrot/mcp/transports/http.py +312 -0
- parrot/mcp/transports/mcp.proto +108 -0
- parrot/mcp/transports/quic.py +1082 -0
- parrot/mcp/transports/sse.py +330 -0
- parrot/mcp/transports/stdio.py +309 -0
- parrot/mcp/transports/unix.py +395 -0
- parrot/mcp/transports/websocket.py +547 -0
- parrot/memory/__init__.py +16 -0
- parrot/memory/abstract.py +209 -0
- parrot/memory/agent.py +32 -0
- parrot/memory/cache.py +175 -0
- parrot/memory/core.py +555 -0
- parrot/memory/file.py +153 -0
- parrot/memory/mem.py +131 -0
- parrot/memory/redis.py +613 -0
- parrot/models/__init__.py +46 -0
- parrot/models/basic.py +118 -0
- parrot/models/compliance.py +208 -0
- parrot/models/crew.py +395 -0
- parrot/models/detections.py +654 -0
- parrot/models/generation.py +85 -0
- parrot/models/google.py +223 -0
- parrot/models/groq.py +23 -0
- parrot/models/openai.py +30 -0
- parrot/models/outputs.py +285 -0
- parrot/models/responses.py +938 -0
- parrot/notifications/__init__.py +743 -0
- parrot/openapi/__init__.py +3 -0
- parrot/openapi/components.yaml +641 -0
- parrot/openapi/config.py +322 -0
- parrot/outputs/__init__.py +32 -0
- parrot/outputs/formats/__init__.py +108 -0
- parrot/outputs/formats/altair.py +359 -0
- parrot/outputs/formats/application.py +122 -0
- parrot/outputs/formats/base.py +351 -0
- parrot/outputs/formats/bokeh.py +356 -0
- parrot/outputs/formats/card.py +424 -0
- parrot/outputs/formats/chart.py +436 -0
- parrot/outputs/formats/d3.py +255 -0
- parrot/outputs/formats/echarts.py +310 -0
- parrot/outputs/formats/generators/__init__.py +0 -0
- parrot/outputs/formats/generators/abstract.py +61 -0
- parrot/outputs/formats/generators/panel.py +145 -0
- parrot/outputs/formats/generators/streamlit.py +86 -0
- parrot/outputs/formats/generators/terminal.py +63 -0
- parrot/outputs/formats/holoviews.py +310 -0
- parrot/outputs/formats/html.py +147 -0
- parrot/outputs/formats/jinja2.py +46 -0
- parrot/outputs/formats/json.py +87 -0
- parrot/outputs/formats/map.py +933 -0
- parrot/outputs/formats/markdown.py +172 -0
- parrot/outputs/formats/matplotlib.py +237 -0
- parrot/outputs/formats/mixins/__init__.py +0 -0
- parrot/outputs/formats/mixins/emaps.py +855 -0
- parrot/outputs/formats/plotly.py +341 -0
- parrot/outputs/formats/seaborn.py +310 -0
- parrot/outputs/formats/table.py +397 -0
- parrot/outputs/formats/template_report.py +138 -0
- parrot/outputs/formats/yaml.py +125 -0
- parrot/outputs/formatter.py +152 -0
- parrot/outputs/templates/__init__.py +95 -0
- parrot/pipelines/__init__.py +0 -0
- parrot/pipelines/abstract.py +210 -0
- parrot/pipelines/detector.py +124 -0
- parrot/pipelines/models.py +90 -0
- parrot/pipelines/planogram.py +3002 -0
- parrot/pipelines/table.sql +97 -0
- parrot/plugins/__init__.py +106 -0
- parrot/plugins/importer.py +80 -0
- parrot/py.typed +0 -0
- parrot/registry/__init__.py +18 -0
- parrot/registry/registry.py +594 -0
- parrot/scheduler/__init__.py +1189 -0
- parrot/scheduler/models.py +60 -0
- parrot/security/__init__.py +16 -0
- parrot/security/prompt_injection.py +268 -0
- parrot/security/security_events.sql +25 -0
- parrot/services/__init__.py +1 -0
- parrot/services/mcp/__init__.py +8 -0
- parrot/services/mcp/config.py +13 -0
- parrot/services/mcp/server.py +295 -0
- parrot/services/o365_remote_auth.py +235 -0
- parrot/stores/__init__.py +7 -0
- parrot/stores/abstract.py +352 -0
- parrot/stores/arango.py +1090 -0
- parrot/stores/bigquery.py +1377 -0
- parrot/stores/cache.py +106 -0
- parrot/stores/empty.py +10 -0
- parrot/stores/faiss_store.py +1157 -0
- parrot/stores/kb/__init__.py +9 -0
- parrot/stores/kb/abstract.py +68 -0
- parrot/stores/kb/cache.py +165 -0
- parrot/stores/kb/doc.py +325 -0
- parrot/stores/kb/hierarchy.py +346 -0
- parrot/stores/kb/local.py +457 -0
- parrot/stores/kb/prompt.py +28 -0
- parrot/stores/kb/redis.py +659 -0
- parrot/stores/kb/store.py +115 -0
- parrot/stores/kb/user.py +374 -0
- parrot/stores/models.py +59 -0
- parrot/stores/pgvector.py +3 -0
- parrot/stores/postgres.py +2853 -0
- parrot/stores/utils/__init__.py +0 -0
- parrot/stores/utils/chunking.py +197 -0
- parrot/telemetry/__init__.py +3 -0
- parrot/telemetry/mixin.py +111 -0
- parrot/template/__init__.py +3 -0
- parrot/template/engine.py +259 -0
- parrot/tools/__init__.py +23 -0
- parrot/tools/abstract.py +644 -0
- parrot/tools/agent.py +363 -0
- parrot/tools/arangodbsearch.py +537 -0
- parrot/tools/arxiv_tool.py +188 -0
- parrot/tools/calculator/__init__.py +3 -0
- parrot/tools/calculator/operations/__init__.py +38 -0
- parrot/tools/calculator/operations/calculus.py +80 -0
- parrot/tools/calculator/operations/statistics.py +76 -0
- parrot/tools/calculator/tool.py +150 -0
- parrot/tools/cloudwatch.py +988 -0
- parrot/tools/codeinterpreter/__init__.py +127 -0
- parrot/tools/codeinterpreter/executor.py +371 -0
- parrot/tools/codeinterpreter/internals.py +473 -0
- parrot/tools/codeinterpreter/models.py +643 -0
- parrot/tools/codeinterpreter/prompts.py +224 -0
- parrot/tools/codeinterpreter/tool.py +664 -0
- parrot/tools/company_info/__init__.py +6 -0
- parrot/tools/company_info/tool.py +1138 -0
- parrot/tools/correlationanalysis.py +437 -0
- parrot/tools/database/abstract.py +286 -0
- parrot/tools/database/bq.py +115 -0
- parrot/tools/database/cache.py +284 -0
- parrot/tools/database/models.py +95 -0
- parrot/tools/database/pg.py +343 -0
- parrot/tools/databasequery.py +1159 -0
- parrot/tools/db.py +1800 -0
- parrot/tools/ddgo.py +370 -0
- parrot/tools/decorators.py +271 -0
- parrot/tools/dftohtml.py +282 -0
- parrot/tools/document.py +549 -0
- parrot/tools/ecs.py +819 -0
- parrot/tools/edareport.py +368 -0
- parrot/tools/elasticsearch.py +1049 -0
- parrot/tools/employees.py +462 -0
- parrot/tools/epson/__init__.py +96 -0
- parrot/tools/excel.py +683 -0
- parrot/tools/file/__init__.py +13 -0
- parrot/tools/file/abstract.py +76 -0
- parrot/tools/file/gcs.py +378 -0
- parrot/tools/file/local.py +284 -0
- parrot/tools/file/s3.py +511 -0
- parrot/tools/file/tmp.py +309 -0
- parrot/tools/file/tool.py +501 -0
- parrot/tools/file_reader.py +129 -0
- parrot/tools/flowtask/__init__.py +19 -0
- parrot/tools/flowtask/tool.py +761 -0
- parrot/tools/gittoolkit.py +508 -0
- parrot/tools/google/__init__.py +18 -0
- parrot/tools/google/base.py +169 -0
- parrot/tools/google/tools.py +1251 -0
- parrot/tools/googlelocation.py +5 -0
- parrot/tools/googleroutes.py +5 -0
- parrot/tools/googlesearch.py +5 -0
- parrot/tools/googlesitesearch.py +5 -0
- parrot/tools/googlevoice.py +2 -0
- parrot/tools/gvoice.py +695 -0
- parrot/tools/ibisworld/README.md +225 -0
- parrot/tools/ibisworld/__init__.py +11 -0
- parrot/tools/ibisworld/tool.py +366 -0
- parrot/tools/jiratoolkit.py +1718 -0
- parrot/tools/manager.py +1098 -0
- parrot/tools/math.py +152 -0
- parrot/tools/metadata.py +476 -0
- parrot/tools/msteams.py +1621 -0
- parrot/tools/msword.py +635 -0
- parrot/tools/multidb.py +580 -0
- parrot/tools/multistoresearch.py +369 -0
- parrot/tools/networkninja.py +167 -0
- parrot/tools/nextstop/__init__.py +4 -0
- parrot/tools/nextstop/base.py +286 -0
- parrot/tools/nextstop/employee.py +733 -0
- parrot/tools/nextstop/store.py +462 -0
- parrot/tools/notification.py +435 -0
- parrot/tools/o365/__init__.py +42 -0
- parrot/tools/o365/base.py +295 -0
- parrot/tools/o365/bundle.py +522 -0
- parrot/tools/o365/events.py +554 -0
- parrot/tools/o365/mail.py +992 -0
- parrot/tools/o365/onedrive.py +497 -0
- parrot/tools/o365/sharepoint.py +641 -0
- parrot/tools/openapi_toolkit.py +904 -0
- parrot/tools/openweather.py +527 -0
- parrot/tools/pdfprint.py +1001 -0
- parrot/tools/powerbi.py +518 -0
- parrot/tools/powerpoint.py +1113 -0
- parrot/tools/pricestool.py +146 -0
- parrot/tools/products/__init__.py +246 -0
- parrot/tools/prophet_tool.py +171 -0
- parrot/tools/pythonpandas.py +630 -0
- parrot/tools/pythonrepl.py +910 -0
- parrot/tools/qsource.py +436 -0
- parrot/tools/querytoolkit.py +395 -0
- parrot/tools/quickeda.py +827 -0
- parrot/tools/resttool.py +553 -0
- parrot/tools/retail/__init__.py +0 -0
- parrot/tools/retail/bby.py +528 -0
- parrot/tools/sandboxtool.py +703 -0
- parrot/tools/sassie/__init__.py +352 -0
- parrot/tools/scraping/__init__.py +7 -0
- parrot/tools/scraping/docs/select.md +466 -0
- parrot/tools/scraping/documentation.md +1278 -0
- parrot/tools/scraping/driver.py +436 -0
- parrot/tools/scraping/models.py +576 -0
- parrot/tools/scraping/options.py +85 -0
- parrot/tools/scraping/orchestrator.py +517 -0
- parrot/tools/scraping/readme.md +740 -0
- parrot/tools/scraping/tool.py +3115 -0
- parrot/tools/seasonaldetection.py +642 -0
- parrot/tools/shell_tool/__init__.py +5 -0
- parrot/tools/shell_tool/actions.py +408 -0
- parrot/tools/shell_tool/engine.py +155 -0
- parrot/tools/shell_tool/models.py +322 -0
- parrot/tools/shell_tool/tool.py +442 -0
- parrot/tools/site_search.py +214 -0
- parrot/tools/textfile.py +418 -0
- parrot/tools/think.py +378 -0
- parrot/tools/toolkit.py +298 -0
- parrot/tools/webapp_tool.py +187 -0
- parrot/tools/whatif.py +1279 -0
- parrot/tools/workday/MULTI_WSDL_EXAMPLE.md +249 -0
- parrot/tools/workday/__init__.py +6 -0
- parrot/tools/workday/models.py +1389 -0
- parrot/tools/workday/tool.py +1293 -0
- parrot/tools/yfinance_tool.py +306 -0
- parrot/tools/zipcode.py +217 -0
- parrot/utils/__init__.py +2 -0
- parrot/utils/helpers.py +73 -0
- parrot/utils/parsers/__init__.py +5 -0
- parrot/utils/parsers/toml.c +12078 -0
- parrot/utils/parsers/toml.cpython-310-x86_64-linux-gnu.so +0 -0
- parrot/utils/parsers/toml.pyx +21 -0
- parrot/utils/toml.py +11 -0
- parrot/utils/types.cpp +20936 -0
- parrot/utils/types.cpython-310-x86_64-linux-gnu.so +0 -0
- parrot/utils/types.pyx +213 -0
- parrot/utils/uv.py +11 -0
- parrot/version.py +10 -0
- parrot/yaml-rs/Cargo.lock +350 -0
- parrot/yaml-rs/Cargo.toml +19 -0
- parrot/yaml-rs/pyproject.toml +19 -0
- parrot/yaml-rs/python/yaml_rs/__init__.py +81 -0
- parrot/yaml-rs/src/lib.rs +222 -0
- requirements/docker-compose.yml +24 -0
- requirements/requirements-dev.txt +21 -0
parrot/tools/excel.py
ADDED
|
@@ -0,0 +1,683 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MS Excel Tool migrated to use AbstractDocumentTool framework.
|
|
3
|
+
"""
|
|
4
|
+
import io
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any, Dict, List, Optional, Literal, Union
|
|
7
|
+
import pandas as pd
|
|
8
|
+
from openpyxl import Workbook, load_workbook
|
|
9
|
+
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
|
|
10
|
+
from openpyxl.utils.dataframe import dataframe_to_rows
|
|
11
|
+
from odf.opendocument import OpenDocumentSpreadsheet
|
|
12
|
+
from odf.table import Table, TableRow, TableCell
|
|
13
|
+
from odf.text import P
|
|
14
|
+
from odf.style import Style, TableCellProperties, TextProperties
|
|
15
|
+
from pydantic import Field, field_validator, ConfigDict
|
|
16
|
+
from .document import AbstractDocumentTool, DocumentGenerationArgs
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ExcelArgs(DocumentGenerationArgs):
|
|
20
|
+
"""Arguments schema for Excel/ODS Document generation."""
|
|
21
|
+
|
|
22
|
+
content: Union[pd.DataFrame, List[Dict[str, Any]]] = Field(
|
|
23
|
+
...,
|
|
24
|
+
description="Pandas DataFrame or Dataset to export to Excel/ODS format"
|
|
25
|
+
)
|
|
26
|
+
sheet_name: str = Field(
|
|
27
|
+
"Sheet1",
|
|
28
|
+
description="Name of the worksheet"
|
|
29
|
+
)
|
|
30
|
+
template_file: Optional[str] = Field(
|
|
31
|
+
None,
|
|
32
|
+
description="Path to Excel/ODS template file to use as base"
|
|
33
|
+
)
|
|
34
|
+
output_format: Literal["excel", "ods"] = Field(
|
|
35
|
+
"excel",
|
|
36
|
+
description="Export format - 'excel' for .xlsx or 'ods' for OpenDocument"
|
|
37
|
+
)
|
|
38
|
+
header_styles: Optional[Dict[str, Any]] = Field(
|
|
39
|
+
None,
|
|
40
|
+
description="Dictionary of styles to apply to headers (font, color, etc.)"
|
|
41
|
+
)
|
|
42
|
+
data_styles: Optional[Dict[str, Any]] = Field(
|
|
43
|
+
None,
|
|
44
|
+
description="Dictionary of styles to apply to data cells"
|
|
45
|
+
)
|
|
46
|
+
auto_adjust_columns: bool = Field(
|
|
47
|
+
True,
|
|
48
|
+
description="Whether to auto-adjust column widths based on content"
|
|
49
|
+
)
|
|
50
|
+
freeze_header: bool = Field(
|
|
51
|
+
False,
|
|
52
|
+
description="Whether to freeze the header row"
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
56
|
+
|
|
57
|
+
@field_validator('content')
|
|
58
|
+
@classmethod
|
|
59
|
+
def validate_content(cls, v):
|
|
60
|
+
if isinstance(v, pd.DataFrame):
|
|
61
|
+
if v.empty:
|
|
62
|
+
raise ValueError("DataFrame content cannot be empty")
|
|
63
|
+
elif isinstance(v, list):
|
|
64
|
+
if not v:
|
|
65
|
+
raise ValueError("Content list cannot be empty")
|
|
66
|
+
if not all(isinstance(item, dict) for item in v):
|
|
67
|
+
raise ValueError("Content list must contain only dictionaries")
|
|
68
|
+
if v is None:
|
|
69
|
+
raise ValueError("content cannot be empty")
|
|
70
|
+
return v
|
|
71
|
+
|
|
72
|
+
@field_validator('sheet_name')
|
|
73
|
+
@classmethod
|
|
74
|
+
def validate_sheet_name(cls, v):
|
|
75
|
+
if not v or not v.strip():
|
|
76
|
+
raise ValueError("sheet_name cannot be empty")
|
|
77
|
+
# Excel sheet name limitations
|
|
78
|
+
invalid_chars = r'[:/\\?*\[\]]'
|
|
79
|
+
if any(char in v for char in invalid_chars):
|
|
80
|
+
raise ValueError(f"sheet_name contains invalid characters: {invalid_chars}")
|
|
81
|
+
if len(v) > 31:
|
|
82
|
+
raise ValueError("sheet_name cannot exceed 31 characters")
|
|
83
|
+
return v.strip()
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class ExcelTool(AbstractDocumentTool):
|
|
87
|
+
"""
|
|
88
|
+
Microsoft Excel/OpenDocument Spreadsheet Generation Tool.
|
|
89
|
+
|
|
90
|
+
This tool exports pandas DataFrames to Excel (.xlsx) or OpenDocument (.ods) files
|
|
91
|
+
with support for custom styling, templates, and advanced formatting features.
|
|
92
|
+
|
|
93
|
+
Features:
|
|
94
|
+
- Export DataFrames to Excel or ODS formats
|
|
95
|
+
- Custom header and data cell styling
|
|
96
|
+
- Template support for both formats
|
|
97
|
+
- Auto-adjusting column widths
|
|
98
|
+
- Header row freezing
|
|
99
|
+
- Professional spreadsheet formatting
|
|
100
|
+
- Comprehensive error handling and validation
|
|
101
|
+
"""
|
|
102
|
+
|
|
103
|
+
name = "excel_generator"
|
|
104
|
+
description = (
|
|
105
|
+
"Export pandas DataFrames to Excel (.xlsx) or OpenDocument (.ods) files "
|
|
106
|
+
"with custom styling, templates, and professional formatting. "
|
|
107
|
+
"Supports both Excel and ODS formats with advanced styling options."
|
|
108
|
+
)
|
|
109
|
+
args_schema = ExcelArgs
|
|
110
|
+
|
|
111
|
+
# Document type configuration
|
|
112
|
+
document_type = "spreadsheet"
|
|
113
|
+
default_extension = "xlsx"
|
|
114
|
+
supported_extensions = [".xlsx", ".xls", ".ods"]
|
|
115
|
+
|
|
116
|
+
def __init__(
|
|
117
|
+
self,
|
|
118
|
+
templates_dir: Optional[Path] = None,
|
|
119
|
+
default_format: Literal["excel", "ods"] = "excel",
|
|
120
|
+
**kwargs
|
|
121
|
+
):
|
|
122
|
+
"""
|
|
123
|
+
Initialize the Excel Tool.
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
templates_dir: Directory containing Excel/ODS templates
|
|
127
|
+
default_format: Default output format ('excel' or 'ods')
|
|
128
|
+
**kwargs: Additional arguments for AbstractDocumentTool
|
|
129
|
+
"""
|
|
130
|
+
super().__init__(templates_dir=templates_dir, **kwargs)
|
|
131
|
+
self.default_format = default_format
|
|
132
|
+
|
|
133
|
+
def _detect_output_format(self, output_format: str, filename: Optional[str] = None) -> str:
|
|
134
|
+
"""Detect output format from format parameter or filename extension."""
|
|
135
|
+
if output_format:
|
|
136
|
+
return output_format
|
|
137
|
+
|
|
138
|
+
if filename:
|
|
139
|
+
ext = Path(filename).suffix.lower()
|
|
140
|
+
if ext in ['.ods']:
|
|
141
|
+
return 'ods'
|
|
142
|
+
elif ext in ['.xlsx', '.xls']:
|
|
143
|
+
return 'excel'
|
|
144
|
+
|
|
145
|
+
return self.default_format
|
|
146
|
+
|
|
147
|
+
def _parse_content_to_dataframe(self, content: Union[str, List[Dict], pd.DataFrame]) -> pd.DataFrame:
|
|
148
|
+
"""
|
|
149
|
+
Parse content into a pandas DataFrame.
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
content: Can be a DataFrame, list of dictionaries, or JSON string
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
pandas DataFrame
|
|
156
|
+
"""
|
|
157
|
+
if isinstance(content, pd.DataFrame):
|
|
158
|
+
return content
|
|
159
|
+
elif isinstance(content, dict):
|
|
160
|
+
# Single dictionary, convert to DataFrame
|
|
161
|
+
return pd.DataFrame(content)
|
|
162
|
+
elif isinstance(content, list):
|
|
163
|
+
if not content:
|
|
164
|
+
raise ValueError("Content list cannot be empty")
|
|
165
|
+
if not all(isinstance(item, dict) for item in content):
|
|
166
|
+
raise ValueError("Content list must contain only dictionaries")
|
|
167
|
+
return pd.DataFrame(content)
|
|
168
|
+
elif isinstance(content, str):
|
|
169
|
+
try:
|
|
170
|
+
# Try to parse as JSON
|
|
171
|
+
data = self._json_decoder(content)
|
|
172
|
+
if isinstance(data, list):
|
|
173
|
+
return pd.DataFrame(data)
|
|
174
|
+
elif isinstance(data, dict):
|
|
175
|
+
# Single dictionary, wrap in list
|
|
176
|
+
return pd.DataFrame([data])
|
|
177
|
+
else:
|
|
178
|
+
raise ValueError("JSON content must be a list of objects or a single object")
|
|
179
|
+
except (TypeError, ValueError):
|
|
180
|
+
raise ValueError("String content must be valid JSON")
|
|
181
|
+
else:
|
|
182
|
+
raise ValueError(
|
|
183
|
+
"Content must be a pandas DataFrame, list of dictionaries, or JSON string"
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
def _get_extension_for_format(self, output_format: str) -> str:
|
|
187
|
+
"""Get file extension for the specified format."""
|
|
188
|
+
return "ods" if output_format == "ods" else "xlsx"
|
|
189
|
+
|
|
190
|
+
def _create_excel_workbook(
|
|
191
|
+
self,
|
|
192
|
+
dataframe: pd.DataFrame,
|
|
193
|
+
sheet_name: str,
|
|
194
|
+
template_file: Optional[str] = None,
|
|
195
|
+
header_styles: Optional[Dict[str, Any]] = None,
|
|
196
|
+
data_styles: Optional[Dict[str, Any]] = None,
|
|
197
|
+
auto_adjust_columns: bool = True,
|
|
198
|
+
freeze_header: bool = False
|
|
199
|
+
) -> Workbook:
|
|
200
|
+
"""Create Excel workbook with DataFrame data and styling."""
|
|
201
|
+
# Load template or create new workbook
|
|
202
|
+
if template_file:
|
|
203
|
+
template_path = self._get_template_path(template_file)
|
|
204
|
+
if template_path and template_path.exists():
|
|
205
|
+
wb = load_workbook(str(template_path))
|
|
206
|
+
self.logger.info(f"Loaded Excel template: {template_path}")
|
|
207
|
+
|
|
208
|
+
# Clear existing data in the target sheet if it exists
|
|
209
|
+
if sheet_name in wb.sheetnames:
|
|
210
|
+
ws = wb[sheet_name]
|
|
211
|
+
ws.delete_rows(1, ws.max_row)
|
|
212
|
+
else:
|
|
213
|
+
ws = wb.create_sheet(sheet_name)
|
|
214
|
+
else:
|
|
215
|
+
self.logger.warning(f"Template not found: {template_file}, creating new workbook")
|
|
216
|
+
wb = Workbook()
|
|
217
|
+
ws = wb.active
|
|
218
|
+
ws.title = sheet_name
|
|
219
|
+
else:
|
|
220
|
+
wb = Workbook()
|
|
221
|
+
ws = wb.active
|
|
222
|
+
ws.title = sheet_name
|
|
223
|
+
|
|
224
|
+
# Convert DataFrame to rows
|
|
225
|
+
rows = dataframe_to_rows(dataframe, index=False, header=True)
|
|
226
|
+
|
|
227
|
+
# Add data to worksheet
|
|
228
|
+
for r_idx, row in enumerate(rows, 1):
|
|
229
|
+
for c_idx, value in enumerate(row, 1):
|
|
230
|
+
cell = ws.cell(row=r_idx, column=c_idx, value=value)
|
|
231
|
+
|
|
232
|
+
# Apply header styles
|
|
233
|
+
if r_idx == 1 and header_styles:
|
|
234
|
+
self._apply_excel_cell_style(cell, header_styles)
|
|
235
|
+
# Apply data styles
|
|
236
|
+
elif r_idx > 1 and data_styles:
|
|
237
|
+
self._apply_excel_cell_style(cell, data_styles)
|
|
238
|
+
|
|
239
|
+
# Apply default header styling if no custom styles provided
|
|
240
|
+
if not header_styles:
|
|
241
|
+
self._apply_default_excel_header_styles(ws, len(dataframe.columns))
|
|
242
|
+
|
|
243
|
+
# Auto-adjust column widths
|
|
244
|
+
if auto_adjust_columns:
|
|
245
|
+
self._adjust_excel_column_widths(ws)
|
|
246
|
+
|
|
247
|
+
# Freeze header row
|
|
248
|
+
if freeze_header:
|
|
249
|
+
ws.freeze_panes = ws['A2']
|
|
250
|
+
|
|
251
|
+
return wb
|
|
252
|
+
|
|
253
|
+
def _apply_excel_cell_style(self, cell, styles: Dict[str, Any]) -> None:
|
|
254
|
+
"""Apply styles to an Excel cell."""
|
|
255
|
+
# Font styling
|
|
256
|
+
if any(key in styles for key in ['font_name', 'font_size', 'bold', 'italic', 'font_color']):
|
|
257
|
+
font_kwargs = {}
|
|
258
|
+
if 'font_name' in styles:
|
|
259
|
+
font_kwargs['name'] = styles['font_name']
|
|
260
|
+
if 'font_size' in styles:
|
|
261
|
+
font_kwargs['size'] = styles['font_size']
|
|
262
|
+
if 'bold' in styles:
|
|
263
|
+
font_kwargs['bold'] = styles['bold']
|
|
264
|
+
if 'italic' in styles:
|
|
265
|
+
font_kwargs['italic'] = styles['italic']
|
|
266
|
+
if 'font_color' in styles:
|
|
267
|
+
font_kwargs['color'] = styles['font_color']
|
|
268
|
+
|
|
269
|
+
cell.font = Font(**font_kwargs)
|
|
270
|
+
|
|
271
|
+
# Background color
|
|
272
|
+
if 'background_color' in styles:
|
|
273
|
+
cell.fill = PatternFill(
|
|
274
|
+
start_color=styles['background_color'],
|
|
275
|
+
end_color=styles['background_color'],
|
|
276
|
+
fill_type="solid"
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
# Alignment
|
|
280
|
+
if any(key in styles for key in ['horizontal', 'vertical', 'wrap_text']):
|
|
281
|
+
align_kwargs = {}
|
|
282
|
+
if 'horizontal' in styles:
|
|
283
|
+
align_kwargs['horizontal'] = styles['horizontal']
|
|
284
|
+
if 'vertical' in styles:
|
|
285
|
+
align_kwargs['vertical'] = styles['vertical']
|
|
286
|
+
if 'wrap_text' in styles:
|
|
287
|
+
align_kwargs['wrap_text'] = styles['wrap_text']
|
|
288
|
+
|
|
289
|
+
cell.alignment = Alignment(**align_kwargs)
|
|
290
|
+
|
|
291
|
+
# Borders
|
|
292
|
+
if 'border' in styles:
|
|
293
|
+
border_style = styles['border']
|
|
294
|
+
side = Side(style=border_style, color="000000")
|
|
295
|
+
cell.border = Border(left=side, right=side, top=side, bottom=side)
|
|
296
|
+
|
|
297
|
+
def _apply_default_excel_header_styles(self, ws, num_columns: int) -> None:
|
|
298
|
+
"""Apply default styling to header row."""
|
|
299
|
+
header_font = Font(name='Calibri', size=12, bold=True, color="FFFFFF")
|
|
300
|
+
header_fill = PatternFill(start_color="366092", end_color="366092", fill_type="solid")
|
|
301
|
+
header_alignment = Alignment(horizontal="center", vertical="center")
|
|
302
|
+
|
|
303
|
+
for col in range(1, num_columns + 1):
|
|
304
|
+
cell = ws.cell(row=1, column=col)
|
|
305
|
+
cell.font = header_font
|
|
306
|
+
cell.fill = header_fill
|
|
307
|
+
cell.alignment = header_alignment
|
|
308
|
+
|
|
309
|
+
def _adjust_excel_column_widths(self, ws) -> None:
|
|
310
|
+
"""Auto-adjust column widths based on content."""
|
|
311
|
+
for column in ws.columns:
|
|
312
|
+
max_length = 0
|
|
313
|
+
column_letter = column[0].column_letter
|
|
314
|
+
|
|
315
|
+
for cell in column:
|
|
316
|
+
try:
|
|
317
|
+
if len(str(cell.value)) > max_length:
|
|
318
|
+
max_length = len(str(cell.value))
|
|
319
|
+
except:
|
|
320
|
+
pass
|
|
321
|
+
|
|
322
|
+
adjusted_width = min(max_length + 2, 50) # Cap at 50 characters
|
|
323
|
+
ws.column_dimensions[column_letter].width = adjusted_width
|
|
324
|
+
|
|
325
|
+
def _create_ods_document(
|
|
326
|
+
self,
|
|
327
|
+
dataframe: pd.DataFrame,
|
|
328
|
+
sheet_name: str,
|
|
329
|
+
header_styles: Optional[Dict[str, Any]] = None,
|
|
330
|
+
data_styles: Optional[Dict[str, Any]] = None
|
|
331
|
+
) -> OpenDocumentSpreadsheet:
|
|
332
|
+
"""Create ODS document with DataFrame data and styling."""
|
|
333
|
+
# Create new ODS document
|
|
334
|
+
doc = OpenDocumentSpreadsheet()
|
|
335
|
+
|
|
336
|
+
# Create styles
|
|
337
|
+
header_style = self._create_ods_header_style(doc, header_styles)
|
|
338
|
+
data_style = self._create_ods_data_style(doc, data_styles)
|
|
339
|
+
|
|
340
|
+
# Create table (sheet)
|
|
341
|
+
table = Table(name=sheet_name)
|
|
342
|
+
|
|
343
|
+
# Add header row
|
|
344
|
+
header_row = TableRow()
|
|
345
|
+
for col_name in dataframe.columns:
|
|
346
|
+
cell = TableCell(stylename=header_style)
|
|
347
|
+
cell.addElement(P(text=str(col_name)))
|
|
348
|
+
header_row.addElement(cell)
|
|
349
|
+
table.addElement(header_row)
|
|
350
|
+
|
|
351
|
+
# Add data rows
|
|
352
|
+
for _, row in dataframe.iterrows():
|
|
353
|
+
data_row = TableRow()
|
|
354
|
+
for value in row:
|
|
355
|
+
cell = TableCell(stylename=data_style)
|
|
356
|
+
cell.addElement(P(text=str(value) if pd.notna(value) else ""))
|
|
357
|
+
data_row.addElement(cell)
|
|
358
|
+
table.addElement(data_row)
|
|
359
|
+
|
|
360
|
+
doc.spreadsheet.addElement(table)
|
|
361
|
+
return doc
|
|
362
|
+
|
|
363
|
+
def _create_ods_header_style(self, doc, custom_styles: Optional[Dict[str, Any]]) -> str:
|
|
364
|
+
"""Create ODS style for headers."""
|
|
365
|
+
style = Style(name="HeaderStyle", family="table-cell")
|
|
366
|
+
|
|
367
|
+
# Default header properties
|
|
368
|
+
cell_props = TableCellProperties(
|
|
369
|
+
backgroundcolor="#366092",
|
|
370
|
+
border="1pt solid #000000"
|
|
371
|
+
)
|
|
372
|
+
text_props = TextProperties(
|
|
373
|
+
fontweight="bold",
|
|
374
|
+
color="#FFFFFF",
|
|
375
|
+
fontfamily="Calibri",
|
|
376
|
+
fontsize="12pt"
|
|
377
|
+
)
|
|
378
|
+
|
|
379
|
+
# Apply custom styles if provided
|
|
380
|
+
if custom_styles:
|
|
381
|
+
if 'background_color' in custom_styles:
|
|
382
|
+
cell_props.backgroundcolor = custom_styles['background_color']
|
|
383
|
+
if 'font_color' in custom_styles:
|
|
384
|
+
text_props.color = custom_styles['font_color']
|
|
385
|
+
if 'font_name' in custom_styles:
|
|
386
|
+
text_props.fontfamily = custom_styles['font_name']
|
|
387
|
+
if 'font_size' in custom_styles:
|
|
388
|
+
text_props.fontsize = f"{custom_styles['font_size']}pt"
|
|
389
|
+
if 'bold' in custom_styles:
|
|
390
|
+
text_props.fontweight = "bold" if custom_styles['bold'] else "normal"
|
|
391
|
+
|
|
392
|
+
style.addElement(cell_props)
|
|
393
|
+
style.addElement(text_props)
|
|
394
|
+
doc.styles.addElement(style)
|
|
395
|
+
|
|
396
|
+
return "HeaderStyle"
|
|
397
|
+
|
|
398
|
+
def _create_ods_data_style(self, doc, custom_styles: Optional[Dict[str, Any]]) -> str:
|
|
399
|
+
"""Create ODS style for data cells."""
|
|
400
|
+
style = Style(name="DataStyle", family="table-cell")
|
|
401
|
+
|
|
402
|
+
# Default data properties
|
|
403
|
+
cell_props = TableCellProperties(border="1pt solid #CCCCCC")
|
|
404
|
+
text_props = TextProperties(
|
|
405
|
+
fontfamily="Calibri",
|
|
406
|
+
fontsize="11pt"
|
|
407
|
+
)
|
|
408
|
+
|
|
409
|
+
# Apply custom styles if provided
|
|
410
|
+
if custom_styles:
|
|
411
|
+
if 'background_color' in custom_styles:
|
|
412
|
+
cell_props.backgroundcolor = custom_styles['background_color']
|
|
413
|
+
if 'font_color' in custom_styles:
|
|
414
|
+
text_props.color = custom_styles['font_color']
|
|
415
|
+
if 'font_name' in custom_styles:
|
|
416
|
+
text_props.fontfamily = custom_styles['font_name']
|
|
417
|
+
if 'font_size' in custom_styles:
|
|
418
|
+
text_props.fontsize = f"{custom_styles['font_size']}pt"
|
|
419
|
+
if 'bold' in custom_styles:
|
|
420
|
+
text_props.fontweight = "bold" if custom_styles['bold'] else "normal"
|
|
421
|
+
|
|
422
|
+
style.addElement(cell_props)
|
|
423
|
+
style.addElement(text_props)
|
|
424
|
+
doc.styles.addElement(style)
|
|
425
|
+
|
|
426
|
+
return "DataStyle"
|
|
427
|
+
|
|
428
|
+
async def _generate_document_content(self, content: str, **kwargs) -> bytes:
|
|
429
|
+
"""
|
|
430
|
+
Generate Excel/ODS document content from structured data.
|
|
431
|
+
|
|
432
|
+
Args:
|
|
433
|
+
content: Structured data - can be JSON string, list of dicts, or DataFrame
|
|
434
|
+
**kwargs: Additional arguments from ExcelArgs
|
|
435
|
+
|
|
436
|
+
Returns:
|
|
437
|
+
Excel/ODS document as bytes
|
|
438
|
+
"""
|
|
439
|
+
try:
|
|
440
|
+
# Extract arguments
|
|
441
|
+
sheet_name = kwargs.get('sheet_name', 'Sheet1')
|
|
442
|
+
template_file = kwargs.get('template_file')
|
|
443
|
+
output_format = kwargs.get('output_format', 'excel')
|
|
444
|
+
header_styles = kwargs.get('header_styles')
|
|
445
|
+
data_styles = kwargs.get('data_styles')
|
|
446
|
+
auto_adjust_columns = kwargs.get('auto_adjust_columns', True)
|
|
447
|
+
freeze_header = kwargs.get('freeze_header', False)
|
|
448
|
+
|
|
449
|
+
# Parse content to DataFrame
|
|
450
|
+
dataframe = self._parse_content_to_dataframe(content)
|
|
451
|
+
|
|
452
|
+
self.logger.info(
|
|
453
|
+
f"Generating {output_format} document with {len(dataframe)} rows and "
|
|
454
|
+
f"{len(dataframe.columns)} columns"
|
|
455
|
+
)
|
|
456
|
+
|
|
457
|
+
# Create document based on format
|
|
458
|
+
doc_bytes = io.BytesIO()
|
|
459
|
+
|
|
460
|
+
if output_format == "ods":
|
|
461
|
+
# Create ODS document
|
|
462
|
+
doc = self._create_ods_document(
|
|
463
|
+
dataframe=dataframe,
|
|
464
|
+
sheet_name=sheet_name,
|
|
465
|
+
header_styles=header_styles,
|
|
466
|
+
data_styles=data_styles
|
|
467
|
+
)
|
|
468
|
+
doc.save(doc_bytes)
|
|
469
|
+
else:
|
|
470
|
+
# Create Excel document
|
|
471
|
+
wb = self._create_excel_workbook(
|
|
472
|
+
dataframe=dataframe,
|
|
473
|
+
sheet_name=sheet_name,
|
|
474
|
+
template_file=template_file,
|
|
475
|
+
header_styles=header_styles,
|
|
476
|
+
data_styles=data_styles,
|
|
477
|
+
auto_adjust_columns=auto_adjust_columns,
|
|
478
|
+
freeze_header=freeze_header
|
|
479
|
+
)
|
|
480
|
+
wb.save(doc_bytes)
|
|
481
|
+
|
|
482
|
+
doc_bytes.seek(0)
|
|
483
|
+
return doc_bytes.getvalue()
|
|
484
|
+
|
|
485
|
+
except Exception as e:
|
|
486
|
+
self.logger.error(f"Error generating {output_format} document: {e}")
|
|
487
|
+
raise
|
|
488
|
+
|
|
489
|
+
async def _execute(
|
|
490
|
+
self,
|
|
491
|
+
content: Union[str, List[Dict], pd.DataFrame],
|
|
492
|
+
sheet_name: str = "Sheet1",
|
|
493
|
+
template_file: Optional[str] = None,
|
|
494
|
+
output_format: Literal["excel", "ods"] = "excel",
|
|
495
|
+
header_styles: Optional[Dict[str, Any]] = None,
|
|
496
|
+
data_styles: Optional[Dict[str, Any]] = None,
|
|
497
|
+
auto_adjust_columns: bool = True,
|
|
498
|
+
freeze_header: bool = False,
|
|
499
|
+
output_filename: Optional[str] = None,
|
|
500
|
+
file_prefix: str = "spreadsheet",
|
|
501
|
+
output_dir: Optional[str] = None,
|
|
502
|
+
overwrite_existing: bool = False,
|
|
503
|
+
**kwargs
|
|
504
|
+
) -> Dict[str, Any]:
|
|
505
|
+
"""
|
|
506
|
+
Execute Excel/ODS document generation (AbstractTool interface).
|
|
507
|
+
|
|
508
|
+
Args:
|
|
509
|
+
content: Structured data - DataFrame, list of dicts, or JSON string
|
|
510
|
+
sheet_name: Name of the worksheet
|
|
511
|
+
template_file: Excel/ODS template file path
|
|
512
|
+
output_format: Export format ('excel' or 'ods')
|
|
513
|
+
header_styles: Custom header styling
|
|
514
|
+
data_styles: Custom data cell styling
|
|
515
|
+
auto_adjust_columns: Whether to auto-adjust column widths
|
|
516
|
+
freeze_header: Whether to freeze the header row
|
|
517
|
+
output_filename: Custom filename (without extension)
|
|
518
|
+
file_prefix: Prefix for auto-generated filenames
|
|
519
|
+
output_dir: Custom output directory
|
|
520
|
+
overwrite_existing: Whether to overwrite existing files
|
|
521
|
+
**kwargs: Additional arguments
|
|
522
|
+
|
|
523
|
+
Returns:
|
|
524
|
+
Dictionary with document generation results
|
|
525
|
+
"""
|
|
526
|
+
try:
|
|
527
|
+
# Parse content to get DataFrame info for logging
|
|
528
|
+
dataframe = self._parse_content_to_dataframe(content)
|
|
529
|
+
|
|
530
|
+
# Detect format and set appropriate extension
|
|
531
|
+
detected_format = self._detect_output_format(output_format, output_filename)
|
|
532
|
+
extension = self._get_extension_for_format(detected_format)
|
|
533
|
+
|
|
534
|
+
self.logger.info(
|
|
535
|
+
f"Starting {detected_format.upper()} document generation with "
|
|
536
|
+
f"{len(dataframe)} rows and {len(dataframe.columns)} columns"
|
|
537
|
+
)
|
|
538
|
+
|
|
539
|
+
# Use the safe document creation workflow
|
|
540
|
+
result = await self._create_document_safely(
|
|
541
|
+
content=dataframe,
|
|
542
|
+
output_filename=output_filename,
|
|
543
|
+
file_prefix=file_prefix,
|
|
544
|
+
output_dir=output_dir,
|
|
545
|
+
overwrite_existing=overwrite_existing or self.overwrite_existing,
|
|
546
|
+
extension=extension,
|
|
547
|
+
sheet_name=sheet_name,
|
|
548
|
+
template_file=template_file,
|
|
549
|
+
output_format=detected_format,
|
|
550
|
+
header_styles=header_styles,
|
|
551
|
+
data_styles=data_styles,
|
|
552
|
+
auto_adjust_columns=auto_adjust_columns,
|
|
553
|
+
freeze_header=freeze_header
|
|
554
|
+
)
|
|
555
|
+
|
|
556
|
+
if result['status'] == 'success':
|
|
557
|
+
# Add Excel-specific metadata
|
|
558
|
+
result['metadata'].update({
|
|
559
|
+
'format': detected_format,
|
|
560
|
+
'sheet_name': sheet_name,
|
|
561
|
+
'rows': len(dataframe),
|
|
562
|
+
'columns': len(dataframe.columns),
|
|
563
|
+
'column_names': list(dataframe.columns)
|
|
564
|
+
})
|
|
565
|
+
|
|
566
|
+
self.logger.info(
|
|
567
|
+
f"{detected_format.upper()} document created successfully: "
|
|
568
|
+
f"{result['metadata']['filename']}"
|
|
569
|
+
)
|
|
570
|
+
|
|
571
|
+
return result
|
|
572
|
+
|
|
573
|
+
except Exception as e:
|
|
574
|
+
self.logger.error(f"Error in Excel document generation: {e}")
|
|
575
|
+
raise
|
|
576
|
+
|
|
577
|
+
# Convenience methods for direct DataFrame export
|
|
578
|
+
async def export_dataframe(
|
|
579
|
+
self,
|
|
580
|
+
dataframe: pd.DataFrame,
|
|
581
|
+
output_format: Literal["excel", "ods"] = "excel",
|
|
582
|
+
**kwargs
|
|
583
|
+
) -> Dict[str, Any]:
|
|
584
|
+
"""
|
|
585
|
+
Convenience method to directly export a DataFrame.
|
|
586
|
+
|
|
587
|
+
Args:
|
|
588
|
+
dataframe: DataFrame to export
|
|
589
|
+
output_format: Export format
|
|
590
|
+
**kwargs: Additional arguments for _execute
|
|
591
|
+
|
|
592
|
+
Returns:
|
|
593
|
+
Dictionary with export results
|
|
594
|
+
"""
|
|
595
|
+
return await self._execute(
|
|
596
|
+
content=dataframe,
|
|
597
|
+
output_format=output_format,
|
|
598
|
+
**kwargs
|
|
599
|
+
)
|
|
600
|
+
|
|
601
|
+
async def export_data(
|
|
602
|
+
self,
|
|
603
|
+
data: Union[List[Dict], pd.DataFrame, str],
|
|
604
|
+
output_format: Literal["excel", "ods"] = "excel",
|
|
605
|
+
**kwargs
|
|
606
|
+
) -> Dict[str, Any]:
|
|
607
|
+
"""
|
|
608
|
+
Convenience method to export various data formats.
|
|
609
|
+
|
|
610
|
+
Args:
|
|
611
|
+
data: Data to export (DataFrame, list of dicts, or JSON string)
|
|
612
|
+
output_format: Export format
|
|
613
|
+
**kwargs: Additional arguments for _execute
|
|
614
|
+
|
|
615
|
+
Returns:
|
|
616
|
+
Dictionary with export results
|
|
617
|
+
"""
|
|
618
|
+
return await self._execute(
|
|
619
|
+
content=data,
|
|
620
|
+
output_format=output_format,
|
|
621
|
+
**kwargs
|
|
622
|
+
)
|
|
623
|
+
|
|
624
|
+
def get_format_info(self) -> Dict[str, Any]:
|
|
625
|
+
"""Get information about supported formats."""
|
|
626
|
+
return {
|
|
627
|
+
"supported_formats": ["excel", "ods"],
|
|
628
|
+
"excel_extensions": [".xlsx", ".xls"],
|
|
629
|
+
"ods_extensions": [".ods"],
|
|
630
|
+
"default_format": self.default_format,
|
|
631
|
+
"features": {
|
|
632
|
+
"templates": True,
|
|
633
|
+
"custom_styling": True,
|
|
634
|
+
"auto_column_width": True,
|
|
635
|
+
"freeze_panes": True,
|
|
636
|
+
"multiple_sheets": False # Could be extended in future
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
|
|
641
|
+
class DataFrameToExcelTool(ExcelTool):
|
|
642
|
+
"""
|
|
643
|
+
Simplified Excel tool that focuses purely on DataFrame export.
|
|
644
|
+
|
|
645
|
+
This is a convenience wrapper around ExcelTool for users who primarily
|
|
646
|
+
need to export DataFrames without complex document features.
|
|
647
|
+
"""
|
|
648
|
+
|
|
649
|
+
name = "dataframe_to_excel"
|
|
650
|
+
description = (
|
|
651
|
+
"Simple tool to export pandas DataFrames to Excel or ODS files. "
|
|
652
|
+
"Focused on quick DataFrame export with minimal configuration."
|
|
653
|
+
)
|
|
654
|
+
|
|
655
|
+
async def quick_export(
|
|
656
|
+
self,
|
|
657
|
+
data: Union[pd.DataFrame, List[Dict], str],
|
|
658
|
+
filename: Optional[str] = None,
|
|
659
|
+
format: Literal["excel", "ods"] = "excel"
|
|
660
|
+
) -> str:
|
|
661
|
+
"""
|
|
662
|
+
Quick export method that returns just the file path.
|
|
663
|
+
|
|
664
|
+
Args:
|
|
665
|
+
data: Data to export (DataFrame, list of dicts, or JSON string)
|
|
666
|
+
filename: Optional filename
|
|
667
|
+
format: Export format
|
|
668
|
+
|
|
669
|
+
Returns:
|
|
670
|
+
Path to the created file
|
|
671
|
+
"""
|
|
672
|
+
result = await self.export_data(
|
|
673
|
+
data=data,
|
|
674
|
+
output_filename=filename,
|
|
675
|
+
output_format=format
|
|
676
|
+
)
|
|
677
|
+
|
|
678
|
+
if result['status'] == 'success':
|
|
679
|
+
return result['metadata']['file_path']
|
|
680
|
+
else:
|
|
681
|
+
raise Exception(
|
|
682
|
+
f"Export failed: {result.get('error', 'Unknown error')}"
|
|
683
|
+
)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from .abstract import FileManagerInterface, FileMetadata
|
|
2
|
+
from .local import LocalFileManager
|
|
3
|
+
from .s3 import S3FileManager
|
|
4
|
+
from .tmp import TempFileManager
|
|
5
|
+
from .gcs import GCSFileManager
|
|
6
|
+
from .tool import FileManagerTool
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
__all__ = (
|
|
10
|
+
"FileManagerInterface",
|
|
11
|
+
"FileMetadata",
|
|
12
|
+
"FileManagerTool",
|
|
13
|
+
)
|