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/clients/hf.py
ADDED
|
@@ -0,0 +1,582 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TransformersClient for ai-parrot framework.
|
|
3
|
+
Supports micro-LLMs from HuggingFace transformers for small tasks.
|
|
4
|
+
"""
|
|
5
|
+
import asyncio
|
|
6
|
+
import logging
|
|
7
|
+
import uuid
|
|
8
|
+
import time
|
|
9
|
+
from typing import Any, AsyncIterator, Dict, List, Optional, Union
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from enum import Enum
|
|
12
|
+
|
|
13
|
+
import torch
|
|
14
|
+
from transformers import (
|
|
15
|
+
AutoModelForCausalLM,
|
|
16
|
+
AutoTokenizer,
|
|
17
|
+
GenerationConfig
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
from .base import AbstractClient, MessageResponse, StreamingRetryConfig
|
|
21
|
+
from ..models import (
|
|
22
|
+
AIMessage,
|
|
23
|
+
AIMessageFactory,
|
|
24
|
+
CompletionUsage,
|
|
25
|
+
StructuredOutputConfig,
|
|
26
|
+
OutputFormat
|
|
27
|
+
)
|
|
28
|
+
from ..memory import ConversationHistory, ConversationTurn
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class TransformersModel(Enum):
|
|
32
|
+
"""Enum for supported transformer models."""
|
|
33
|
+
DIALOPT_MEDIUM = "microsoft/DialoGPT-medium"
|
|
34
|
+
DIALOPT_SMALL = "microsoft/DialoGPT-small"
|
|
35
|
+
DIALOPT_LARGE = "microsoft/DialoGPT-large"
|
|
36
|
+
TINY_LLM = "arnir0/Tiny-LLM"
|
|
37
|
+
GEMMA_2B = "google/gemma-2-2b-it"
|
|
38
|
+
GEMMA_9B = "google/gemma-2-9b-it"
|
|
39
|
+
GEMMA_3_4B = "google/gemma-3-4b-it"
|
|
40
|
+
GEMMA_3_1B = "google/gemma-3-1b-pt"
|
|
41
|
+
QWEN_1_5B = "Qwen/Qwen2.5-1.5B-Instruct"
|
|
42
|
+
QWEN_3B = "Qwen/Qwen2.5-3B-Instruct"
|
|
43
|
+
QWEN_7B = "Qwen/Qwen2.5-7B-Instruct"
|
|
44
|
+
BCCARD_QWEN_32B = "BCCard/Qwen2.5-VL-32B-Instruct-FP8-Dynamic"
|
|
45
|
+
PHI_3_MINI = "microsoft/Phi-3-mini-4k-instruct"
|
|
46
|
+
PHI_3_SMALL = "microsoft/Phi-3-small-8k-instruct"
|
|
47
|
+
PHI_3_5_MINI = "microsoft/Phi-3.5-mini-instruct"
|
|
48
|
+
OPENAI_GPT_20B = "openai/gpt-oss-20b"
|
|
49
|
+
HUGGINGFACE_TB_SMOLLM2_1_7B = "HuggingFaceTB/SmolLM2-1.7B"
|
|
50
|
+
DEEPSEEK_R1_1B = "deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B"
|
|
51
|
+
DEEPSEEK_R1_7B = "deepseek-ai/DeepSeek-R1-Distill-Qwen-7B"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class TransformersClient(AbstractClient):
|
|
55
|
+
"""
|
|
56
|
+
Client for interacting with HuggingFace transformers micro-LLMs.
|
|
57
|
+
|
|
58
|
+
This client is designed for small, local models that can run efficiently
|
|
59
|
+
on CPU or single GPU setups for quick tasks and lightweight inference.
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
client_type: str = "transformers"
|
|
63
|
+
client_name: str = "transformers"
|
|
64
|
+
|
|
65
|
+
def __init__(
|
|
66
|
+
self,
|
|
67
|
+
model: Union[str, TransformersModel] = TransformersModel.QWEN_3B,
|
|
68
|
+
device: Optional[str] = None,
|
|
69
|
+
torch_dtype: Optional[torch.dtype] = None,
|
|
70
|
+
trust_remote_code: bool = False,
|
|
71
|
+
use_fast_tokenizer: bool = True,
|
|
72
|
+
**kwargs
|
|
73
|
+
):
|
|
74
|
+
"""
|
|
75
|
+
Initialize the TransformersClient.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
model: Model name or TransformersModel enum
|
|
79
|
+
device: Device to run the model on ('cpu', 'cuda', 'auto')
|
|
80
|
+
torch_dtype: PyTorch data type for the model
|
|
81
|
+
trust_remote_code: Whether to trust remote code
|
|
82
|
+
use_fast_tokenizer: Whether to use fast tokenizer
|
|
83
|
+
**kwargs: Additional arguments for AbstractClient
|
|
84
|
+
"""
|
|
85
|
+
super().__init__(**kwargs)
|
|
86
|
+
|
|
87
|
+
# Model configuration
|
|
88
|
+
self.model_name = model.value if isinstance(model, TransformersModel) else model
|
|
89
|
+
self.client_name = self.model_name.split("/")[-1] # Use last part of model name as client name
|
|
90
|
+
self.device = device or ("cuda" if torch.cuda.is_available() else "cpu")
|
|
91
|
+
self.torch_dtype = torch_dtype or (torch.float16 if torch.cuda.is_available() else torch.float32)
|
|
92
|
+
self.trust_remote_code = trust_remote_code
|
|
93
|
+
self.use_fast_tokenizer = use_fast_tokenizer
|
|
94
|
+
|
|
95
|
+
# Model and tokenizer (will be loaded lazily)
|
|
96
|
+
self.model = None
|
|
97
|
+
self.tokenizer = None
|
|
98
|
+
|
|
99
|
+
# Generation configuration
|
|
100
|
+
self.generation_config = GenerationConfig(
|
|
101
|
+
max_new_tokens=512,
|
|
102
|
+
temperature=0.7,
|
|
103
|
+
top_p=0.9,
|
|
104
|
+
top_k=50,
|
|
105
|
+
do_sample=True,
|
|
106
|
+
pad_token_id=None, # Will be set after tokenizer is loaded
|
|
107
|
+
eos_token_id=None, # Will be set after tokenizer is loaded
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
self.logger = logging.getLogger(
|
|
111
|
+
f"parrot.TransformersClient.{self.model_name}"
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
async def get_client(self) -> Any:
|
|
115
|
+
"""Initialize the client context and load the model."""
|
|
116
|
+
await self._load_model()
|
|
117
|
+
return self.model
|
|
118
|
+
|
|
119
|
+
async def close(self):
|
|
120
|
+
"""Clean up resources."""
|
|
121
|
+
await self.clear_model()
|
|
122
|
+
await super().close()
|
|
123
|
+
|
|
124
|
+
async def _load_model(self):
|
|
125
|
+
"""Load the model and tokenizer asynchronously."""
|
|
126
|
+
if self.model is not None and self.tokenizer is not None:
|
|
127
|
+
return
|
|
128
|
+
|
|
129
|
+
self.logger.info(f"Loading model: {self.model_name}")
|
|
130
|
+
|
|
131
|
+
# Load tokenizer
|
|
132
|
+
self.tokenizer = AutoTokenizer.from_pretrained(
|
|
133
|
+
self.model_name,
|
|
134
|
+
use_fast=self.use_fast_tokenizer,
|
|
135
|
+
trust_remote_code=self.trust_remote_code,
|
|
136
|
+
padding_side='left' # Important for batch generation
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
# Set pad token if not available
|
|
140
|
+
if self.tokenizer.pad_token is None:
|
|
141
|
+
self.tokenizer.pad_token = self.tokenizer.eos_token
|
|
142
|
+
|
|
143
|
+
# Load model
|
|
144
|
+
self.model = AutoModelForCausalLM.from_pretrained(
|
|
145
|
+
self.model_name,
|
|
146
|
+
torch_dtype=self.torch_dtype,
|
|
147
|
+
device_map=self.device if self.device != "cpu" else None,
|
|
148
|
+
trust_remote_code=self.trust_remote_code,
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
if self.device == "cpu":
|
|
152
|
+
self.model = self.model.to(self.device)
|
|
153
|
+
|
|
154
|
+
# Update generation config with tokenizer info
|
|
155
|
+
self.generation_config.pad_token_id = self.tokenizer.pad_token_id
|
|
156
|
+
self.generation_config.eos_token_id = self.tokenizer.eos_token_id
|
|
157
|
+
|
|
158
|
+
self.logger.info(f"Model loaded successfully on {self.device}")
|
|
159
|
+
|
|
160
|
+
def _prepare_prompt(
|
|
161
|
+
self,
|
|
162
|
+
prompt: str,
|
|
163
|
+
system_prompt: Optional[str] = None,
|
|
164
|
+
conversation_history: Optional[List[Dict[str, str]]] = None
|
|
165
|
+
) -> str:
|
|
166
|
+
"""
|
|
167
|
+
Prepare the prompt based on the model type.
|
|
168
|
+
|
|
169
|
+
Args:
|
|
170
|
+
prompt: User prompt
|
|
171
|
+
system_prompt: System prompt
|
|
172
|
+
conversation_history: Previous conversation turns
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
Formatted prompt string
|
|
176
|
+
"""
|
|
177
|
+
# Handle different model formats
|
|
178
|
+
if "gemma" in self.model_name.lower():
|
|
179
|
+
return self._format_gemma_prompt(prompt, system_prompt, conversation_history)
|
|
180
|
+
elif "qwen" in self.model_name.lower():
|
|
181
|
+
return self._format_qwen_prompt(prompt, system_prompt, conversation_history)
|
|
182
|
+
elif "phi" in self.model_name.lower():
|
|
183
|
+
return self._format_phi_prompt(prompt, system_prompt, conversation_history)
|
|
184
|
+
elif "dialogpt" in self.model_name.lower():
|
|
185
|
+
return self._format_dialogpt_prompt(prompt, conversation_history)
|
|
186
|
+
else:
|
|
187
|
+
# Default simple format
|
|
188
|
+
return self._format_simple_prompt(prompt, system_prompt, conversation_history)
|
|
189
|
+
|
|
190
|
+
def _format_gemma_prompt(
|
|
191
|
+
self,
|
|
192
|
+
prompt: str,
|
|
193
|
+
system_prompt: Optional[str] = None,
|
|
194
|
+
conversation_history: Optional[List[Dict[str, str]]] = None
|
|
195
|
+
) -> str:
|
|
196
|
+
"""Format prompt for Gemma models."""
|
|
197
|
+
messages = []
|
|
198
|
+
|
|
199
|
+
if system_prompt:
|
|
200
|
+
messages.append({"role": "system", "content": system_prompt})
|
|
201
|
+
|
|
202
|
+
if conversation_history:
|
|
203
|
+
messages.extend(conversation_history)
|
|
204
|
+
|
|
205
|
+
messages.append({"role": "user", "content": prompt})
|
|
206
|
+
|
|
207
|
+
# Use tokenizer's chat template if available
|
|
208
|
+
if hasattr(self.tokenizer, 'apply_chat_template'):
|
|
209
|
+
return self.tokenizer.apply_chat_template(
|
|
210
|
+
messages,
|
|
211
|
+
tokenize=False,
|
|
212
|
+
add_generation_prompt=True
|
|
213
|
+
)
|
|
214
|
+
else:
|
|
215
|
+
# Fallback format
|
|
216
|
+
formatted = ""
|
|
217
|
+
for msg in messages:
|
|
218
|
+
formatted += f"<{msg['role']}>\n{msg['content']}\n</{msg['role']}>\n"
|
|
219
|
+
return formatted
|
|
220
|
+
|
|
221
|
+
def _format_qwen_prompt(
|
|
222
|
+
self,
|
|
223
|
+
prompt: str,
|
|
224
|
+
system_prompt: Optional[str] = None,
|
|
225
|
+
conversation_history: Optional[List[Dict[str, str]]] = None
|
|
226
|
+
) -> str:
|
|
227
|
+
"""Format prompt for Qwen models."""
|
|
228
|
+
messages = []
|
|
229
|
+
|
|
230
|
+
if system_prompt:
|
|
231
|
+
messages.append({"role": "system", "content": system_prompt})
|
|
232
|
+
else:
|
|
233
|
+
messages.append({
|
|
234
|
+
"role": "system",
|
|
235
|
+
"content": "You are Qwen, created by Alibaba Cloud. You are a helpful assistant."
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
if conversation_history:
|
|
239
|
+
messages.extend(conversation_history)
|
|
240
|
+
|
|
241
|
+
messages.append({"role": "user", "content": prompt})
|
|
242
|
+
|
|
243
|
+
if hasattr(self.tokenizer, 'apply_chat_template'):
|
|
244
|
+
return self.tokenizer.apply_chat_template(
|
|
245
|
+
messages,
|
|
246
|
+
tokenize=False,
|
|
247
|
+
add_generation_prompt=True
|
|
248
|
+
)
|
|
249
|
+
else:
|
|
250
|
+
# Fallback format
|
|
251
|
+
formatted = ""
|
|
252
|
+
for msg in messages:
|
|
253
|
+
formatted += f"<|im_start|>{msg['role']}\n{msg['content']}<|im_end|>\n"
|
|
254
|
+
formatted += "<|im_start|>assistant\n"
|
|
255
|
+
return formatted
|
|
256
|
+
|
|
257
|
+
def _format_phi_prompt(
|
|
258
|
+
self,
|
|
259
|
+
prompt: str,
|
|
260
|
+
system_prompt: Optional[str] = None,
|
|
261
|
+
conversation_history: Optional[List[Dict[str, str]]] = None
|
|
262
|
+
) -> str:
|
|
263
|
+
"""Format prompt for Phi models."""
|
|
264
|
+
messages = []
|
|
265
|
+
|
|
266
|
+
if system_prompt:
|
|
267
|
+
messages.append({"role": "system", "content": system_prompt})
|
|
268
|
+
|
|
269
|
+
if conversation_history:
|
|
270
|
+
messages.extend(conversation_history)
|
|
271
|
+
|
|
272
|
+
messages.append({"role": "user", "content": prompt})
|
|
273
|
+
|
|
274
|
+
if hasattr(self.tokenizer, 'apply_chat_template'):
|
|
275
|
+
return self.tokenizer.apply_chat_template(
|
|
276
|
+
messages,
|
|
277
|
+
tokenize=False,
|
|
278
|
+
add_generation_prompt=True
|
|
279
|
+
)
|
|
280
|
+
else:
|
|
281
|
+
# Phi-3 format
|
|
282
|
+
formatted = ""
|
|
283
|
+
for msg in messages:
|
|
284
|
+
formatted += f"<|{msg['role']}|>\n{msg['content']}<|end|>\n"
|
|
285
|
+
formatted += "<|assistant|>\n"
|
|
286
|
+
return formatted
|
|
287
|
+
|
|
288
|
+
def _format_dialogpt_prompt(
|
|
289
|
+
self,
|
|
290
|
+
prompt: str,
|
|
291
|
+
conversation_history: Optional[List[Dict[str, str]]] = None
|
|
292
|
+
) -> str:
|
|
293
|
+
"""Format prompt for DialoGPT models."""
|
|
294
|
+
# DialoGPT is conversational, so we concatenate with EOS tokens
|
|
295
|
+
conversation = ""
|
|
296
|
+
|
|
297
|
+
if conversation_history:
|
|
298
|
+
for turn in conversation_history:
|
|
299
|
+
if turn["role"] == "user":
|
|
300
|
+
conversation += turn["content"] + self.tokenizer.eos_token
|
|
301
|
+
elif turn["role"] == "assistant":
|
|
302
|
+
conversation += turn["content"] + self.tokenizer.eos_token
|
|
303
|
+
|
|
304
|
+
conversation += prompt + self.tokenizer.eos_token
|
|
305
|
+
return conversation
|
|
306
|
+
|
|
307
|
+
def _format_simple_prompt(
|
|
308
|
+
self,
|
|
309
|
+
prompt: str,
|
|
310
|
+
system_prompt: Optional[str] = None,
|
|
311
|
+
conversation_history: Optional[List[Dict[str, str]]] = None
|
|
312
|
+
) -> str:
|
|
313
|
+
"""Simple fallback prompt format."""
|
|
314
|
+
formatted = ""
|
|
315
|
+
|
|
316
|
+
if system_prompt:
|
|
317
|
+
formatted += f"System: {system_prompt}\n\n"
|
|
318
|
+
|
|
319
|
+
if conversation_history:
|
|
320
|
+
for turn in conversation_history:
|
|
321
|
+
formatted += f"{turn['role'].title()}: {turn['content']}\n"
|
|
322
|
+
|
|
323
|
+
formatted += f"User: {prompt}\nAssistant:"
|
|
324
|
+
return formatted
|
|
325
|
+
|
|
326
|
+
def _get_conversation_history(
|
|
327
|
+
self,
|
|
328
|
+
user_id: Optional[str],
|
|
329
|
+
session_id: Optional[str]
|
|
330
|
+
) -> List[Dict[str, str]]:
|
|
331
|
+
"""Get conversation history from memory."""
|
|
332
|
+
if not self.conversation_memory or not user_id or not session_id:
|
|
333
|
+
return []
|
|
334
|
+
|
|
335
|
+
try:
|
|
336
|
+
# This would be implemented based on your memory system
|
|
337
|
+
# For now, return empty list
|
|
338
|
+
return []
|
|
339
|
+
except Exception as e:
|
|
340
|
+
self.logger.warning(f"Could not retrieve conversation history: {e}")
|
|
341
|
+
return []
|
|
342
|
+
|
|
343
|
+
async def ask(
|
|
344
|
+
self,
|
|
345
|
+
prompt: str,
|
|
346
|
+
max_tokens: int = 512,
|
|
347
|
+
temperature: float = 0.7,
|
|
348
|
+
files: Optional[List[Union[str, Path]]] = None,
|
|
349
|
+
system_prompt: Optional[str] = None,
|
|
350
|
+
user_id: Optional[str] = None,
|
|
351
|
+
session_id: Optional[str] = None,
|
|
352
|
+
tools: Optional[List[Dict[str, Any]]] = None,
|
|
353
|
+
structured_output: Optional[Union[type, StructuredOutputConfig]] = None,
|
|
354
|
+
**kwargs
|
|
355
|
+
) -> AIMessage:
|
|
356
|
+
"""
|
|
357
|
+
Send a prompt to the transformer model and return the response.
|
|
358
|
+
|
|
359
|
+
Args:
|
|
360
|
+
prompt: The input prompt
|
|
361
|
+
model: Model name (ignored, uses initialized model)
|
|
362
|
+
max_tokens: Maximum tokens to generate
|
|
363
|
+
temperature: Sampling temperature
|
|
364
|
+
files: File attachments (not supported by transformers)
|
|
365
|
+
system_prompt: System prompt
|
|
366
|
+
user_id: User ID for conversation memory
|
|
367
|
+
session_id: Session ID for conversation memory
|
|
368
|
+
tools: Tool definitions (not supported)
|
|
369
|
+
structured_output: Structured output configuration
|
|
370
|
+
**kwargs: Additional generation parameters
|
|
371
|
+
|
|
372
|
+
Returns:
|
|
373
|
+
AIMessage response
|
|
374
|
+
"""
|
|
375
|
+
if not self.model or not self.tokenizer:
|
|
376
|
+
await self._load_model()
|
|
377
|
+
|
|
378
|
+
turn_id = str(uuid.uuid4())
|
|
379
|
+
original_prompt = prompt
|
|
380
|
+
|
|
381
|
+
messages, conversation_session, system_prompt = await self._prepare_conversation_context(
|
|
382
|
+
prompt, files, user_id, session_id, system_prompt
|
|
383
|
+
)
|
|
384
|
+
|
|
385
|
+
if files:
|
|
386
|
+
self.logger.warning(
|
|
387
|
+
"File attachments not supported by TransformersClient"
|
|
388
|
+
)
|
|
389
|
+
|
|
390
|
+
if tools:
|
|
391
|
+
self.logger.warning(
|
|
392
|
+
"Tool calling not supported by TransformersClient"
|
|
393
|
+
)
|
|
394
|
+
all_tool_calls = []
|
|
395
|
+
|
|
396
|
+
# Get conversation history
|
|
397
|
+
conversation_history = self._get_conversation_history(user_id, session_id)
|
|
398
|
+
|
|
399
|
+
# Prepare the prompt
|
|
400
|
+
formatted_prompt = self._prepare_prompt(prompt, system_prompt, conversation_history)
|
|
401
|
+
|
|
402
|
+
# Update generation config
|
|
403
|
+
gen_config = GenerationConfig(
|
|
404
|
+
max_new_tokens=max_tokens,
|
|
405
|
+
temperature=temperature,
|
|
406
|
+
top_p=kwargs.get('top_p', 0.9),
|
|
407
|
+
top_k=kwargs.get('top_k', 50),
|
|
408
|
+
do_sample=temperature > 0,
|
|
409
|
+
pad_token_id=self.tokenizer.pad_token_id,
|
|
410
|
+
eos_token_id=self.tokenizer.eos_token_id,
|
|
411
|
+
repetition_penalty=kwargs.get('repetition_penalty', 1.1),
|
|
412
|
+
)
|
|
413
|
+
|
|
414
|
+
# Tokenize input
|
|
415
|
+
inputs = self.tokenizer.encode(formatted_prompt, return_tensors="pt")
|
|
416
|
+
if self.device != "cpu":
|
|
417
|
+
inputs = inputs.to(self.device)
|
|
418
|
+
|
|
419
|
+
# Generate response
|
|
420
|
+
start_time = time.time()
|
|
421
|
+
|
|
422
|
+
with torch.no_grad():
|
|
423
|
+
outputs = self.model.generate(
|
|
424
|
+
inputs,
|
|
425
|
+
generation_config=gen_config,
|
|
426
|
+
**kwargs
|
|
427
|
+
)
|
|
428
|
+
|
|
429
|
+
generation_time = time.time() - start_time
|
|
430
|
+
|
|
431
|
+
# Decode response
|
|
432
|
+
input_length = inputs.shape[1]
|
|
433
|
+
generated_ids = outputs[0][input_length:]
|
|
434
|
+
response_text = self.tokenizer.decode(generated_ids, skip_special_tokens=True)
|
|
435
|
+
|
|
436
|
+
# Clean up response
|
|
437
|
+
response_text = response_text.strip()
|
|
438
|
+
|
|
439
|
+
# Create usage statistics
|
|
440
|
+
usage = CompletionUsage(
|
|
441
|
+
prompt_tokens=input_length,
|
|
442
|
+
completion_tokens=len(generated_ids),
|
|
443
|
+
total_tokens=input_length + len(generated_ids)
|
|
444
|
+
)
|
|
445
|
+
|
|
446
|
+
# Create AIMessage response
|
|
447
|
+
ai_message = AIMessageFactory.create_message(
|
|
448
|
+
response=response_text,
|
|
449
|
+
input_text=original_prompt,
|
|
450
|
+
user_id=user_id,
|
|
451
|
+
session_id=session_id,
|
|
452
|
+
turn_id=turn_id,
|
|
453
|
+
model=self.model_name,
|
|
454
|
+
text_response=response_text,
|
|
455
|
+
usage=usage,
|
|
456
|
+
response_time=generation_time,
|
|
457
|
+
)
|
|
458
|
+
|
|
459
|
+
# Store conversation turn if memory is available
|
|
460
|
+
# Update conversation memory
|
|
461
|
+
tools_used = [tc.name for tc in all_tool_calls]
|
|
462
|
+
await self._update_conversation_memory(
|
|
463
|
+
user_id,
|
|
464
|
+
session_id,
|
|
465
|
+
conversation_session,
|
|
466
|
+
messages,
|
|
467
|
+
system_prompt,
|
|
468
|
+
turn_id,
|
|
469
|
+
original_prompt,
|
|
470
|
+
response_text,
|
|
471
|
+
tools_used
|
|
472
|
+
)
|
|
473
|
+
|
|
474
|
+
# Handle structured output if requested
|
|
475
|
+
if structured_output:
|
|
476
|
+
try:
|
|
477
|
+
structured_result = await self._handle_structured_output(
|
|
478
|
+
{"content": [{"type": "text", "text": response_text}]},
|
|
479
|
+
structured_output
|
|
480
|
+
)
|
|
481
|
+
ai_message.structured_output = structured_result
|
|
482
|
+
except Exception as e:
|
|
483
|
+
self.logger.warning(f"Failed to parse structured output: {e}")
|
|
484
|
+
|
|
485
|
+
return ai_message
|
|
486
|
+
|
|
487
|
+
async def ask_stream(
|
|
488
|
+
self,
|
|
489
|
+
prompt: str,
|
|
490
|
+
model: Optional[str] = None,
|
|
491
|
+
max_tokens: int = 512,
|
|
492
|
+
temperature: float = 0.7,
|
|
493
|
+
files: Optional[List[Union[str, Path]]] = None,
|
|
494
|
+
system_prompt: Optional[str] = None,
|
|
495
|
+
user_id: Optional[str] = None,
|
|
496
|
+
session_id: Optional[str] = None,
|
|
497
|
+
tools: Optional[List[Dict[str, Any]]] = None,
|
|
498
|
+
**kwargs
|
|
499
|
+
) -> AsyncIterator[str]:
|
|
500
|
+
"""
|
|
501
|
+
Stream the model's response.
|
|
502
|
+
|
|
503
|
+
Note: True streaming is not easily available with transformers,
|
|
504
|
+
so this implementation yields the complete response.
|
|
505
|
+
"""
|
|
506
|
+
response = await self.ask(
|
|
507
|
+
prompt=prompt,
|
|
508
|
+
model=model,
|
|
509
|
+
max_tokens=max_tokens,
|
|
510
|
+
temperature=temperature,
|
|
511
|
+
files=files,
|
|
512
|
+
system_prompt=system_prompt,
|
|
513
|
+
user_id=user_id,
|
|
514
|
+
session_id=session_id,
|
|
515
|
+
tools=tools,
|
|
516
|
+
**kwargs
|
|
517
|
+
)
|
|
518
|
+
|
|
519
|
+
# Simulate streaming by yielding chunks
|
|
520
|
+
text = response.content
|
|
521
|
+
chunk_size = 10 # Characters per chunk
|
|
522
|
+
|
|
523
|
+
for i in range(0, len(text), chunk_size):
|
|
524
|
+
chunk = text[i:i + chunk_size]
|
|
525
|
+
yield chunk
|
|
526
|
+
await asyncio.sleep(0.01) # Small delay to simulate streaming
|
|
527
|
+
|
|
528
|
+
async def batch_ask(self, requests: List[Dict[str, Any]]) -> List[AIMessage]:
|
|
529
|
+
"""
|
|
530
|
+
Process multiple requests in batch.
|
|
531
|
+
|
|
532
|
+
Note: This processes requests sequentially to avoid memory issues
|
|
533
|
+
with multiple models loaded simultaneously.
|
|
534
|
+
"""
|
|
535
|
+
results = []
|
|
536
|
+
for request in requests:
|
|
537
|
+
try:
|
|
538
|
+
result = await self.ask(**request)
|
|
539
|
+
results.append(result)
|
|
540
|
+
except Exception as e:
|
|
541
|
+
self.logger.error(f"Error in batch request: {e}")
|
|
542
|
+
# Create error response
|
|
543
|
+
error_message = AIMessageFactory.create_message(
|
|
544
|
+
response=result,
|
|
545
|
+
input_text=request.get('prompt', ''),
|
|
546
|
+
user_id=request.get('user_id'),
|
|
547
|
+
session_id=request.get('session_id'),
|
|
548
|
+
turn_id=str(uuid.uuid4()),
|
|
549
|
+
model=self.model_name,
|
|
550
|
+
usage=CompletionUsage(prompt_tokens=0, completion_tokens=0, total_tokens=0)
|
|
551
|
+
)
|
|
552
|
+
results.append(error_message)
|
|
553
|
+
|
|
554
|
+
return results
|
|
555
|
+
|
|
556
|
+
def get_model_info(self) -> Dict[str, Any]:
|
|
557
|
+
"""Get information about the loaded model."""
|
|
558
|
+
if not self.model:
|
|
559
|
+
return {"status": "not_loaded"}
|
|
560
|
+
|
|
561
|
+
return {
|
|
562
|
+
"model_name": self.model_name,
|
|
563
|
+
"device": self.device,
|
|
564
|
+
"torch_dtype": str(self.torch_dtype),
|
|
565
|
+
"status": "loaded",
|
|
566
|
+
"vocab_size": self.tokenizer.vocab_size if self.tokenizer else None,
|
|
567
|
+
"max_position_embeddings": getattr(self.model.config, 'max_position_embeddings', None),
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
async def clear_model(self):
|
|
571
|
+
"""Clear the model from memory."""
|
|
572
|
+
if self.model:
|
|
573
|
+
del self.model
|
|
574
|
+
self.model = None
|
|
575
|
+
if self.tokenizer:
|
|
576
|
+
del self.tokenizer
|
|
577
|
+
self.tokenizer = None
|
|
578
|
+
if torch.cuda.is_available():
|
|
579
|
+
torch.cuda.empty_cache()
|
|
580
|
+
self.logger.info(
|
|
581
|
+
"Model cleared from memory"
|
|
582
|
+
)
|
parrot/clients/models.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import Any, Dict, Optional, Type
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from .base import AbstractClient
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class LLMConfig:
|
|
9
|
+
"""Resolved LLM configuration."""
|
|
10
|
+
provider: Optional[str] = None
|
|
11
|
+
model: Optional[str] = None
|
|
12
|
+
temperature: float = 0.1
|
|
13
|
+
top_k: int = 41
|
|
14
|
+
top_p: float = 0.9
|
|
15
|
+
max_tokens: Optional[int] = None
|
|
16
|
+
client_class: Optional[Type[AbstractClient]] = None
|
|
17
|
+
client_instance: Optional[AbstractClient] = None
|
|
18
|
+
extra: Dict[str, Any] = field(default_factory=dict)
|