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/document.py
ADDED
|
@@ -0,0 +1,549 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AbstractDocumentTool - Base class for document generation tools.
|
|
3
|
+
|
|
4
|
+
This extends AbstractTool with common functionality for document generators like:
|
|
5
|
+
- PowerPoint, Word, Excel, PDF tools
|
|
6
|
+
- Standard document output management
|
|
7
|
+
- File path validation and generation
|
|
8
|
+
- Async file operations
|
|
9
|
+
- Template management
|
|
10
|
+
"""
|
|
11
|
+
from abc import abstractmethod
|
|
12
|
+
from typing import Any, Dict, Optional, Union, List
|
|
13
|
+
import re
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from datetime import datetime
|
|
16
|
+
import aiofiles
|
|
17
|
+
import aiofiles.os
|
|
18
|
+
import pandas as pd
|
|
19
|
+
from pydantic import BaseModel, Field, field_validator
|
|
20
|
+
from .abstract import AbstractTool
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class DocumentGenerationArgs(BaseModel):
|
|
24
|
+
"""Base arguments schema for document generation tools."""
|
|
25
|
+
|
|
26
|
+
content: str = Field(
|
|
27
|
+
...,
|
|
28
|
+
description="Content to be converted to document (text, markdown, HTML, etc.)"
|
|
29
|
+
)
|
|
30
|
+
output_filename: Optional[str] = Field(
|
|
31
|
+
None,
|
|
32
|
+
description="Custom filename for the output document (without extension). If None, auto-generates with timestamp"
|
|
33
|
+
)
|
|
34
|
+
file_prefix: str = Field(
|
|
35
|
+
"document",
|
|
36
|
+
description="Prefix for auto-generated filenames"
|
|
37
|
+
)
|
|
38
|
+
output_dir: Optional[str] = Field(
|
|
39
|
+
None,
|
|
40
|
+
description="Custom output directory. If None, uses tool's default directory"
|
|
41
|
+
)
|
|
42
|
+
overwrite_existing: bool = Field(
|
|
43
|
+
False,
|
|
44
|
+
description="Whether to overwrite existing files with the same name"
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
@field_validator('output_filename')
|
|
48
|
+
@classmethod
|
|
49
|
+
def validate_filename(cls, v):
|
|
50
|
+
if v is not None:
|
|
51
|
+
# Remove invalid filename characters
|
|
52
|
+
invalid_chars = r'[<>:"/\\|?*]'
|
|
53
|
+
if re.search(invalid_chars, v):
|
|
54
|
+
raise ValueError(f"Filename contains invalid characters: {invalid_chars}")
|
|
55
|
+
return v
|
|
56
|
+
|
|
57
|
+
@field_validator('file_prefix')
|
|
58
|
+
@classmethod
|
|
59
|
+
def validate_file_prefix(cls, v):
|
|
60
|
+
# Clean file prefix
|
|
61
|
+
return re.sub(r'[<>:"/\\|?*]', '_', v) if v else "document"
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class DocumentMetadata(BaseModel):
|
|
65
|
+
"""Metadata for generated documents."""
|
|
66
|
+
|
|
67
|
+
filename: str = Field(
|
|
68
|
+
...,
|
|
69
|
+
description="Name of the generated document file"
|
|
70
|
+
)
|
|
71
|
+
file_path: str = Field(
|
|
72
|
+
...,
|
|
73
|
+
description="Full path to the generated document file"
|
|
74
|
+
)
|
|
75
|
+
file_url: str = Field(
|
|
76
|
+
...,
|
|
77
|
+
description="Public URL to access the generated document file"
|
|
78
|
+
)
|
|
79
|
+
relative_url: str = Field(
|
|
80
|
+
...,
|
|
81
|
+
description="Relative URL to access the generated document file"
|
|
82
|
+
)
|
|
83
|
+
file_size: int = Field(
|
|
84
|
+
...,
|
|
85
|
+
description="Size of the generated document file in bytes"
|
|
86
|
+
)
|
|
87
|
+
file_size_mb: float = Field(
|
|
88
|
+
...,
|
|
89
|
+
description="Size of the generated document file in megabytes"
|
|
90
|
+
)
|
|
91
|
+
file_extension: str = Field(
|
|
92
|
+
...,
|
|
93
|
+
description="File extension of the generated document"
|
|
94
|
+
)
|
|
95
|
+
created_at: str = Field(
|
|
96
|
+
...,
|
|
97
|
+
description="Timestamp when the document was created"
|
|
98
|
+
)
|
|
99
|
+
content_length: int = Field(
|
|
100
|
+
...,
|
|
101
|
+
description="Length of the document content in characters"
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class AbstractDocumentTool(AbstractTool):
|
|
106
|
+
"""
|
|
107
|
+
Abstract base class for document generation tools.
|
|
108
|
+
|
|
109
|
+
This class provides common functionality for tools that generate documents
|
|
110
|
+
like PowerPoint presentations, Word documents, Excel spreadsheets, PDFs, etc.
|
|
111
|
+
|
|
112
|
+
Features:
|
|
113
|
+
- Standardized document output management
|
|
114
|
+
- File path validation and generation
|
|
115
|
+
- Async file operations with aiofiles
|
|
116
|
+
- Template management support
|
|
117
|
+
- Duplicate file handling
|
|
118
|
+
- Comprehensive metadata generation
|
|
119
|
+
"""
|
|
120
|
+
|
|
121
|
+
# Document-specific configuration
|
|
122
|
+
document_type: str = "document" # Override in subclasses (e.g., "presentation", "spreadsheet")
|
|
123
|
+
default_extension: str = "txt" # Override in subclasses (e.g., "pptx", "docx", "xlsx")
|
|
124
|
+
supported_extensions: List[str] = [] # Override in subclasses
|
|
125
|
+
|
|
126
|
+
def __init__(
|
|
127
|
+
self,
|
|
128
|
+
templates_dir: Optional[Path] = None,
|
|
129
|
+
output_dir: Optional[Union[str, Path]] = None,
|
|
130
|
+
default_template_name: Optional[str] = None,
|
|
131
|
+
max_file_size_mb: float = 100.0,
|
|
132
|
+
overwrite_existing: bool = False,
|
|
133
|
+
**kwargs
|
|
134
|
+
):
|
|
135
|
+
"""
|
|
136
|
+
Initialize the AbstractDocumentTool.
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
templates_dir: Directory containing document templates
|
|
140
|
+
default_template_name: Default template file name
|
|
141
|
+
max_file_size_mb: Maximum allowed file size in MB
|
|
142
|
+
**kwargs: Additional arguments for AbstractTool
|
|
143
|
+
"""
|
|
144
|
+
# Set output_dir in kwargs if provided, so AbstractTool can use it
|
|
145
|
+
if output_dir:
|
|
146
|
+
kwargs['output_dir'] = Path(output_dir).resolve()
|
|
147
|
+
|
|
148
|
+
super().__init__(**kwargs)
|
|
149
|
+
|
|
150
|
+
self.overwrite_existing = overwrite_existing
|
|
151
|
+
|
|
152
|
+
# Template management
|
|
153
|
+
self.templates_dir = templates_dir
|
|
154
|
+
self.default_template_name = default_template_name
|
|
155
|
+
self.max_file_size_mb = max_file_size_mb
|
|
156
|
+
|
|
157
|
+
# Initialize templates directory if provided
|
|
158
|
+
if self.templates_dir:
|
|
159
|
+
self.templates_dir = Path(self.templates_dir)
|
|
160
|
+
if not self.templates_dir.exists():
|
|
161
|
+
self.templates_dir.mkdir(parents=True, exist_ok=True)
|
|
162
|
+
self.logger.info(
|
|
163
|
+
f"Created templates directory: {self.templates_dir}"
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
# If output_dir was provided, ensure it exists
|
|
167
|
+
if output_dir and not self.output_dir.exists():
|
|
168
|
+
self.output_dir.mkdir(parents=True, exist_ok=True)
|
|
169
|
+
self.logger.info(
|
|
170
|
+
f"Created output directory: {self.output_dir}"
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
def _default_output_dir(self) -> Path:
|
|
174
|
+
"""Get the default output directory for this document type."""
|
|
175
|
+
return self.static_dir / "documents" / self.document_type
|
|
176
|
+
|
|
177
|
+
async def _ensure_output_directory(self, custom_dir: Optional[str] = None) -> Path:
|
|
178
|
+
"""
|
|
179
|
+
Ensure output directory exists and return the path.
|
|
180
|
+
|
|
181
|
+
Args:
|
|
182
|
+
custom_dir: Custom output directory path
|
|
183
|
+
|
|
184
|
+
Returns:
|
|
185
|
+
Path object for the output directory
|
|
186
|
+
"""
|
|
187
|
+
if custom_dir:
|
|
188
|
+
output_dir = Path(custom_dir).resolve()
|
|
189
|
+
else:
|
|
190
|
+
output_dir = self.output_dir
|
|
191
|
+
|
|
192
|
+
# Create directory if it doesn't exist
|
|
193
|
+
if not await aiofiles.os.path.exists(output_dir):
|
|
194
|
+
await aiofiles.os.makedirs(output_dir, exist_ok=True)
|
|
195
|
+
self.logger.info(f"Created output directory: {output_dir}")
|
|
196
|
+
|
|
197
|
+
return output_dir
|
|
198
|
+
|
|
199
|
+
def _generate_document_filename(
|
|
200
|
+
self,
|
|
201
|
+
output_filename: Optional[str],
|
|
202
|
+
file_prefix: str,
|
|
203
|
+
extension: Optional[str] = None
|
|
204
|
+
) -> str:
|
|
205
|
+
"""
|
|
206
|
+
Generate a filename for the document.
|
|
207
|
+
|
|
208
|
+
Args:
|
|
209
|
+
output_filename: User-provided filename (without extension)
|
|
210
|
+
file_prefix: Prefix for auto-generated names
|
|
211
|
+
extension: File extension (without dot)
|
|
212
|
+
|
|
213
|
+
Returns:
|
|
214
|
+
Complete filename with extension
|
|
215
|
+
"""
|
|
216
|
+
# Use default extension if not provided
|
|
217
|
+
if not extension:
|
|
218
|
+
extension = self.default_extension
|
|
219
|
+
|
|
220
|
+
# Ensure extension doesn't have a leading dot
|
|
221
|
+
extension = extension.lstrip('.')
|
|
222
|
+
|
|
223
|
+
if output_filename:
|
|
224
|
+
# Use provided filename
|
|
225
|
+
if not output_filename.endswith(f'.{extension}'):
|
|
226
|
+
filename = f"{output_filename}.{extension}"
|
|
227
|
+
else:
|
|
228
|
+
filename = output_filename
|
|
229
|
+
else:
|
|
230
|
+
# Generate filename with timestamp
|
|
231
|
+
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
232
|
+
filename = f"{file_prefix}_{timestamp}.{extension}"
|
|
233
|
+
|
|
234
|
+
return filename
|
|
235
|
+
|
|
236
|
+
async def _check_file_exists(
|
|
237
|
+
self,
|
|
238
|
+
file_path: Path,
|
|
239
|
+
overwrite_existing: bool
|
|
240
|
+
) -> None:
|
|
241
|
+
"""
|
|
242
|
+
Check if file exists and handle according to overwrite setting.
|
|
243
|
+
|
|
244
|
+
Args:
|
|
245
|
+
file_path: Path to the file
|
|
246
|
+
overwrite_existing: Whether to overwrite existing files
|
|
247
|
+
|
|
248
|
+
Raises:
|
|
249
|
+
FileExistsError: If file exists and overwrite is False
|
|
250
|
+
"""
|
|
251
|
+
if await aiofiles.os.path.exists(file_path):
|
|
252
|
+
if not overwrite_existing:
|
|
253
|
+
self.logger.warning(
|
|
254
|
+
f"File already exists: {file_path}"
|
|
255
|
+
)
|
|
256
|
+
raise FileExistsError(
|
|
257
|
+
f"File already exists: {file_path.name}. "
|
|
258
|
+
f"Set overwrite_existing=True to overwrite."
|
|
259
|
+
)
|
|
260
|
+
else:
|
|
261
|
+
self.logger.info(
|
|
262
|
+
f"Will overwrite existing file: {file_path}"
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
async def _save_document_content(
|
|
266
|
+
self,
|
|
267
|
+
content: Union[bytes, str],
|
|
268
|
+
file_path: Path,
|
|
269
|
+
encoding: Optional[str] = None
|
|
270
|
+
) -> None:
|
|
271
|
+
"""
|
|
272
|
+
Save document content to file using aiofiles.
|
|
273
|
+
|
|
274
|
+
Args:
|
|
275
|
+
content: Content to save (bytes or string)
|
|
276
|
+
file_path: Path where to save the file
|
|
277
|
+
encoding: Text encoding (only used for string content)
|
|
278
|
+
"""
|
|
279
|
+
try:
|
|
280
|
+
if isinstance(content, bytes):
|
|
281
|
+
# Binary content (e.g., Excel, PowerPoint files)
|
|
282
|
+
async with aiofiles.open(file_path, 'wb') as f:
|
|
283
|
+
await f.write(content)
|
|
284
|
+
else:
|
|
285
|
+
# Text content (e.g., HTML, markdown, plain text)
|
|
286
|
+
encoding = encoding or 'utf-8'
|
|
287
|
+
async with aiofiles.open(file_path, 'w', encoding=encoding) as f:
|
|
288
|
+
await f.write(content)
|
|
289
|
+
|
|
290
|
+
self.logger.info(
|
|
291
|
+
f"Document saved successfully: {file_path}"
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
except Exception as e:
|
|
295
|
+
self.logger.error(
|
|
296
|
+
f"Error saving document to {file_path}: {e}"
|
|
297
|
+
)
|
|
298
|
+
raise
|
|
299
|
+
|
|
300
|
+
async def _get_file_size(self, file_path: Path) -> int:
|
|
301
|
+
"""
|
|
302
|
+
Get file size in bytes.
|
|
303
|
+
|
|
304
|
+
Args:
|
|
305
|
+
file_path: Path to the file
|
|
306
|
+
|
|
307
|
+
Returns:
|
|
308
|
+
File size in bytes
|
|
309
|
+
"""
|
|
310
|
+
try:
|
|
311
|
+
stat = await aiofiles.os.stat(file_path)
|
|
312
|
+
return stat.st_size
|
|
313
|
+
except Exception as e:
|
|
314
|
+
self.logger.error(f"Error getting file size for {file_path}: {e}")
|
|
315
|
+
return 0
|
|
316
|
+
|
|
317
|
+
async def _validate_file_size(self, file_path: Path) -> None:
|
|
318
|
+
"""
|
|
319
|
+
Validate that file size is within limits.
|
|
320
|
+
|
|
321
|
+
Args:
|
|
322
|
+
file_path: Path to the file
|
|
323
|
+
|
|
324
|
+
Raises:
|
|
325
|
+
ValueError: If file is too large
|
|
326
|
+
"""
|
|
327
|
+
file_size = await self._get_file_size(file_path)
|
|
328
|
+
file_size_mb = file_size / (1024 * 1024)
|
|
329
|
+
|
|
330
|
+
if file_size_mb > self.max_file_size_mb:
|
|
331
|
+
raise ValueError(
|
|
332
|
+
f"Generated file is too large: {file_size_mb:.2f}MB "
|
|
333
|
+
f"(max allowed: {self.max_file_size_mb}MB)"
|
|
334
|
+
)
|
|
335
|
+
|
|
336
|
+
async def _generate_document_metadata(
|
|
337
|
+
self,
|
|
338
|
+
file_path: Path,
|
|
339
|
+
content_length: int
|
|
340
|
+
) -> DocumentMetadata:
|
|
341
|
+
"""
|
|
342
|
+
Generate metadata for the created document.
|
|
343
|
+
|
|
344
|
+
Args:
|
|
345
|
+
file_path: Path to the generated file
|
|
346
|
+
content_length: Length of original content
|
|
347
|
+
|
|
348
|
+
Returns:
|
|
349
|
+
DocumentMetadata object
|
|
350
|
+
"""
|
|
351
|
+
file_size = await self._get_file_size(file_path)
|
|
352
|
+
file_url = self.to_static_url(file_path)
|
|
353
|
+
|
|
354
|
+
return DocumentMetadata(
|
|
355
|
+
filename=file_path.name,
|
|
356
|
+
file_path=str(file_path),
|
|
357
|
+
file_url=file_url,
|
|
358
|
+
relative_url=self.relative_url(file_url),
|
|
359
|
+
file_size=file_size,
|
|
360
|
+
file_size_mb=round(file_size / (1024 * 1024), 2),
|
|
361
|
+
file_extension=file_path.suffix.lstrip('.'),
|
|
362
|
+
created_at=datetime.now().isoformat(),
|
|
363
|
+
content_length=content_length
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
def _get_template_path(
|
|
367
|
+
self,
|
|
368
|
+
template_name: Optional[str]
|
|
369
|
+
) -> Optional[Path]:
|
|
370
|
+
"""
|
|
371
|
+
Get the full path to a template file.
|
|
372
|
+
|
|
373
|
+
Args:
|
|
374
|
+
template_name: Name of the template file
|
|
375
|
+
|
|
376
|
+
Returns:
|
|
377
|
+
Path to template file or None if not found
|
|
378
|
+
"""
|
|
379
|
+
if not template_name or not self.templates_dir:
|
|
380
|
+
return None
|
|
381
|
+
|
|
382
|
+
template_path = self.templates_dir / template_name
|
|
383
|
+
|
|
384
|
+
if template_path.exists():
|
|
385
|
+
return template_path
|
|
386
|
+
else:
|
|
387
|
+
self.logger.warning(f"Template not found: {template_path}")
|
|
388
|
+
return None
|
|
389
|
+
|
|
390
|
+
def _list_available_templates(
|
|
391
|
+
self,
|
|
392
|
+
extensions: Optional[List[str]] = None
|
|
393
|
+
) -> List[str]:
|
|
394
|
+
"""
|
|
395
|
+
List available template files.
|
|
396
|
+
|
|
397
|
+
Args:
|
|
398
|
+
extensions: File extensions to filter by (e.g., ['.pptx', '.potx'])
|
|
399
|
+
|
|
400
|
+
Returns:
|
|
401
|
+
List of template filenames
|
|
402
|
+
"""
|
|
403
|
+
if not self.templates_dir or not self.templates_dir.exists():
|
|
404
|
+
return []
|
|
405
|
+
|
|
406
|
+
templates = []
|
|
407
|
+
extensions = extensions or self.supported_extensions or [f'.{self.default_extension}']
|
|
408
|
+
|
|
409
|
+
for ext in extensions:
|
|
410
|
+
ext = ext if ext.startswith('.') else f'.{ext}'
|
|
411
|
+
templates.extend([
|
|
412
|
+
f.name for f in self.templates_dir.glob(f'*{ext}')
|
|
413
|
+
if f.is_file()
|
|
414
|
+
])
|
|
415
|
+
|
|
416
|
+
return sorted(templates)
|
|
417
|
+
|
|
418
|
+
async def _create_document_safely(
|
|
419
|
+
self,
|
|
420
|
+
content: str,
|
|
421
|
+
output_filename: Optional[str] = None,
|
|
422
|
+
file_prefix: str = "document",
|
|
423
|
+
output_dir: Optional[str] = None,
|
|
424
|
+
overwrite_existing: bool = False,
|
|
425
|
+
extension: Optional[str] = None,
|
|
426
|
+
**kwargs
|
|
427
|
+
) -> Dict[str, Any]:
|
|
428
|
+
"""
|
|
429
|
+
Safely create a document with all error handling and validation.
|
|
430
|
+
|
|
431
|
+
This method provides a complete workflow for document creation:
|
|
432
|
+
1. Validate input
|
|
433
|
+
2. Ensure output directory exists
|
|
434
|
+
3. Generate filename
|
|
435
|
+
4. Check for file conflicts
|
|
436
|
+
5. Create the document content
|
|
437
|
+
6. Save the file
|
|
438
|
+
7. Validate file size
|
|
439
|
+
8. Generate metadata
|
|
440
|
+
|
|
441
|
+
Args:
|
|
442
|
+
content: Content to convert to document
|
|
443
|
+
output_filename: Custom filename (without extension)
|
|
444
|
+
file_prefix: Prefix for auto-generated filenames
|
|
445
|
+
output_dir: Custom output directory
|
|
446
|
+
overwrite_existing: Whether to overwrite existing files
|
|
447
|
+
extension: File extension override
|
|
448
|
+
**kwargs: Additional arguments for document creation
|
|
449
|
+
|
|
450
|
+
Returns:
|
|
451
|
+
Dictionary with document metadata and status
|
|
452
|
+
"""
|
|
453
|
+
try:
|
|
454
|
+
# 1. Validate input
|
|
455
|
+
if isinstance(content, pd.DataFrame):
|
|
456
|
+
if content.empty:
|
|
457
|
+
raise ValueError("DataFrame content cannot be empty")
|
|
458
|
+
elif isinstance(content, str):
|
|
459
|
+
if not content.strip():
|
|
460
|
+
raise ValueError("Content cannot be empty")
|
|
461
|
+
elif not content:
|
|
462
|
+
raise ValueError("Content cannot be empty")
|
|
463
|
+
|
|
464
|
+
# 2. Ensure output directory exists
|
|
465
|
+
output_directory = await self._ensure_output_directory(output_dir)
|
|
466
|
+
|
|
467
|
+
# 3. Generate filename
|
|
468
|
+
filename = self._generate_document_filename(
|
|
469
|
+
output_filename, file_prefix, extension
|
|
470
|
+
)
|
|
471
|
+
file_path = output_directory / filename
|
|
472
|
+
# 4. Check for file conflicts
|
|
473
|
+
await self._check_file_exists(file_path, overwrite_existing)
|
|
474
|
+
# 5. Create document content (implemented by subclasses)
|
|
475
|
+
document_content = await self._generate_document_content(content, **kwargs)
|
|
476
|
+
# 6. Save the file
|
|
477
|
+
await self._save_document_content(document_content, file_path)
|
|
478
|
+
# 7. Validate file size
|
|
479
|
+
await self._validate_file_size(file_path)
|
|
480
|
+
# 8. Generate metadata
|
|
481
|
+
metadata = await self._generate_document_metadata(file_path, len(content))
|
|
482
|
+
self.logger.info(f"Document created successfully: {filename}")
|
|
483
|
+
|
|
484
|
+
return {
|
|
485
|
+
"status": "success",
|
|
486
|
+
"message": f"{self.document_type.title()} created successfully",
|
|
487
|
+
"metadata": metadata.model_dump(),
|
|
488
|
+
**metadata.model_dump() # For backward compatibility
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
except Exception as e:
|
|
492
|
+
self.logger.error(f"Error creating {self.document_type}: {e}")
|
|
493
|
+
return {
|
|
494
|
+
"status": "error",
|
|
495
|
+
"error": str(e),
|
|
496
|
+
"message": f"Failed to create {self.document_type}: {str(e)}"
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
@abstractmethod
|
|
500
|
+
async def _generate_document_content(self, content: str, **kwargs) -> Union[bytes, str]:
|
|
501
|
+
"""
|
|
502
|
+
Generate the actual document content.
|
|
503
|
+
|
|
504
|
+
This method must be implemented by subclasses to create the specific
|
|
505
|
+
document format (PowerPoint, Word, Excel, etc.).
|
|
506
|
+
|
|
507
|
+
Args:
|
|
508
|
+
content: Input content to convert
|
|
509
|
+
**kwargs: Additional arguments specific to the document type
|
|
510
|
+
|
|
511
|
+
Returns:
|
|
512
|
+
Document content as bytes (for binary formats) or string (for text formats)
|
|
513
|
+
"""
|
|
514
|
+
pass
|
|
515
|
+
|
|
516
|
+
# Utility methods for subclasses
|
|
517
|
+
|
|
518
|
+
def get_supported_extensions(self) -> List[str]:
|
|
519
|
+
"""Get list of supported file extensions for this document type."""
|
|
520
|
+
return self.supported_extensions or [self.default_extension]
|
|
521
|
+
|
|
522
|
+
def get_available_templates(self) -> List[str]:
|
|
523
|
+
"""Get list of available template files."""
|
|
524
|
+
return self._list_available_templates()
|
|
525
|
+
|
|
526
|
+
async def template_exists(self, template_name: str) -> bool:
|
|
527
|
+
"""Check if a template file exists."""
|
|
528
|
+
template_path = self._get_template_path(template_name)
|
|
529
|
+
return template_path is not None and await aiofiles.os.path.exists(template_path)
|
|
530
|
+
|
|
531
|
+
def get_document_info(self) -> Dict[str, Any]:
|
|
532
|
+
"""Get information about this document tool."""
|
|
533
|
+
return {
|
|
534
|
+
"document_type": self.document_type,
|
|
535
|
+
"default_extension": self.default_extension,
|
|
536
|
+
"supported_extensions": self.get_supported_extensions(),
|
|
537
|
+
"templates_dir": str(self.templates_dir) if self.templates_dir else None,
|
|
538
|
+
"available_templates": self.get_available_templates(),
|
|
539
|
+
"output_dir": str(self.output_dir),
|
|
540
|
+
"max_file_size_mb": self.max_file_size_mb
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
def _get_current_date(self) -> str:
|
|
544
|
+
"""Get current date in YYYY-MM-DD format."""
|
|
545
|
+
return datetime.now().strftime('%Y-%m-%d')
|
|
546
|
+
|
|
547
|
+
def _get_current_timestamp(self) -> str:
|
|
548
|
+
"""Get current timestamp in ISO format."""
|
|
549
|
+
return datetime.now().isoformat()
|