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
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
"""
|
|
2
|
+
StoreInfo toolkit for store information and demographic analysis.
|
|
3
|
+
"""
|
|
4
|
+
from typing import Dict, Any, List, Optional, Union, Literal, Callable
|
|
5
|
+
from datetime import datetime, time
|
|
6
|
+
from pydantic import BaseModel, Field
|
|
7
|
+
import pandas as pd
|
|
8
|
+
from ..decorators import tool_schema
|
|
9
|
+
from .base import BaseNextStop
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# Pydantic models for structured outputs
|
|
13
|
+
class StoreBasicInfo(BaseModel):
|
|
14
|
+
"""Basic store information model."""
|
|
15
|
+
store_id: str = Field(description="Unique store identifier")
|
|
16
|
+
store_name: Optional[str] = Field(default=None, description="Store name")
|
|
17
|
+
street_address: Optional[str] = Field(default=None, description="Store address")
|
|
18
|
+
city: Optional[str] = Field(default=None, description="City")
|
|
19
|
+
state_name: Optional[str] = Field(default=None, description="State")
|
|
20
|
+
state_code: Optional[str] = Field(default=None, description="State code")
|
|
21
|
+
zipcode: Optional[str] = Field(default=None, description="ZIP code")
|
|
22
|
+
latitude: Optional[float] = Field(default=None, description="Latitude coordinate")
|
|
23
|
+
longitude: Optional[float] = Field(default=None, description="Longitude coordinate")
|
|
24
|
+
account_name: Optional[str] = Field(default=None, description="Account name")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class FootTrafficData(BaseModel):
|
|
28
|
+
"""Foot traffic data model."""
|
|
29
|
+
store_id: str = Field(description="Store identifier")
|
|
30
|
+
start_date: datetime = Field(description="Start date of the traffic period")
|
|
31
|
+
avg_visits_per_day: Optional[float] = Field(default=None, description="Average visits per day")
|
|
32
|
+
foottraffic: Optional[int] = Field(default=None, description="Total foot traffic")
|
|
33
|
+
visits_by_day_of_week_monday: Optional[int] = Field(default=None, description="Monday visits")
|
|
34
|
+
visits_by_day_of_week_tuesday: Optional[int] = Field(default=None, description="Tuesday visits")
|
|
35
|
+
visits_by_day_of_week_wednesday: Optional[int] = Field(default=None, description="Wednesday visits")
|
|
36
|
+
visits_by_day_of_week_thursday: Optional[int] = Field(default=None, description="Thursday visits")
|
|
37
|
+
visits_by_day_of_week_friday: Optional[int] = Field(default=None, description="Friday visits")
|
|
38
|
+
visits_by_day_of_week_saturday: Optional[int] = Field(default=None, description="Saturday visits")
|
|
39
|
+
visits_by_day_of_week_sunday: Optional[int] = Field(default=None, description="Sunday visits")
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class FootTrafficSearch(BaseModel):
|
|
43
|
+
"""Foot traffic search model."""
|
|
44
|
+
state_code: str = Field(description="State code")
|
|
45
|
+
retailer_name: str = Field(description="Retailer name")
|
|
46
|
+
limit: int = Field(default=10, description="Number of results to return")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class FootTrafficInfo(BaseModel):
|
|
50
|
+
"""Foot traffic information model."""
|
|
51
|
+
store_id: str = Field(description="Store identifier")
|
|
52
|
+
store_number: Optional[str] = Field(default=None, description="Store number")
|
|
53
|
+
store_name: Optional[str] = Field(default=None, description="Store name")
|
|
54
|
+
state_name: Optional[str] = Field(default=None, description="State name")
|
|
55
|
+
city: Optional[str] = Field(default=None, description="City name")
|
|
56
|
+
state_code: Optional[str] = Field(default=None, description="State code")
|
|
57
|
+
zipcode: Optional[str] = Field(default=None, description="ZIP code")
|
|
58
|
+
street_address: Optional[str] = Field(default=None, description="Street address")
|
|
59
|
+
foottraffic: Optional[int] = Field(default=None, description="Average of foot traffic")
|
|
60
|
+
|
|
61
|
+
class VisitInfo(BaseModel):
|
|
62
|
+
"""Visit information model."""
|
|
63
|
+
# Basic visit info
|
|
64
|
+
form_id: int = Field(default=None, description="Form identifier")
|
|
65
|
+
formid: int = Field(default=None, description="Form ID")
|
|
66
|
+
visit_date: Optional[datetime] = Field(default=None, description="Date of visit")
|
|
67
|
+
visitor_name: Optional[str] = Field(default=None, description="Visitor name")
|
|
68
|
+
visitor_username: Optional[str] = Field(default=None, description="Visitor username")
|
|
69
|
+
visit_timestamp: Optional[datetime] = Field(default=None, description="Visit timestamp")
|
|
70
|
+
visit_length: Optional[float] = Field(default=None, description="Visit length")
|
|
71
|
+
time_in: Optional[time] = Field(default=None, description="Check-in time")
|
|
72
|
+
time_out: Optional[time] = Field(default=None, description="Check-out time")
|
|
73
|
+
store_id: str = Field(description="Store identifier")
|
|
74
|
+
visit_dow: Optional[int] = Field(default=None, description="Day of week (0=Monday)")
|
|
75
|
+
visit_hour: Optional[int] = Field(default=None, description="Hour of visit")
|
|
76
|
+
alt_store: Optional[str] = Field(default=None, description="Alternative store name")
|
|
77
|
+
time_spent_minutes: Optional[float] = Field(default=None, description="Time spent in minutes")
|
|
78
|
+
visit_data: Optional[List[Dict[str, Any]]] = Field(default=None, description="Visit data aggregated")
|
|
79
|
+
# Aggreated questions:
|
|
80
|
+
questions: Optional[Dict[str, List[Dict[str, Any]]]] = Field(
|
|
81
|
+
default=None,
|
|
82
|
+
description="Aggregated visit questions and answers organized by question type"
|
|
83
|
+
)
|
|
84
|
+
# Visitor statistics
|
|
85
|
+
number_of_visits: Optional[int] = Field(default=None, description="Total number of visits by this visitor")
|
|
86
|
+
latest_visit_date: Optional[datetime] = Field(default=None, description="Latest visit date for this visitor")
|
|
87
|
+
visited_stores: Optional[int] = Field(default=None, description="Number of stores visited by this visitor")
|
|
88
|
+
average_hour_visit: Optional[float] = Field(default=None, description="Average hour of visits")
|
|
89
|
+
most_frequent_hour_of_day: Optional[int] = Field(default=None, description="Most frequent hour of day")
|
|
90
|
+
most_frequent_day_of_week: Optional[int] = Field(default=None, description="Most frequent day of week")
|
|
91
|
+
day_of_week: Optional[str] = Field(default=None, description="Day of week name")
|
|
92
|
+
median_visits_per_store: Optional[float] = Field(default=None, description="Median visits per store")
|
|
93
|
+
median_visit_duration: Optional[float] = Field(default=None, description="Median visit duration")
|
|
94
|
+
|
|
95
|
+
# Input schemas for tools
|
|
96
|
+
class StoreInfoInput(BaseModel):
|
|
97
|
+
"""Input schema for store information queries."""
|
|
98
|
+
store_id: str = Field(description="The unique identifier of the store")
|
|
99
|
+
program: Optional[str] = Field(
|
|
100
|
+
default=None,
|
|
101
|
+
description="Program slug for the store (e.g., 'hisense', 'epson')"
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class FootTrafficInput(BaseModel):
|
|
106
|
+
"""Input schema for foot traffic queries."""
|
|
107
|
+
store_id: str = Field(description="The unique identifier of the store")
|
|
108
|
+
output_format: Literal["pandas", "structured"] = Field(
|
|
109
|
+
default="structured",
|
|
110
|
+
description="Output format: 'pandas' for DataFrame, 'structured' for Pydantic models"
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class VisitInfoInput(BaseModel):
|
|
115
|
+
"""Input schema for visit information queries."""
|
|
116
|
+
store_id: str = Field(description="The unique identifier of the store")
|
|
117
|
+
program_slug: Optional[str] = Field(
|
|
118
|
+
default=None,
|
|
119
|
+
description="Program slug for the store (e.g., 'hisense', 'epson')"
|
|
120
|
+
)
|
|
121
|
+
limit: int = Field(default=10, description="Maximum number of visits to retrieve")
|
|
122
|
+
output_format: Literal["pandas", "structured"] = Field(
|
|
123
|
+
default="structured",
|
|
124
|
+
description="Output format: 'pandas' for DataFrame, 'structured' for Pydantic models"
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
class VisitQuestionInput(BaseModel):
|
|
128
|
+
"""Input schema for visit question queries."""
|
|
129
|
+
store_id: str = Field(description="The unique identifier of the store")
|
|
130
|
+
program_slug: Optional[str] = Field(
|
|
131
|
+
default=None,
|
|
132
|
+
description="Program slug for the store (e.g., 'hisense', 'epson')"
|
|
133
|
+
)
|
|
134
|
+
limit: int = Field(default=5, description="Maximum number of visits to retrieve")
|
|
135
|
+
|
|
136
|
+
class StoreSearchInput(BaseModel):
|
|
137
|
+
"""Input schema for store search queries."""
|
|
138
|
+
city: Optional[str] = Field(default=None, description="City name to search for stores")
|
|
139
|
+
state_name: Optional[str] = Field(default=None, description="US State Name")
|
|
140
|
+
zipcode: Optional[str] = Field(default=None, description="ZIP code")
|
|
141
|
+
limit: int = Field(default=50, description="Maximum number of stores to return")
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
class DatasetQueryInput(BaseModel):
|
|
145
|
+
"""Input schema for custom dataset queries."""
|
|
146
|
+
query: str = Field(description="SQL query to execute")
|
|
147
|
+
output_format: Literal["pandas", "dict"] = Field(
|
|
148
|
+
default="pandas",
|
|
149
|
+
description="Output format: 'pandas' for DataFrame, 'dict' for dictionary"
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
class StoreInfo(BaseNextStop):
|
|
154
|
+
"""Comprehensive toolkit for store information and demographic analysis.
|
|
155
|
+
|
|
156
|
+
This toolkit provides tools to:
|
|
157
|
+
1. get_visit_information: Get visit information for an store including recent visit history.
|
|
158
|
+
2. get_store_information: Retrieve comprehensive store information including location and visit statistics
|
|
159
|
+
3. get_foot_traffic: Foot traffic analysis for stores, providing insights into customer behavior
|
|
160
|
+
4. search_stores: Search for stores by location (city, state, zipcode)
|
|
161
|
+
|
|
162
|
+
All tools are designed to work asynchronously with database connections and external APIs.
|
|
163
|
+
"""
|
|
164
|
+
def _pad_storeid(self, store_id: str , width: int = 4) -> str:
|
|
165
|
+
"""Pad the store ID with leading zeros to ensure it has a fixed width.
|
|
166
|
+
|
|
167
|
+
Split a store id into prefix + numeric suffix and zero-fill the number.
|
|
168
|
+
|
|
169
|
+
Examples:
|
|
170
|
+
pad_store_id("BBY599") -> "BBY0599"
|
|
171
|
+
pad_store_id("BBY4") -> "BBY0004"
|
|
172
|
+
"""
|
|
173
|
+
if self.program != "hisense":
|
|
174
|
+
return store_id.strip() # No padding needed for other programs
|
|
175
|
+
|
|
176
|
+
# Ensure the store_id is a string and strip whitespace
|
|
177
|
+
store_id = str(store_id)
|
|
178
|
+
if not store_id:
|
|
179
|
+
raise ValueError("Store ID cannot be empty")
|
|
180
|
+
s = store_id.strip()
|
|
181
|
+
# extract non-numeric characters as prefix
|
|
182
|
+
prefix = ''.join(filter(str.isalpha, s))
|
|
183
|
+
# extract the suffix from store_id, to get the numeric part:
|
|
184
|
+
s = s.replace(prefix, '', 1)
|
|
185
|
+
if len(s) < width:
|
|
186
|
+
# zero-fill the numeric part to the specified width
|
|
187
|
+
s = s.lstrip('0') # remove leading zeros first
|
|
188
|
+
numeric_suffix = s.zfill(width)
|
|
189
|
+
else:
|
|
190
|
+
numeric_suffix = s
|
|
191
|
+
return f"{prefix}{numeric_suffix}"
|
|
192
|
+
|
|
193
|
+
@tool_schema(FootTrafficInput)
|
|
194
|
+
async def get_foot_traffic(
|
|
195
|
+
self,
|
|
196
|
+
store_id: str,
|
|
197
|
+
output_format: str = "structured"
|
|
198
|
+
) -> Union[pd.DataFrame, List[FootTrafficData]]:
|
|
199
|
+
"""Get foot traffic data for a specific store.
|
|
200
|
+
This method retrieves the foot traffic data for the specified store,
|
|
201
|
+
including the number of visitors and average visits per day.
|
|
202
|
+
"""
|
|
203
|
+
sql = await self._get_query("foot_traffic")
|
|
204
|
+
sql = sql.format(store_id=store_id)
|
|
205
|
+
|
|
206
|
+
# Fetch the foot traffic data
|
|
207
|
+
try:
|
|
208
|
+
return await self._get_dataset(
|
|
209
|
+
sql,
|
|
210
|
+
output_format=output_format,
|
|
211
|
+
structured_obj=FootTrafficData if output_format == "structured" else None
|
|
212
|
+
)
|
|
213
|
+
except ValueError as ve:
|
|
214
|
+
return f"No Traffic data found for the specified store, error: {ve}"
|
|
215
|
+
except Exception as e:
|
|
216
|
+
return f"Error fetching foot traffic data: {e}"
|
|
217
|
+
|
|
218
|
+
@tool_schema(FootTrafficSearch)
|
|
219
|
+
async def get_foot_traffic_average(
|
|
220
|
+
self,
|
|
221
|
+
state_code: str,
|
|
222
|
+
retailer_name: str,
|
|
223
|
+
limit: int = 10,
|
|
224
|
+
output_format: str = "structured"
|
|
225
|
+
) -> Union[pd.DataFrame, List[FootTrafficInfo]]:
|
|
226
|
+
"""Get foot traffic data for a specific store.
|
|
227
|
+
This method retrieves the foot traffic data for the specified store,
|
|
228
|
+
including the number of visitors and average visits per day.
|
|
229
|
+
"""
|
|
230
|
+
sql = await self._get_query("foot_traffic_avg")
|
|
231
|
+
sql = sql.format(state_code=state_code, retailer_name=retailer_name, limit=limit)
|
|
232
|
+
|
|
233
|
+
# Fetch the foot traffic data
|
|
234
|
+
try:
|
|
235
|
+
return await self._get_dataset(
|
|
236
|
+
sql,
|
|
237
|
+
output_format=output_format,
|
|
238
|
+
structured_obj=FootTrafficInfo if output_format == "structured" else None
|
|
239
|
+
)
|
|
240
|
+
except ValueError as ve:
|
|
241
|
+
return f"No Traffic data found for the specified store, error: {ve}"
|
|
242
|
+
except Exception as e:
|
|
243
|
+
return f"Error fetching foot traffic data: {e}"
|
|
244
|
+
|
|
245
|
+
async def _get_visits(
|
|
246
|
+
self,
|
|
247
|
+
store_id: str,
|
|
248
|
+
limit: int = 5,
|
|
249
|
+
output_format: str = "structured"
|
|
250
|
+
) -> List[VisitInfo]:
|
|
251
|
+
"""Internal method to fetch visit information for a store.
|
|
252
|
+
|
|
253
|
+
Args:
|
|
254
|
+
store_id: The unique identifier of the store
|
|
255
|
+
limit: Maximum number of visits to retrieve
|
|
256
|
+
output_format: Output format - 'pandas' for DataFrame, 'structured' for Pydantic models
|
|
257
|
+
|
|
258
|
+
Returns:
|
|
259
|
+
List[VisitInfo]: List of visit information objects
|
|
260
|
+
"""
|
|
261
|
+
|
|
262
|
+
sql = await self._get_query("store_visits")
|
|
263
|
+
store_id = self._pad_storeid(store_id)
|
|
264
|
+
sql = sql.format(store_id=store_id, program_slug=self.program, limit=limit)
|
|
265
|
+
print('STORE QUERY > ', sql)
|
|
266
|
+
try:
|
|
267
|
+
return await self._get_dataset(
|
|
268
|
+
sql,
|
|
269
|
+
output_format=output_format,
|
|
270
|
+
structured_obj=VisitInfo if output_format == "structured" else None
|
|
271
|
+
)
|
|
272
|
+
except ValueError as ve:
|
|
273
|
+
return f"No visit information found for the specified store, error: {ve}"
|
|
274
|
+
except Exception as e:
|
|
275
|
+
return f"Error fetching visit information: {e}"
|
|
276
|
+
|
|
277
|
+
@tool_schema(VisitInfoInput)
|
|
278
|
+
async def get_visit_information(
|
|
279
|
+
self,
|
|
280
|
+
store_id: str,
|
|
281
|
+
limit: int = 3,
|
|
282
|
+
output_format: str = "structured",
|
|
283
|
+
program_slug: Optional[str] = None
|
|
284
|
+
) -> Union[pd.DataFrame, List[VisitInfo]]:
|
|
285
|
+
"""Get visit information for a specific store.
|
|
286
|
+
|
|
287
|
+
This method retrieves visit information for the specified store,
|
|
288
|
+
including visitor statistics and aggregated visit data.
|
|
289
|
+
"""
|
|
290
|
+
try:
|
|
291
|
+
# Ensure the program is set correctly
|
|
292
|
+
if program_slug:
|
|
293
|
+
self.program = program_slug
|
|
294
|
+
visits = await self._get_visits(store_id, limit, output_format)
|
|
295
|
+
if isinstance(visits, str): # If an error message was returned
|
|
296
|
+
return visits
|
|
297
|
+
|
|
298
|
+
return visits
|
|
299
|
+
except ValueError as ve:
|
|
300
|
+
return f"No visit information found for the specified store, error: {ve}"
|
|
301
|
+
except Exception as e:
|
|
302
|
+
return f"Error fetching visit information: {e}"
|
|
303
|
+
|
|
304
|
+
@tool_schema(VisitQuestionInput)
|
|
305
|
+
async def get_visit_questions(
|
|
306
|
+
self,
|
|
307
|
+
store_id: str,
|
|
308
|
+
program_slug: Optional[str] = None,
|
|
309
|
+
limit: int = 3
|
|
310
|
+
) -> Dict[str, List[Dict[str, Any]]]:
|
|
311
|
+
"""
|
|
312
|
+
Get visit information for a specific store, focusing on questions and answers.
|
|
313
|
+
"""
|
|
314
|
+
if program_slug:
|
|
315
|
+
self.program = program_slug
|
|
316
|
+
visits = await self._get_visits(
|
|
317
|
+
store_id,
|
|
318
|
+
limit,
|
|
319
|
+
"structured"
|
|
320
|
+
)
|
|
321
|
+
if isinstance(visits, str): # If an error message was returned
|
|
322
|
+
return visits
|
|
323
|
+
|
|
324
|
+
question_data = {
|
|
325
|
+
'9730': [], # Key Wins
|
|
326
|
+
'9731': [], # Challenges
|
|
327
|
+
'9732': [], # Next Focus
|
|
328
|
+
'9733': [] # Competitive
|
|
329
|
+
}
|
|
330
|
+
for row_index, visit in enumerate(visits):
|
|
331
|
+
if not visit.visit_data:
|
|
332
|
+
continue
|
|
333
|
+
|
|
334
|
+
for qa_item in visit.visit_data:
|
|
335
|
+
column_name = qa_item.get('column_name')
|
|
336
|
+
if column_name in question_data:
|
|
337
|
+
# first: truncate answer if is too long
|
|
338
|
+
answer = qa_item.get('answer', '')
|
|
339
|
+
if answer is None:
|
|
340
|
+
answer = "No answer provided"
|
|
341
|
+
if len(answer) > 100:
|
|
342
|
+
answer = answer[:100] + '...'
|
|
343
|
+
question_data[column_name].append({
|
|
344
|
+
'answer': answer,
|
|
345
|
+
'row_index': row_index,
|
|
346
|
+
'visitor': visit.visitor_username,
|
|
347
|
+
'visit_date': visit.visit_date.isoformat() if visit.visit_date else None,
|
|
348
|
+
'store_id': visit.store_id,
|
|
349
|
+
'visit_length': visit.visit_length,
|
|
350
|
+
'question_text': qa_item.get('question', ''),
|
|
351
|
+
'time_in': visit.time_in.isoformat() if visit.time_in else None,
|
|
352
|
+
'time_out': visit.time_out.isoformat() if visit.time_out else None,
|
|
353
|
+
'visit_dow': visit.visit_dow,
|
|
354
|
+
'visit_hour': visit.visit_hour,
|
|
355
|
+
'day_of_week': visit.day_of_week,
|
|
356
|
+
'time_spent_minutes': visit.time_spent_minutes
|
|
357
|
+
})
|
|
358
|
+
return question_data
|
|
359
|
+
|
|
360
|
+
@tool_schema(StoreInfoInput)
|
|
361
|
+
async def get_store_information(self, store_id: str, program: str) -> StoreBasicInfo:
|
|
362
|
+
"""Get comprehensive store information including location and basic details,
|
|
363
|
+
contact information, operating hours, and aggregate visit statistics.
|
|
364
|
+
Provides total visits, unique visitors, and average visit duration
|
|
365
|
+
for the specified store. Essential for store analysis and planning.
|
|
366
|
+
"""
|
|
367
|
+
# Ensure the program is set correctly
|
|
368
|
+
if program:
|
|
369
|
+
self.program = program
|
|
370
|
+
sql = await self._get_query("store_info")
|
|
371
|
+
store_id = self._pad_storeid(store_id)
|
|
372
|
+
sql = sql.format(store_id=store_id, limit=3)
|
|
373
|
+
|
|
374
|
+
# Fetch the store data
|
|
375
|
+
try:
|
|
376
|
+
store_data = await self._get_dataset(sql, output_format='pandas')
|
|
377
|
+
except Exception as e:
|
|
378
|
+
return f"Error fetching store information: {e}"
|
|
379
|
+
|
|
380
|
+
if store_data.empty:
|
|
381
|
+
return f"No store found with ID {store_id}"
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
# Convert first row to Pydantic model
|
|
385
|
+
store_info = store_data.iloc[0].to_dict()
|
|
386
|
+
return StoreBasicInfo(**store_info)
|
|
387
|
+
|
|
388
|
+
@tool_schema(StoreSearchInput)
|
|
389
|
+
async def search_stores(
|
|
390
|
+
self,
|
|
391
|
+
city: Optional[str] = None,
|
|
392
|
+
state_name: Optional[str] = None,
|
|
393
|
+
zipcode: Optional[str] = None,
|
|
394
|
+
limit: int = 50
|
|
395
|
+
) -> List[StoreBasicInfo]:
|
|
396
|
+
"""
|
|
397
|
+
Search for stores based on city, state, or zipcode.
|
|
398
|
+
"""
|
|
399
|
+
# Build WHERE clause based on provided criteria
|
|
400
|
+
conditions = []
|
|
401
|
+
if city:
|
|
402
|
+
conditions.append(f"LOWER(s.city) LIKE LOWER('%{city}%')")
|
|
403
|
+
if state_name:
|
|
404
|
+
conditions.append(f"LOWER(c.state_name) LIKE LOWER('%{state_name}%')")
|
|
405
|
+
if zipcode:
|
|
406
|
+
conditions.append(f"s.zipcode = '{zipcode}'")
|
|
407
|
+
|
|
408
|
+
if not conditions:
|
|
409
|
+
raise ValueError("At least one search criterion (city, state, or zipcode) must be provided")
|
|
410
|
+
|
|
411
|
+
where_clause = " AND ".join(conditions)
|
|
412
|
+
|
|
413
|
+
sql = f"""
|
|
414
|
+
SELECT DISTINCT ON (s.city, s.zipcode) store_id, store_name, street_address, c.city,
|
|
415
|
+
s.latitude, s.longitude, account_name, c.state_code, c.state_name
|
|
416
|
+
FROM troc.stores s
|
|
417
|
+
JOIN datasets.usa_cities c on s.zipcode = c.zipcode and s.city = c.city
|
|
418
|
+
WHERE program_slug = '{self.program}'
|
|
419
|
+
AND {where_clause}
|
|
420
|
+
"""
|
|
421
|
+
try:
|
|
422
|
+
stores_data = await self._get_dataset(sql, output_format='pandas')
|
|
423
|
+
except Exception as e:
|
|
424
|
+
return f"Error searching for stores: {e}"
|
|
425
|
+
|
|
426
|
+
if stores_data.empty:
|
|
427
|
+
search_terms = []
|
|
428
|
+
if city:
|
|
429
|
+
search_terms.append(f"city: {city}")
|
|
430
|
+
if state_name:
|
|
431
|
+
search_terms.append(f"state: {state_name}")
|
|
432
|
+
if zipcode:
|
|
433
|
+
search_terms.append(f"zipcode: {zipcode}")
|
|
434
|
+
|
|
435
|
+
return f"No stores found matching the criteria: {', '.join(search_terms)}."
|
|
436
|
+
|
|
437
|
+
# Convert DataFrame to list of Pydantic models
|
|
438
|
+
stores = []
|
|
439
|
+
for _, row in stores_data.iterrows():
|
|
440
|
+
stores.append(StoreBasicInfo(**row.to_dict()))
|
|
441
|
+
|
|
442
|
+
return stores
|
|
443
|
+
|
|
444
|
+
# @tool_schema(DatasetQueryInput)
|
|
445
|
+
# async def get_custom_dataset(
|
|
446
|
+
# self,
|
|
447
|
+
# query: str,
|
|
448
|
+
# output_format: str = "pandas"
|
|
449
|
+
# ) -> Union[pd.DataFrame, Dict[str, Any]]:
|
|
450
|
+
# """Execute a custom SQL query and return the dataset.
|
|
451
|
+
|
|
452
|
+
# Args:
|
|
453
|
+
# query: SQL query to execute
|
|
454
|
+
# output_format: Output format - 'pandas' for DataFrame, 'dict' for dictionary
|
|
455
|
+
|
|
456
|
+
# Returns:
|
|
457
|
+
# Union[pd.DataFrame, Dict]: Query results in requested format
|
|
458
|
+
# """
|
|
459
|
+
# try:
|
|
460
|
+
# return await self._get_dataset(query, output_format=output_format)
|
|
461
|
+
# except Exception as e:
|
|
462
|
+
# return f"Error executing custom query: {str(e)}. Please check your SQL syntax and table names."
|