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.
Files changed (535) hide show
  1. agentui/.prettierrc +15 -0
  2. agentui/QUICKSTART.md +272 -0
  3. agentui/README.md +59 -0
  4. agentui/env.example +16 -0
  5. agentui/jsconfig.json +14 -0
  6. agentui/package-lock.json +4242 -0
  7. agentui/package.json +34 -0
  8. agentui/scripts/postinstall/apply-patches.mjs +260 -0
  9. agentui/src/app.css +61 -0
  10. agentui/src/app.d.ts +13 -0
  11. agentui/src/app.html +12 -0
  12. agentui/src/components/LoadingSpinner.svelte +64 -0
  13. agentui/src/components/ThemeSwitcher.svelte +159 -0
  14. agentui/src/components/index.js +4 -0
  15. agentui/src/lib/api/bots.ts +60 -0
  16. agentui/src/lib/api/chat.ts +22 -0
  17. agentui/src/lib/api/http.ts +25 -0
  18. agentui/src/lib/components/BotCard.svelte +33 -0
  19. agentui/src/lib/components/ChatBubble.svelte +63 -0
  20. agentui/src/lib/components/Toast.svelte +21 -0
  21. agentui/src/lib/config.ts +20 -0
  22. agentui/src/lib/stores/auth.svelte.ts +73 -0
  23. agentui/src/lib/stores/theme.svelte.js +64 -0
  24. agentui/src/lib/stores/toast.svelte.ts +31 -0
  25. agentui/src/lib/utils/conversation.ts +39 -0
  26. agentui/src/routes/+layout.svelte +20 -0
  27. agentui/src/routes/+page.svelte +232 -0
  28. agentui/src/routes/login/+page.svelte +200 -0
  29. agentui/src/routes/talk/[agentId]/+page.svelte +297 -0
  30. agentui/src/routes/talk/[agentId]/+page.ts +7 -0
  31. agentui/static/README.md +1 -0
  32. agentui/svelte.config.js +11 -0
  33. agentui/tailwind.config.ts +53 -0
  34. agentui/tsconfig.json +3 -0
  35. agentui/vite.config.ts +10 -0
  36. ai_parrot-0.17.2.dist-info/METADATA +472 -0
  37. ai_parrot-0.17.2.dist-info/RECORD +535 -0
  38. ai_parrot-0.17.2.dist-info/WHEEL +6 -0
  39. ai_parrot-0.17.2.dist-info/entry_points.txt +2 -0
  40. ai_parrot-0.17.2.dist-info/licenses/LICENSE +21 -0
  41. ai_parrot-0.17.2.dist-info/top_level.txt +6 -0
  42. crew-builder/.prettierrc +15 -0
  43. crew-builder/QUICKSTART.md +259 -0
  44. crew-builder/README.md +113 -0
  45. crew-builder/env.example +17 -0
  46. crew-builder/jsconfig.json +14 -0
  47. crew-builder/package-lock.json +4182 -0
  48. crew-builder/package.json +37 -0
  49. crew-builder/scripts/postinstall/apply-patches.mjs +260 -0
  50. crew-builder/src/app.css +62 -0
  51. crew-builder/src/app.d.ts +13 -0
  52. crew-builder/src/app.html +12 -0
  53. crew-builder/src/components/LoadingSpinner.svelte +64 -0
  54. crew-builder/src/components/ThemeSwitcher.svelte +149 -0
  55. crew-builder/src/components/index.js +9 -0
  56. crew-builder/src/lib/api/bots.ts +60 -0
  57. crew-builder/src/lib/api/chat.ts +80 -0
  58. crew-builder/src/lib/api/client.ts +56 -0
  59. crew-builder/src/lib/api/crew/crew.ts +136 -0
  60. crew-builder/src/lib/api/index.ts +5 -0
  61. crew-builder/src/lib/api/o365/auth.ts +65 -0
  62. crew-builder/src/lib/auth/auth.ts +54 -0
  63. crew-builder/src/lib/components/AgentNode.svelte +43 -0
  64. crew-builder/src/lib/components/BotCard.svelte +33 -0
  65. crew-builder/src/lib/components/ChatBubble.svelte +67 -0
  66. crew-builder/src/lib/components/ConfigPanel.svelte +278 -0
  67. crew-builder/src/lib/components/JsonTreeNode.svelte +76 -0
  68. crew-builder/src/lib/components/JsonViewer.svelte +24 -0
  69. crew-builder/src/lib/components/MarkdownEditor.svelte +48 -0
  70. crew-builder/src/lib/components/ThemeToggle.svelte +36 -0
  71. crew-builder/src/lib/components/Toast.svelte +67 -0
  72. crew-builder/src/lib/components/Toolbar.svelte +157 -0
  73. crew-builder/src/lib/components/index.ts +10 -0
  74. crew-builder/src/lib/config.ts +8 -0
  75. crew-builder/src/lib/stores/auth.svelte.ts +228 -0
  76. crew-builder/src/lib/stores/crewStore.ts +369 -0
  77. crew-builder/src/lib/stores/theme.svelte.js +145 -0
  78. crew-builder/src/lib/stores/toast.svelte.ts +69 -0
  79. crew-builder/src/lib/utils/conversation.ts +39 -0
  80. crew-builder/src/lib/utils/markdown.ts +122 -0
  81. crew-builder/src/lib/utils/talkHistory.ts +47 -0
  82. crew-builder/src/routes/+layout.svelte +20 -0
  83. crew-builder/src/routes/+page.svelte +539 -0
  84. crew-builder/src/routes/agents/+page.svelte +247 -0
  85. crew-builder/src/routes/agents/[agentId]/+page.svelte +288 -0
  86. crew-builder/src/routes/agents/[agentId]/+page.ts +7 -0
  87. crew-builder/src/routes/builder/+page.svelte +204 -0
  88. crew-builder/src/routes/crew/ask/+page.svelte +1052 -0
  89. crew-builder/src/routes/crew/ask/+page.ts +1 -0
  90. crew-builder/src/routes/integrations/o365/+page.svelte +304 -0
  91. crew-builder/src/routes/login/+page.svelte +197 -0
  92. crew-builder/src/routes/talk/[agentId]/+page.svelte +487 -0
  93. crew-builder/src/routes/talk/[agentId]/+page.ts +7 -0
  94. crew-builder/static/README.md +1 -0
  95. crew-builder/svelte.config.js +11 -0
  96. crew-builder/tailwind.config.ts +53 -0
  97. crew-builder/tsconfig.json +3 -0
  98. crew-builder/vite.config.ts +10 -0
  99. mcp_servers/calculator_server.py +309 -0
  100. parrot/__init__.py +27 -0
  101. parrot/__pycache__/__init__.cpython-310.pyc +0 -0
  102. parrot/__pycache__/version.cpython-310.pyc +0 -0
  103. parrot/_version.py +34 -0
  104. parrot/a2a/__init__.py +48 -0
  105. parrot/a2a/client.py +658 -0
  106. parrot/a2a/discovery.py +89 -0
  107. parrot/a2a/mixin.py +257 -0
  108. parrot/a2a/models.py +376 -0
  109. parrot/a2a/server.py +770 -0
  110. parrot/agents/__init__.py +29 -0
  111. parrot/bots/__init__.py +12 -0
  112. parrot/bots/a2a_agent.py +19 -0
  113. parrot/bots/abstract.py +3139 -0
  114. parrot/bots/agent.py +1129 -0
  115. parrot/bots/basic.py +9 -0
  116. parrot/bots/chatbot.py +669 -0
  117. parrot/bots/data.py +1618 -0
  118. parrot/bots/database/__init__.py +5 -0
  119. parrot/bots/database/abstract.py +3071 -0
  120. parrot/bots/database/cache.py +286 -0
  121. parrot/bots/database/models.py +468 -0
  122. parrot/bots/database/prompts.py +154 -0
  123. parrot/bots/database/retries.py +98 -0
  124. parrot/bots/database/router.py +269 -0
  125. parrot/bots/database/sql.py +41 -0
  126. parrot/bots/db/__init__.py +6 -0
  127. parrot/bots/db/abstract.py +556 -0
  128. parrot/bots/db/bigquery.py +602 -0
  129. parrot/bots/db/cache.py +85 -0
  130. parrot/bots/db/documentdb.py +668 -0
  131. parrot/bots/db/elastic.py +1014 -0
  132. parrot/bots/db/influx.py +898 -0
  133. parrot/bots/db/mock.py +96 -0
  134. parrot/bots/db/multi.py +783 -0
  135. parrot/bots/db/prompts.py +185 -0
  136. parrot/bots/db/sql.py +1255 -0
  137. parrot/bots/db/tools.py +212 -0
  138. parrot/bots/document.py +680 -0
  139. parrot/bots/hrbot.py +15 -0
  140. parrot/bots/kb.py +170 -0
  141. parrot/bots/mcp.py +36 -0
  142. parrot/bots/orchestration/README.md +463 -0
  143. parrot/bots/orchestration/__init__.py +1 -0
  144. parrot/bots/orchestration/agent.py +155 -0
  145. parrot/bots/orchestration/crew.py +3330 -0
  146. parrot/bots/orchestration/fsm.py +1179 -0
  147. parrot/bots/orchestration/hr.py +434 -0
  148. parrot/bots/orchestration/storage/__init__.py +4 -0
  149. parrot/bots/orchestration/storage/memory.py +100 -0
  150. parrot/bots/orchestration/storage/mixin.py +119 -0
  151. parrot/bots/orchestration/verify.py +202 -0
  152. parrot/bots/product.py +204 -0
  153. parrot/bots/prompts/__init__.py +96 -0
  154. parrot/bots/prompts/agents.py +155 -0
  155. parrot/bots/prompts/data.py +216 -0
  156. parrot/bots/prompts/output_generation.py +8 -0
  157. parrot/bots/scraper/__init__.py +3 -0
  158. parrot/bots/scraper/models.py +122 -0
  159. parrot/bots/scraper/scraper.py +1173 -0
  160. parrot/bots/scraper/templates.py +115 -0
  161. parrot/bots/stores/__init__.py +5 -0
  162. parrot/bots/stores/local.py +172 -0
  163. parrot/bots/webdev.py +81 -0
  164. parrot/cli.py +17 -0
  165. parrot/clients/__init__.py +16 -0
  166. parrot/clients/base.py +1491 -0
  167. parrot/clients/claude.py +1191 -0
  168. parrot/clients/factory.py +129 -0
  169. parrot/clients/google.py +4567 -0
  170. parrot/clients/gpt.py +1975 -0
  171. parrot/clients/grok.py +432 -0
  172. parrot/clients/groq.py +986 -0
  173. parrot/clients/hf.py +582 -0
  174. parrot/clients/models.py +18 -0
  175. parrot/conf.py +395 -0
  176. parrot/embeddings/__init__.py +9 -0
  177. parrot/embeddings/base.py +157 -0
  178. parrot/embeddings/google.py +98 -0
  179. parrot/embeddings/huggingface.py +74 -0
  180. parrot/embeddings/openai.py +84 -0
  181. parrot/embeddings/processor.py +88 -0
  182. parrot/exceptions.c +13868 -0
  183. parrot/exceptions.cpython-310-x86_64-linux-gnu.so +0 -0
  184. parrot/exceptions.pxd +22 -0
  185. parrot/exceptions.pxi +15 -0
  186. parrot/exceptions.pyx +44 -0
  187. parrot/generators/__init__.py +29 -0
  188. parrot/generators/base.py +200 -0
  189. parrot/generators/html.py +293 -0
  190. parrot/generators/react.py +205 -0
  191. parrot/generators/streamlit.py +203 -0
  192. parrot/generators/template.py +105 -0
  193. parrot/handlers/__init__.py +4 -0
  194. parrot/handlers/agent.py +861 -0
  195. parrot/handlers/agents/__init__.py +1 -0
  196. parrot/handlers/agents/abstract.py +900 -0
  197. parrot/handlers/bots.py +338 -0
  198. parrot/handlers/chat.py +915 -0
  199. parrot/handlers/creation.sql +192 -0
  200. parrot/handlers/crew/ARCHITECTURE.md +362 -0
  201. parrot/handlers/crew/README_BOTMANAGER_PERSISTENCE.md +303 -0
  202. parrot/handlers/crew/README_REDIS_PERSISTENCE.md +366 -0
  203. parrot/handlers/crew/__init__.py +0 -0
  204. parrot/handlers/crew/handler.py +801 -0
  205. parrot/handlers/crew/models.py +229 -0
  206. parrot/handlers/crew/redis_persistence.py +523 -0
  207. parrot/handlers/jobs/__init__.py +10 -0
  208. parrot/handlers/jobs/job.py +384 -0
  209. parrot/handlers/jobs/mixin.py +627 -0
  210. parrot/handlers/jobs/models.py +115 -0
  211. parrot/handlers/jobs/worker.py +31 -0
  212. parrot/handlers/models.py +596 -0
  213. parrot/handlers/o365_auth.py +105 -0
  214. parrot/handlers/stream.py +337 -0
  215. parrot/interfaces/__init__.py +6 -0
  216. parrot/interfaces/aws.py +143 -0
  217. parrot/interfaces/credentials.py +113 -0
  218. parrot/interfaces/database.py +27 -0
  219. parrot/interfaces/google.py +1123 -0
  220. parrot/interfaces/hierarchy.py +1227 -0
  221. parrot/interfaces/http.py +651 -0
  222. parrot/interfaces/images/__init__.py +0 -0
  223. parrot/interfaces/images/plugins/__init__.py +24 -0
  224. parrot/interfaces/images/plugins/abstract.py +58 -0
  225. parrot/interfaces/images/plugins/analisys.py +148 -0
  226. parrot/interfaces/images/plugins/classify.py +150 -0
  227. parrot/interfaces/images/plugins/classifybase.py +182 -0
  228. parrot/interfaces/images/plugins/detect.py +150 -0
  229. parrot/interfaces/images/plugins/exif.py +1103 -0
  230. parrot/interfaces/images/plugins/hash.py +52 -0
  231. parrot/interfaces/images/plugins/vision.py +104 -0
  232. parrot/interfaces/images/plugins/yolo.py +66 -0
  233. parrot/interfaces/images/plugins/zerodetect.py +197 -0
  234. parrot/interfaces/o365.py +978 -0
  235. parrot/interfaces/onedrive.py +822 -0
  236. parrot/interfaces/sharepoint.py +1435 -0
  237. parrot/interfaces/soap.py +257 -0
  238. parrot/loaders/__init__.py +8 -0
  239. parrot/loaders/abstract.py +1131 -0
  240. parrot/loaders/audio.py +199 -0
  241. parrot/loaders/basepdf.py +53 -0
  242. parrot/loaders/basevideo.py +1568 -0
  243. parrot/loaders/csv.py +409 -0
  244. parrot/loaders/docx.py +116 -0
  245. parrot/loaders/epubloader.py +316 -0
  246. parrot/loaders/excel.py +199 -0
  247. parrot/loaders/factory.py +55 -0
  248. parrot/loaders/files/__init__.py +0 -0
  249. parrot/loaders/files/abstract.py +39 -0
  250. parrot/loaders/files/html.py +26 -0
  251. parrot/loaders/files/text.py +63 -0
  252. parrot/loaders/html.py +152 -0
  253. parrot/loaders/markdown.py +442 -0
  254. parrot/loaders/pdf.py +373 -0
  255. parrot/loaders/pdfmark.py +320 -0
  256. parrot/loaders/pdftables.py +506 -0
  257. parrot/loaders/ppt.py +476 -0
  258. parrot/loaders/qa.py +63 -0
  259. parrot/loaders/splitters/__init__.py +10 -0
  260. parrot/loaders/splitters/base.py +138 -0
  261. parrot/loaders/splitters/md.py +228 -0
  262. parrot/loaders/splitters/token.py +143 -0
  263. parrot/loaders/txt.py +26 -0
  264. parrot/loaders/video.py +89 -0
  265. parrot/loaders/videolocal.py +218 -0
  266. parrot/loaders/videounderstanding.py +377 -0
  267. parrot/loaders/vimeo.py +167 -0
  268. parrot/loaders/web.py +599 -0
  269. parrot/loaders/youtube.py +504 -0
  270. parrot/manager/__init__.py +5 -0
  271. parrot/manager/manager.py +1030 -0
  272. parrot/mcp/__init__.py +28 -0
  273. parrot/mcp/adapter.py +105 -0
  274. parrot/mcp/cli.py +174 -0
  275. parrot/mcp/client.py +119 -0
  276. parrot/mcp/config.py +75 -0
  277. parrot/mcp/integration.py +842 -0
  278. parrot/mcp/oauth.py +933 -0
  279. parrot/mcp/server.py +225 -0
  280. parrot/mcp/transports/__init__.py +3 -0
  281. parrot/mcp/transports/base.py +279 -0
  282. parrot/mcp/transports/grpc_session.py +163 -0
  283. parrot/mcp/transports/http.py +312 -0
  284. parrot/mcp/transports/mcp.proto +108 -0
  285. parrot/mcp/transports/quic.py +1082 -0
  286. parrot/mcp/transports/sse.py +330 -0
  287. parrot/mcp/transports/stdio.py +309 -0
  288. parrot/mcp/transports/unix.py +395 -0
  289. parrot/mcp/transports/websocket.py +547 -0
  290. parrot/memory/__init__.py +16 -0
  291. parrot/memory/abstract.py +209 -0
  292. parrot/memory/agent.py +32 -0
  293. parrot/memory/cache.py +175 -0
  294. parrot/memory/core.py +555 -0
  295. parrot/memory/file.py +153 -0
  296. parrot/memory/mem.py +131 -0
  297. parrot/memory/redis.py +613 -0
  298. parrot/models/__init__.py +46 -0
  299. parrot/models/basic.py +118 -0
  300. parrot/models/compliance.py +208 -0
  301. parrot/models/crew.py +395 -0
  302. parrot/models/detections.py +654 -0
  303. parrot/models/generation.py +85 -0
  304. parrot/models/google.py +223 -0
  305. parrot/models/groq.py +23 -0
  306. parrot/models/openai.py +30 -0
  307. parrot/models/outputs.py +285 -0
  308. parrot/models/responses.py +938 -0
  309. parrot/notifications/__init__.py +743 -0
  310. parrot/openapi/__init__.py +3 -0
  311. parrot/openapi/components.yaml +641 -0
  312. parrot/openapi/config.py +322 -0
  313. parrot/outputs/__init__.py +32 -0
  314. parrot/outputs/formats/__init__.py +108 -0
  315. parrot/outputs/formats/altair.py +359 -0
  316. parrot/outputs/formats/application.py +122 -0
  317. parrot/outputs/formats/base.py +351 -0
  318. parrot/outputs/formats/bokeh.py +356 -0
  319. parrot/outputs/formats/card.py +424 -0
  320. parrot/outputs/formats/chart.py +436 -0
  321. parrot/outputs/formats/d3.py +255 -0
  322. parrot/outputs/formats/echarts.py +310 -0
  323. parrot/outputs/formats/generators/__init__.py +0 -0
  324. parrot/outputs/formats/generators/abstract.py +61 -0
  325. parrot/outputs/formats/generators/panel.py +145 -0
  326. parrot/outputs/formats/generators/streamlit.py +86 -0
  327. parrot/outputs/formats/generators/terminal.py +63 -0
  328. parrot/outputs/formats/holoviews.py +310 -0
  329. parrot/outputs/formats/html.py +147 -0
  330. parrot/outputs/formats/jinja2.py +46 -0
  331. parrot/outputs/formats/json.py +87 -0
  332. parrot/outputs/formats/map.py +933 -0
  333. parrot/outputs/formats/markdown.py +172 -0
  334. parrot/outputs/formats/matplotlib.py +237 -0
  335. parrot/outputs/formats/mixins/__init__.py +0 -0
  336. parrot/outputs/formats/mixins/emaps.py +855 -0
  337. parrot/outputs/formats/plotly.py +341 -0
  338. parrot/outputs/formats/seaborn.py +310 -0
  339. parrot/outputs/formats/table.py +397 -0
  340. parrot/outputs/formats/template_report.py +138 -0
  341. parrot/outputs/formats/yaml.py +125 -0
  342. parrot/outputs/formatter.py +152 -0
  343. parrot/outputs/templates/__init__.py +95 -0
  344. parrot/pipelines/__init__.py +0 -0
  345. parrot/pipelines/abstract.py +210 -0
  346. parrot/pipelines/detector.py +124 -0
  347. parrot/pipelines/models.py +90 -0
  348. parrot/pipelines/planogram.py +3002 -0
  349. parrot/pipelines/table.sql +97 -0
  350. parrot/plugins/__init__.py +106 -0
  351. parrot/plugins/importer.py +80 -0
  352. parrot/py.typed +0 -0
  353. parrot/registry/__init__.py +18 -0
  354. parrot/registry/registry.py +594 -0
  355. parrot/scheduler/__init__.py +1189 -0
  356. parrot/scheduler/models.py +60 -0
  357. parrot/security/__init__.py +16 -0
  358. parrot/security/prompt_injection.py +268 -0
  359. parrot/security/security_events.sql +25 -0
  360. parrot/services/__init__.py +1 -0
  361. parrot/services/mcp/__init__.py +8 -0
  362. parrot/services/mcp/config.py +13 -0
  363. parrot/services/mcp/server.py +295 -0
  364. parrot/services/o365_remote_auth.py +235 -0
  365. parrot/stores/__init__.py +7 -0
  366. parrot/stores/abstract.py +352 -0
  367. parrot/stores/arango.py +1090 -0
  368. parrot/stores/bigquery.py +1377 -0
  369. parrot/stores/cache.py +106 -0
  370. parrot/stores/empty.py +10 -0
  371. parrot/stores/faiss_store.py +1157 -0
  372. parrot/stores/kb/__init__.py +9 -0
  373. parrot/stores/kb/abstract.py +68 -0
  374. parrot/stores/kb/cache.py +165 -0
  375. parrot/stores/kb/doc.py +325 -0
  376. parrot/stores/kb/hierarchy.py +346 -0
  377. parrot/stores/kb/local.py +457 -0
  378. parrot/stores/kb/prompt.py +28 -0
  379. parrot/stores/kb/redis.py +659 -0
  380. parrot/stores/kb/store.py +115 -0
  381. parrot/stores/kb/user.py +374 -0
  382. parrot/stores/models.py +59 -0
  383. parrot/stores/pgvector.py +3 -0
  384. parrot/stores/postgres.py +2853 -0
  385. parrot/stores/utils/__init__.py +0 -0
  386. parrot/stores/utils/chunking.py +197 -0
  387. parrot/telemetry/__init__.py +3 -0
  388. parrot/telemetry/mixin.py +111 -0
  389. parrot/template/__init__.py +3 -0
  390. parrot/template/engine.py +259 -0
  391. parrot/tools/__init__.py +23 -0
  392. parrot/tools/abstract.py +644 -0
  393. parrot/tools/agent.py +363 -0
  394. parrot/tools/arangodbsearch.py +537 -0
  395. parrot/tools/arxiv_tool.py +188 -0
  396. parrot/tools/calculator/__init__.py +3 -0
  397. parrot/tools/calculator/operations/__init__.py +38 -0
  398. parrot/tools/calculator/operations/calculus.py +80 -0
  399. parrot/tools/calculator/operations/statistics.py +76 -0
  400. parrot/tools/calculator/tool.py +150 -0
  401. parrot/tools/cloudwatch.py +988 -0
  402. parrot/tools/codeinterpreter/__init__.py +127 -0
  403. parrot/tools/codeinterpreter/executor.py +371 -0
  404. parrot/tools/codeinterpreter/internals.py +473 -0
  405. parrot/tools/codeinterpreter/models.py +643 -0
  406. parrot/tools/codeinterpreter/prompts.py +224 -0
  407. parrot/tools/codeinterpreter/tool.py +664 -0
  408. parrot/tools/company_info/__init__.py +6 -0
  409. parrot/tools/company_info/tool.py +1138 -0
  410. parrot/tools/correlationanalysis.py +437 -0
  411. parrot/tools/database/abstract.py +286 -0
  412. parrot/tools/database/bq.py +115 -0
  413. parrot/tools/database/cache.py +284 -0
  414. parrot/tools/database/models.py +95 -0
  415. parrot/tools/database/pg.py +343 -0
  416. parrot/tools/databasequery.py +1159 -0
  417. parrot/tools/db.py +1800 -0
  418. parrot/tools/ddgo.py +370 -0
  419. parrot/tools/decorators.py +271 -0
  420. parrot/tools/dftohtml.py +282 -0
  421. parrot/tools/document.py +549 -0
  422. parrot/tools/ecs.py +819 -0
  423. parrot/tools/edareport.py +368 -0
  424. parrot/tools/elasticsearch.py +1049 -0
  425. parrot/tools/employees.py +462 -0
  426. parrot/tools/epson/__init__.py +96 -0
  427. parrot/tools/excel.py +683 -0
  428. parrot/tools/file/__init__.py +13 -0
  429. parrot/tools/file/abstract.py +76 -0
  430. parrot/tools/file/gcs.py +378 -0
  431. parrot/tools/file/local.py +284 -0
  432. parrot/tools/file/s3.py +511 -0
  433. parrot/tools/file/tmp.py +309 -0
  434. parrot/tools/file/tool.py +501 -0
  435. parrot/tools/file_reader.py +129 -0
  436. parrot/tools/flowtask/__init__.py +19 -0
  437. parrot/tools/flowtask/tool.py +761 -0
  438. parrot/tools/gittoolkit.py +508 -0
  439. parrot/tools/google/__init__.py +18 -0
  440. parrot/tools/google/base.py +169 -0
  441. parrot/tools/google/tools.py +1251 -0
  442. parrot/tools/googlelocation.py +5 -0
  443. parrot/tools/googleroutes.py +5 -0
  444. parrot/tools/googlesearch.py +5 -0
  445. parrot/tools/googlesitesearch.py +5 -0
  446. parrot/tools/googlevoice.py +2 -0
  447. parrot/tools/gvoice.py +695 -0
  448. parrot/tools/ibisworld/README.md +225 -0
  449. parrot/tools/ibisworld/__init__.py +11 -0
  450. parrot/tools/ibisworld/tool.py +366 -0
  451. parrot/tools/jiratoolkit.py +1718 -0
  452. parrot/tools/manager.py +1098 -0
  453. parrot/tools/math.py +152 -0
  454. parrot/tools/metadata.py +476 -0
  455. parrot/tools/msteams.py +1621 -0
  456. parrot/tools/msword.py +635 -0
  457. parrot/tools/multidb.py +580 -0
  458. parrot/tools/multistoresearch.py +369 -0
  459. parrot/tools/networkninja.py +167 -0
  460. parrot/tools/nextstop/__init__.py +4 -0
  461. parrot/tools/nextstop/base.py +286 -0
  462. parrot/tools/nextstop/employee.py +733 -0
  463. parrot/tools/nextstop/store.py +462 -0
  464. parrot/tools/notification.py +435 -0
  465. parrot/tools/o365/__init__.py +42 -0
  466. parrot/tools/o365/base.py +295 -0
  467. parrot/tools/o365/bundle.py +522 -0
  468. parrot/tools/o365/events.py +554 -0
  469. parrot/tools/o365/mail.py +992 -0
  470. parrot/tools/o365/onedrive.py +497 -0
  471. parrot/tools/o365/sharepoint.py +641 -0
  472. parrot/tools/openapi_toolkit.py +904 -0
  473. parrot/tools/openweather.py +527 -0
  474. parrot/tools/pdfprint.py +1001 -0
  475. parrot/tools/powerbi.py +518 -0
  476. parrot/tools/powerpoint.py +1113 -0
  477. parrot/tools/pricestool.py +146 -0
  478. parrot/tools/products/__init__.py +246 -0
  479. parrot/tools/prophet_tool.py +171 -0
  480. parrot/tools/pythonpandas.py +630 -0
  481. parrot/tools/pythonrepl.py +910 -0
  482. parrot/tools/qsource.py +436 -0
  483. parrot/tools/querytoolkit.py +395 -0
  484. parrot/tools/quickeda.py +827 -0
  485. parrot/tools/resttool.py +553 -0
  486. parrot/tools/retail/__init__.py +0 -0
  487. parrot/tools/retail/bby.py +528 -0
  488. parrot/tools/sandboxtool.py +703 -0
  489. parrot/tools/sassie/__init__.py +352 -0
  490. parrot/tools/scraping/__init__.py +7 -0
  491. parrot/tools/scraping/docs/select.md +466 -0
  492. parrot/tools/scraping/documentation.md +1278 -0
  493. parrot/tools/scraping/driver.py +436 -0
  494. parrot/tools/scraping/models.py +576 -0
  495. parrot/tools/scraping/options.py +85 -0
  496. parrot/tools/scraping/orchestrator.py +517 -0
  497. parrot/tools/scraping/readme.md +740 -0
  498. parrot/tools/scraping/tool.py +3115 -0
  499. parrot/tools/seasonaldetection.py +642 -0
  500. parrot/tools/shell_tool/__init__.py +5 -0
  501. parrot/tools/shell_tool/actions.py +408 -0
  502. parrot/tools/shell_tool/engine.py +155 -0
  503. parrot/tools/shell_tool/models.py +322 -0
  504. parrot/tools/shell_tool/tool.py +442 -0
  505. parrot/tools/site_search.py +214 -0
  506. parrot/tools/textfile.py +418 -0
  507. parrot/tools/think.py +378 -0
  508. parrot/tools/toolkit.py +298 -0
  509. parrot/tools/webapp_tool.py +187 -0
  510. parrot/tools/whatif.py +1279 -0
  511. parrot/tools/workday/MULTI_WSDL_EXAMPLE.md +249 -0
  512. parrot/tools/workday/__init__.py +6 -0
  513. parrot/tools/workday/models.py +1389 -0
  514. parrot/tools/workday/tool.py +1293 -0
  515. parrot/tools/yfinance_tool.py +306 -0
  516. parrot/tools/zipcode.py +217 -0
  517. parrot/utils/__init__.py +2 -0
  518. parrot/utils/helpers.py +73 -0
  519. parrot/utils/parsers/__init__.py +5 -0
  520. parrot/utils/parsers/toml.c +12078 -0
  521. parrot/utils/parsers/toml.cpython-310-x86_64-linux-gnu.so +0 -0
  522. parrot/utils/parsers/toml.pyx +21 -0
  523. parrot/utils/toml.py +11 -0
  524. parrot/utils/types.cpp +20936 -0
  525. parrot/utils/types.cpython-310-x86_64-linux-gnu.so +0 -0
  526. parrot/utils/types.pyx +213 -0
  527. parrot/utils/uv.py +11 -0
  528. parrot/version.py +10 -0
  529. parrot/yaml-rs/Cargo.lock +350 -0
  530. parrot/yaml-rs/Cargo.toml +19 -0
  531. parrot/yaml-rs/pyproject.toml +19 -0
  532. parrot/yaml-rs/python/yaml_rs/__init__.py +81 -0
  533. parrot/yaml-rs/src/lib.rs +222 -0
  534. requirements/docker-compose.yml +24 -0
  535. requirements/requirements-dev.txt +21 -0
@@ -0,0 +1,152 @@
1
+ from __future__ import annotations
2
+ import sys
3
+ from typing import Any, Optional, Tuple
4
+ from .formats import get_renderer, get_output_prompt, has_system_prompt
5
+ from ..models.outputs import OutputMode
6
+ from ..template.engine import TemplateEngine
7
+
8
+
9
+ class OutputFormatter:
10
+ """
11
+ Formatter for AI responses supporting multiple output modes.
12
+ """
13
+
14
+ def __init__(self, template_engine: Optional[TemplateEngine] = None):
15
+ """
16
+ Initialize the OutputFormatter.
17
+
18
+ Args:
19
+ template_engine: Optional TemplateEngine instance for template-based rendering.
20
+ If not provided, a new one will be created when needed.
21
+ """
22
+ self._is_ipython = self._detect_ipython()
23
+ self._is_notebook = self._detect_notebook()
24
+ self._environment = self._detect_environment()
25
+ self._renderers = {}
26
+ self._template_engine = template_engine
27
+
28
+ def _detect_environment(self) -> str:
29
+ if self._is_ipython:
30
+ return "jupyter" if self._is_notebook else "ipython"
31
+ return "terminal"
32
+
33
+ def _detect_ipython(self) -> bool:
34
+ try:
35
+ if "IPython" not in sys.modules:
36
+ return False
37
+ from IPython import get_ipython
38
+ return get_ipython() is not None
39
+ except (ImportError, NameError):
40
+ return False
41
+
42
+ def _detect_notebook(self) -> bool:
43
+ try:
44
+ from IPython import get_ipython
45
+ ipython = get_ipython()
46
+ return ipython is not None and "IPKernelApp" in ipython.config
47
+ except Exception:
48
+ return False
49
+
50
+ def _get_renderer(self, mode: OutputMode):
51
+ """
52
+ Get or create a renderer instance for the specified output mode.
53
+
54
+ Args:
55
+ mode: OutputMode enum value
56
+
57
+ Returns:
58
+ Renderer instance for the given mode
59
+ """
60
+ if mode not in self._renderers:
61
+ renderer_cls = get_renderer(mode)
62
+ # Special handling for TEMPLATE_REPORT renderer to pass TemplateEngine
63
+ if mode == OutputMode.TEMPLATE_REPORT:
64
+ # Lazy initialize TemplateEngine if not provided
65
+ if self._template_engine is None:
66
+ self._template_engine = TemplateEngine()
67
+ self._renderers[mode] = renderer_cls(
68
+ template_engine=self._template_engine
69
+ )
70
+ else:
71
+ self._renderers[mode] = renderer_cls()
72
+ return self._renderers[mode]
73
+
74
+ def get_system_prompt(self, mode: OutputMode) -> Optional[str]:
75
+ """
76
+ Get the system prompt for a given output mode.
77
+
78
+ Args:
79
+ mode: OutputMode enum value
80
+
81
+ Returns:
82
+ System prompt string or None if mode has no specific prompt
83
+ """
84
+ print(f"Getting system prompt for mode: {mode}")
85
+ return get_output_prompt(mode)
86
+
87
+ def has_system_prompt(self, mode: OutputMode) -> bool:
88
+ """
89
+ Check if an output mode has a registered system prompt.
90
+
91
+ Args:
92
+ mode: OutputMode enum value
93
+
94
+ Returns:
95
+ True if mode has a system prompt
96
+ """
97
+ return has_system_prompt(mode)
98
+
99
+ async def format(
100
+ self,
101
+ mode: OutputMode,
102
+ data: Any,
103
+ **kwargs
104
+ ) -> Tuple[str, Optional[str]]:
105
+ """
106
+ Format output based on mode
107
+
108
+ Returns:
109
+ Tuple[str, Optional[str]]: (content, wrapped_content)
110
+ - content: main formatted output
111
+ - wrapped_content: optional wrapped version (e.g., HTML)
112
+ """
113
+ if mode == OutputMode.DEFAULT:
114
+ return data, None
115
+
116
+ renderer = self._get_renderer(mode)
117
+ render_method = getattr(renderer, "render_async", renderer.render)
118
+
119
+ # Call renderer and get tuple response
120
+ return await render_method(
121
+ data,
122
+ environment=self._environment,
123
+ is_ipython=self._is_ipython,
124
+ is_notebook=self._is_notebook,
125
+ **kwargs,
126
+ )
127
+
128
+ def add_template(self, name: str, content: str) -> None:
129
+ """
130
+ Add an in-memory template for use with TEMPLATE_REPORT mode.
131
+
132
+ Args:
133
+ name: Template name (e.g., 'report.html', 'summary.md')
134
+ content: Jinja2 template content
135
+
136
+ Example:
137
+ formatter = OutputFormatter()
138
+ formatter.add_template('report.html', '<h1>{{ title }}</h1>')
139
+ result = await formatter.format_async(
140
+ OutputMode.TEMPLATE_REPORT,
141
+ {"title": "My Report"},
142
+ template="report.html"
143
+ )
144
+ """
145
+ # Ensure TemplateEngine is initialized
146
+ if self._template_engine is None:
147
+ self._template_engine = TemplateEngine()
148
+
149
+ # Get or create the TEMPLATE_REPORT renderer to add the template
150
+ renderer = self._get_renderer(OutputMode.TEMPLATE_REPORT)
151
+ if hasattr(renderer, 'add_template'):
152
+ renderer.add_template(name, content)
@@ -0,0 +1,95 @@
1
+ from typing import Dict, Any, List, Optional
2
+ from pathlib import Path
3
+ from jinja2 import Environment, FileSystemLoader, Template
4
+ from pydantic import BaseModel
5
+
6
+ class TemplateSection(BaseModel):
7
+ """Defines a fillable section in the template."""
8
+ name: str
9
+ description: str
10
+ content_type: str # 'text', 'table', 'chart', 'image', 'list'
11
+ required: bool = True
12
+ example: Optional[str] = None
13
+
14
+ class ReportTemplate(BaseModel):
15
+ """Defines a report template structure."""
16
+ name: str
17
+ description: str
18
+ template_path: Path
19
+ sections: List[TemplateSection]
20
+ css_path: Optional[Path] = None
21
+
22
+ def get_section_prompts(self) -> Dict[str, str]:
23
+ """Generate prompts for LLM to fill each section."""
24
+ prompts = {}
25
+ for section in self.sections:
26
+ prompt = (
27
+ f"Generate {section.content_type} content for the "
28
+ f"'{section.name}' section.\n"
29
+ f"Description: {section.description}\n"
30
+ )
31
+ if section.example:
32
+ prompt += f"Example format:\n{section.example}\n"
33
+ prompts[section.name] = prompt
34
+ return prompts
35
+
36
+ class TemplateRegistry:
37
+ """Registry of available templates."""
38
+
39
+ def __init__(self, templates_dir: Path):
40
+ self.templates_dir = templates_dir
41
+ self.env = Environment(
42
+ loader=FileSystemLoader(templates_dir)
43
+ )
44
+ self._templates: Dict[str, ReportTemplate] = {}
45
+
46
+ def register(self, template: ReportTemplate):
47
+ """Register a template."""
48
+ self._templates[template.name] = template
49
+
50
+ def get(self, name: str) -> ReportTemplate:
51
+ """Get a template by name."""
52
+ return self._templates.get(name)
53
+
54
+ def list(self) -> List[str]:
55
+ """List available templates."""
56
+ return list(self._templates.keys())
57
+
58
+ # Built-in templates
59
+ EXECUTIVE_SUMMARY_TEMPLATE = ReportTemplate(
60
+ name="executive_summary",
61
+ description="Executive summary report with key findings",
62
+ template_path=Path("templates/executive_summary.html"),
63
+ sections=[
64
+ TemplateSection(
65
+ name="title",
66
+ description="Report title",
67
+ content_type="text"
68
+ ),
69
+ TemplateSection(
70
+ name="executive_summary",
71
+ description="High-level overview (2-3 paragraphs)",
72
+ content_type="text"
73
+ ),
74
+ TemplateSection(
75
+ name="key_findings",
76
+ description="Bullet points of main findings",
77
+ content_type="list"
78
+ ),
79
+ TemplateSection(
80
+ name="data_table",
81
+ description="Supporting data in table format",
82
+ content_type="table"
83
+ ),
84
+ TemplateSection(
85
+ name="visualization",
86
+ description="Chart showing trends",
87
+ content_type="chart"
88
+ ),
89
+ TemplateSection(
90
+ name="recommendations",
91
+ description="Actionable recommendations",
92
+ content_type="list"
93
+ )
94
+ ]
95
+ )
File without changes
@@ -0,0 +1,210 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import Any, Dict, Optional, List, Tuple, Union
3
+ from pathlib import Path
4
+ import io
5
+ from PIL import (
6
+ Image,
7
+ ImageDraw,
8
+ ImageFont,
9
+ ImageEnhance,
10
+ ImageOps
11
+ )
12
+ from navconfig.logging import logging
13
+ from datamodel.parsers.json import JSONContent # pylint: disable=E0611
14
+ from ..clients.factory import SUPPORTED_CLIENTS
15
+ from ..clients.google import GoogleGenAIClient, GoogleModel
16
+
17
+
18
+ logging.getLogger('pytesseract').setLevel(logging.WARNING)
19
+
20
+ class AbstractPipeline(ABC):
21
+ """Abstract base class for all pipelines."""
22
+ def __init__(
23
+ self,
24
+ llm: Any = None,
25
+ llm_provider: str = "google",
26
+ llm_model: Optional[str] = None,
27
+ **kwargs: Any
28
+ ):
29
+ """
30
+ Initialize the 3-step pipeline
31
+
32
+ Args:
33
+ llm_provider: LLM provider for identification
34
+ llm_model: Specific LLM model
35
+ api_key: API key
36
+ detection_model: Object detection model to use
37
+ """
38
+ self.llm = llm
39
+ self.llm_provider = None
40
+ self.logger = logging.getLogger(f'parrot.pipelines.{self.__class__.__name__}')
41
+ self._json = JSONContent()
42
+ if not llm:
43
+ self.llm_provider = llm_provider.lower()
44
+ self.llm = self._get_llm(
45
+ llm_provider,
46
+ llm_model,
47
+ **kwargs
48
+ )
49
+ else:
50
+ self.llm_provider = llm.client_name.lower()
51
+ # Ensure a Google Client for multi-modal capabilities:
52
+ self.roi_client = GoogleGenAIClient(
53
+ model=GoogleModel.GEMINI_2_5_FLASH,
54
+ temperature=0.0,
55
+ max_retries=2,
56
+ timeout=20
57
+ )
58
+
59
+ def _get_llm(
60
+ self,
61
+ provider: str,
62
+ model: Optional[str] = None,
63
+ **kwargs: Any
64
+ ) -> Any:
65
+ """
66
+ Get the LLM client based on provider and model
67
+
68
+ Args:
69
+ provider: LLM provider name
70
+ model: Specific model to use
71
+ **kwargs: Additional parameters for client initialization
72
+
73
+ Returns:
74
+ Initialized LLM client
75
+ """
76
+ if provider not in SUPPORTED_CLIENTS:
77
+ raise ValueError(
78
+ f"Unsupported LLM provider: {provider}"
79
+ )
80
+
81
+ client_class = SUPPORTED_CLIENTS[provider]
82
+ client = client_class(model=model, **kwargs)
83
+ self.llm_provider = client.client_name.lower()
84
+ return client
85
+
86
+ def open_image(self, image_path: Union[Path, Image.Image]) -> Image.Image:
87
+ """Open an image from a file path."""
88
+ try:
89
+ if isinstance(image_path, (str, Path)):
90
+ img = Image.open(str(image_path))
91
+ else:
92
+ img = image_path
93
+ if img.mode != "RGB":
94
+ img = img.convert("RGB")
95
+ img = self._enhance_image(img)
96
+ self.logger.debug(
97
+ f"Opened image {image_path} with size {img.size} and mode {img.mode}"
98
+ )
99
+ return img
100
+ except Exception as e:
101
+ self.logger.error(f"Error opening image {image_path}: {e}")
102
+ raise
103
+
104
+ def _clamp(self, w, h, x1, y1, x2, y2):
105
+ x1, x2 = int(max(0, min(w - 1, min(x1, x2)))), int(max(0, min(w - 1, max(x1, x2))))
106
+ y1, y2 = int(max(0, min(h - 1, min(y1, y2)))), int(max(0, min(h - 1, max(y1, y2))))
107
+ return x1, y1, x2, y2
108
+
109
+ def _save_detections(
110
+ self,
111
+ pil_image: Image.Image,
112
+ poster_bounds: Tuple[int, int, int, int],
113
+ detections: List[dict],
114
+ save_path: str,
115
+ poster_label: str = 'poster_panel',
116
+ ) -> None:
117
+ """Save debug image showing poster detection results"""
118
+ try:
119
+ debug_img = pil_image.copy()
120
+ draw = ImageDraw.Draw(debug_img)
121
+ # draw the detections:
122
+ for det in detections:
123
+ label = det.label
124
+ conf = float(det.confidence or 0.0)
125
+ bbox = det.bbox
126
+ x1 = int(bbox.x1 * debug_img.width)
127
+ y1 = int(bbox.y1 * debug_img.height)
128
+ x2 = int(bbox.x2 * debug_img.width)
129
+ y2 = int(bbox.y2 * debug_img.height)
130
+ x1, y1, x2, y2 = self._clamp(debug_img.width, debug_img.height, x1, y1, x2, y2)
131
+
132
+ color = (255, 165, 0) if label == poster_label else (0, 255, 255)
133
+ draw.rectangle(
134
+ [(x1, y1), (x2, y2)],
135
+ outline=color,
136
+ width=3
137
+ )
138
+ draw.text(
139
+ (x1, y1 - 20),
140
+ f"{label} {conf:.2f}",
141
+ fill=color
142
+ )
143
+
144
+ # Draw final poster bounds in bright green
145
+ x1, y1, x2, y2 = poster_bounds
146
+ draw.rectangle(
147
+ [(x1, y1), (x2, y2)],
148
+ outline=(0, 255, 0),
149
+ width=4
150
+ )
151
+ draw.text(
152
+ (x1, y1 - 45),
153
+ f"POSTER: {x2-x1}x{y2-y1}",
154
+ fill=(0, 255, 0)
155
+ )
156
+
157
+ # Save debug image
158
+ Path(save_path).parent.mkdir(parents=True, exist_ok=True)
159
+ debug_img.save(save_path, quality=95)
160
+ self.logger.debug(
161
+ f"Saved poster debug image to {save_path}"
162
+ )
163
+
164
+ except Exception as e:
165
+ self.logger.error(f"Failed to save debug image: {e}")
166
+
167
+ def _enhance_image(
168
+ self,
169
+ pil_img: "Image.Image",
170
+ brightness: float = 1.10,
171
+ contrast: float = 1.20
172
+ ) -> "Image.Image":
173
+ """
174
+ Enhances a PIL image by adjusting brightness and contrast.
175
+ This generic utility can be used by any pipeline subclass.
176
+ """
177
+ self.logger.debug("Applying generic image enhancement...")
178
+ # Brightness/contrast + autocontrast; tweak if needed
179
+ pil = ImageEnhance.Brightness(pil_img).enhance(brightness)
180
+ pil = ImageEnhance.Contrast(pil).enhance(contrast)
181
+ pil = ImageOps.autocontrast(pil)
182
+ return pil
183
+
184
+ def _downscale_image(self, img: Image.Image, max_side=1024, quality=82) -> Image.Image:
185
+ if img.mode != "RGB":
186
+ img = img.convert("RGB")
187
+ w, h = img.size
188
+ s = max(w, h)
189
+ if s > max_side:
190
+ scale = max_side / float(s)
191
+ img = img.resize((int(w * scale), int(h * scale)), Image.Resampling.LANCZOS)
192
+ # (Optional) strip metadata by re-encoding
193
+ bio = io.BytesIO()
194
+ img.save(bio, format="JPEG", quality=quality, optimize=True)
195
+ bio.seek(0)
196
+ return Image.open(bio)
197
+
198
+ @abstractmethod
199
+ async def run(self, *args: Any, **kwargs: Any) -> Dict[str, Any]:
200
+ """
201
+ Run the pipeline with the provided arguments
202
+
203
+ Args:
204
+ *args: Positional arguments for the pipeline
205
+ **kwargs: Keyword arguments for the pipeline
206
+
207
+ Returns:
208
+ Dictionary with results of the pipeline execution
209
+ """
210
+ raise NotImplementedError("Subclasses must implement this method")
@@ -0,0 +1,124 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import Any, Dict, Optional, List, Tuple
3
+ import cv2
4
+ import torch
5
+ from PIL import Image
6
+ from transformers import CLIPProcessor, CLIPModel
7
+ from navconfig.logging import logging
8
+ try:
9
+ from ultralytics import YOLO # yolo12m works with this API
10
+ except Exception:
11
+ YOLO = None
12
+ from ..models.detections import DetectionBox
13
+
14
+ class AbstractDetector(ABC):
15
+ """Abstract base class for all detectors."""
16
+ def __init__(
17
+ self,
18
+ yolo_model: str = "yolo12l.pt",
19
+ conf: float = 0.15,
20
+ iou: float = 0.5,
21
+ device: str = "cuda" if torch.cuda.is_available() else "cpu",
22
+ **kwargs
23
+ ):
24
+ if isinstance(yolo_model, str):
25
+ assert YOLO is not None, "ultralytics is required"
26
+ self.yolo = YOLO(yolo_model)
27
+ else:
28
+ self.yolo = yolo_model
29
+ self.conf = conf
30
+ self.iou = iou
31
+ self.device = device
32
+ self.logger = logging.getLogger(
33
+ f'parrot.pipelines.{self.__class__.__name__}'
34
+ )
35
+ self._define_clip()
36
+
37
+ # ----------------------- enhancement & CLIP -------------------------------
38
+ def _embed_image(self, path: Optional[str]):
39
+ if not path:
40
+ return None
41
+ im = Image.open(path).convert("RGB")
42
+ with torch.no_grad():
43
+ inputs = self.proc(images=im, return_tensors="pt").to(self.device)
44
+ feat = self.clip.get_image_features(**inputs)
45
+ feat = feat / feat.norm(dim=-1, keepdim=True)
46
+ return feat
47
+
48
+ def _define_clip(self):
49
+ self.clip = CLIPModel.from_pretrained("openai/clip-vit-base-patch32").to(self.device)
50
+ self.proc = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32")
51
+
52
+ def _iou(self, a: DetectionBox, b: DetectionBox) -> float:
53
+ ix1, iy1 = max(a.x1, b.x1), max(a.y1, b.y1)
54
+ ix2, iy2 = min(a.x2, b.x2), min(a.y2, b.y2)
55
+ iw, ih = max(0, ix2 - ix1), max(0, iy2 - iy1)
56
+ inter = iw * ih
57
+ if inter <= 0:
58
+ return 0.0
59
+ ua = a.area + b.area - inter
60
+ return inter / float(max(1, ua))
61
+
62
+ def _normalized_y(self, b, h: int) -> Tuple[float, float, float]:
63
+ y1n, y2n = b.y1 / h, b.y2 / h
64
+ yc = 0.5 * (y1n + y2n)
65
+ return y1n, yc, y2n
66
+
67
+ def _iou_box_tuple(self, d: DetectionBox, box: tuple[int,int,int,int]) -> float:
68
+ ax1, ay1, ax2, ay2 = box
69
+ ix1, iy1 = max(d.x1, ax1), max(d.y1, ay1)
70
+ ix2, iy2 = min(d.x2, ax2), min(d.y2, ay2)
71
+ if ix2 <= ix1 or iy2 <= iy1:
72
+ return 0.0
73
+ inter = (ix2 - ix1) * (iy2 - iy1)
74
+ return inter / float(d.area + (ax2-ax1)*(ay2-ay1) - inter + 1e-6)
75
+
76
+ def _coerce_bbox(self, bbox, W, H):
77
+ if bbox is None:
78
+ return None
79
+ if isinstance(bbox, (list, tuple)) and len(bbox) == 4:
80
+ x1, y1, x2, y2 = map(float, bbox)
81
+ elif isinstance(bbox, dict):
82
+ if {"x1","y1","x2","y2"} <= bbox.keys():
83
+ x1, y1, x2, y2 = map(float, (bbox["x1"], bbox["y1"], bbox["x2"], bbox["y2"]))
84
+ elif {"x","y","w","h"} <= bbox.keys():
85
+ x1, y1 = float(bbox["x"]), float(bbox["y"])
86
+ x2, y2 = x1 + float(bbox["w"]), y1 + float(bbox["h"])
87
+ else:
88
+ return None
89
+ else:
90
+ return None
91
+ def to_px(v, M):
92
+ return int(round(v * M)) if v <= 1.5 else int(round(v))
93
+ x1, y1, x2, y2 = to_px(x1, W), to_px(y1, H), to_px(x2, W), to_px(y2, H)
94
+ if x2 < x1:
95
+ x1, x2 = x2, x1
96
+ if y2 < y1:
97
+ y1, y2 = y2, y1
98
+ x1 = max(0, min(W-1, x1))
99
+ x2 = max(0, min(W-1, x2))
100
+ y1 = max(0, min(H-1, y1))
101
+ y2 = max(0, min(H-1, y2))
102
+ if (x2-x1) < 4 or (y2-y1) < 4:
103
+ return None
104
+ return (x1, y1, x2, y2)
105
+
106
+ @abstractmethod
107
+ async def detect(
108
+ self,
109
+ image: Any,
110
+ image_array: Any,
111
+ **kwargs: Any
112
+ ) -> Tuple[Any, List[Any]]:
113
+ """
114
+ Abstract method for detecting objects in an image.
115
+
116
+ Args:
117
+ image: The input image.
118
+ image_array: The input image as a numpy array.
119
+ **kwargs: Additional keyword arguments.
120
+
121
+ Returns:
122
+ A tuple containing the processed image and a list of detections.
123
+ """
124
+ pass
@@ -0,0 +1,90 @@
1
+ from typing import Optional, Dict, List, Any, Union
2
+ from pathlib import Path
3
+ from enum import Enum
4
+ from PIL import Image
5
+ from pydantic import BaseModel, Field
6
+ from ..models.detections import (
7
+ PlanogramDescription,
8
+ PlanogramDescriptionFactory,
9
+ )
10
+
11
+ class EndcapGeometry(BaseModel):
12
+ """Configurable endcap geometry parameters"""
13
+ aspect_ratio: float = Field(default=1.35, description="Endcap width/height ratio")
14
+ left_margin_ratio: float = Field(default=0.01, description="Left margin as ratio of panel width")
15
+ right_margin_ratio: float = Field(default=0.03, description="Right margin as ratio of panel width")
16
+ top_margin_ratio: float = Field(default=0.02, description="Top margin as ratio of panel height")
17
+
18
+ # NEW: Additional margin controls for better shelf separation
19
+ bottom_margin_ratio: float = Field(default=0.05, description="Bottom margin as ratio of panel height")
20
+ inter_shelf_padding: float = Field(default=0.02, description="Padding between shelves as ratio of ROI height")
21
+
22
+ # ROI detection specific margins
23
+ width_margin_percent: float = Field(default=0.25, description="Panel width margin percentage")
24
+ height_margin_percent: float = Field(default=0.30, description="Panel height margin percentage")
25
+ top_margin_percent: float = Field(default=0.05, description="Panel top margin percentage")
26
+ side_margin_percent: float = Field(default=0.05, description="Panel side margin percentage")
27
+
28
+ class PlanogramConfig(BaseModel):
29
+ """
30
+ Complete configuration for planogram analysis pipeline.
31
+ Contains planogram description, prompts, and reference images.
32
+ """
33
+ planogram_id: Optional[int] = Field(
34
+ default=None,
35
+ description="Optional unique identifier for the planogram (if any)"
36
+ )
37
+
38
+ config_name: str = Field(
39
+ default="default_planogram_config",
40
+ description="Name of the planogram configuration"
41
+ )
42
+
43
+ # Core planogram configuration
44
+ planogram_config: Dict[str, Any] = Field(
45
+ description="Planogram configuration dictionary (gets converted to PlanogramDescription)"
46
+ )
47
+
48
+ # ROI Detection prompt
49
+ roi_detection_prompt: str = Field(
50
+ description="Prompt for ROI detection phase (used by _find_poster method)"
51
+ )
52
+
53
+ # Object identification prompt
54
+ object_identification_prompt: str = Field(
55
+ description="Prompt for Phase 2 object identification (used by _identify_objects method)"
56
+ )
57
+
58
+ # Reference images
59
+ reference_images: Dict[str, Union[str, Path, Image.Image]] = Field(
60
+ default_factory=dict,
61
+ description="Reference images for object identification"
62
+ )
63
+
64
+ # Optional: Additional detection parameters
65
+ confidence_threshold: float = Field(
66
+ default=0.25,
67
+ description="YOLO detection confidence threshold"
68
+ )
69
+
70
+ detection_model: str = Field(
71
+ default="yolo11l.pt",
72
+ description="YOLO model to use for detection"
73
+ )
74
+
75
+ endcap_geometry: EndcapGeometry = Field(
76
+ default_factory=EndcapGeometry,
77
+ description="Endcap geometry and margin configuration"
78
+ )
79
+
80
+ class Config:
81
+ """Pydantic configuration."""
82
+ arbitrary_types_allowed = True
83
+
84
+ def get_planogram_description(self) -> PlanogramDescription:
85
+ """
86
+ Load and validate a planogram description from a configuration dictionary.
87
+ Uses PlanogramDescriptionFactory to parse and validate the config.
88
+ """
89
+ factory = PlanogramDescriptionFactory()
90
+ return factory.create_planogram_description(self.planogram_config)