From 148a41ce236547098610e1abda303cf29a447d5a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jan 2026 13:06:37 +0000 Subject: [PATCH 1/2] Bump next from 14.0.4 to 14.2.35 in /CogniwareIms/frontend Bumps [next](https://github.com/vercel/next.js) from 14.0.4 to 14.2.35. - [Release notes](https://github.com/vercel/next.js/releases) - [Changelog](https://github.com/vercel/next.js/blob/canary/release.js) - [Commits](https://github.com/vercel/next.js/compare/v14.0.4...v14.2.35) --- updated-dependencies: - dependency-name: next dependency-version: 14.2.35 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- CogniwareIms/frontend/package-lock.json | 137 ++++++++++++------------ CogniwareIms/frontend/package.json | 2 +- 2 files changed, 68 insertions(+), 71 deletions(-) diff --git a/CogniwareIms/frontend/package-lock.json b/CogniwareIms/frontend/package-lock.json index eb41495157..8169ad4cfc 100644 --- a/CogniwareIms/frontend/package-lock.json +++ b/CogniwareIms/frontend/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "axios": "^1.6.2", "lucide-react": "^0.294.0", - "next": "14.0.4", + "next": "^14.2.35", "react": "^18.2.0", "react-dom": "^18.2.0" }, @@ -100,15 +100,15 @@ } }, "node_modules/@next/env": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/@next/env/-/env-14.0.4.tgz", - "integrity": "sha512-irQnbMLbUNQpP1wcE5NstJtbuA/69kRfzBrpAD7Gsn8zm/CY6YQYc3HQBz8QPxwISG26tIm5afvvVbu508oBeQ==", + "version": "14.2.35", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.35.tgz", + "integrity": "sha512-DuhvCtj4t9Gwrx80dmz2F4t/zKQ4ktN8WrMwOuVzkJfBilwAwGr6v16M5eI8yCuZ63H9TTuEU09Iu2HqkzFPVQ==", "license": "MIT" }, "node_modules/@next/swc-darwin-arm64": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.0.4.tgz", - "integrity": "sha512-mF05E/5uPthWzyYDyptcwHptucf/jj09i2SXBPwNzbgBNc+XnwzrL0U6BmPjQeOL+FiB+iG1gwBeq7mlDjSRPg==", + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.33.tgz", + "integrity": "sha512-HqYnb6pxlsshoSTubdXKu15g3iivcbsMXg4bYpjL2iS/V6aQot+iyF4BUc2qA/J/n55YtvE4PHMKWBKGCF/+wA==", "cpu": [ "arm64" ], @@ -122,9 +122,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.0.4.tgz", - "integrity": "sha512-IZQ3C7Bx0k2rYtrZZxKKiusMTM9WWcK5ajyhOZkYYTCc8xytmwSzR1skU7qLgVT/EY9xtXDG0WhY6fyujnI3rw==", + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.33.tgz", + "integrity": "sha512-8HGBeAE5rX3jzKvF593XTTFg3gxeU4f+UWnswa6JPhzaR6+zblO5+fjltJWIZc4aUalqTclvN2QtTC37LxvZAA==", "cpu": [ "x64" ], @@ -138,9 +138,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.0.4.tgz", - "integrity": "sha512-VwwZKrBQo/MGb1VOrxJ6LrKvbpo7UbROuyMRvQKTFKhNaXjUmKTu7wxVkIuCARAfiI8JpaWAnKR+D6tzpCcM4w==", + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.33.tgz", + "integrity": "sha512-JXMBka6lNNmqbkvcTtaX8Gu5by9547bukHQvPoLe9VRBx1gHwzf5tdt4AaezW85HAB3pikcvyqBToRTDA4DeLw==", "cpu": [ "arm64" ], @@ -154,9 +154,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.0.4.tgz", - "integrity": "sha512-8QftwPEW37XxXoAwsn+nXlodKWHfpMaSvt81W43Wh8dv0gkheD+30ezWMcFGHLI71KiWmHK5PSQbTQGUiidvLQ==", + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.33.tgz", + "integrity": "sha512-Bm+QulsAItD/x6Ih8wGIMfRJy4G73tu1HJsrccPW6AfqdZd0Sfm5Imhgkgq2+kly065rYMnCOxTBvmvFY1BKfg==", "cpu": [ "arm64" ], @@ -170,9 +170,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.0.4.tgz", - "integrity": "sha512-/s/Pme3VKfZAfISlYVq2hzFS8AcAIOTnoKupc/j4WlvF6GQ0VouS2Q2KEgPuO1eMBwakWPB1aYFIA4VNVh667A==", + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.33.tgz", + "integrity": "sha512-FnFn+ZBgsVMbGDsTqo8zsnRzydvsGV8vfiWwUo1LD8FTmPTdV+otGSWKc4LJec0oSexFnCYVO4hX8P8qQKaSlg==", "cpu": [ "x64" ], @@ -186,9 +186,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.0.4.tgz", - "integrity": "sha512-m8z/6Fyal4L9Bnlxde5g2Mfa1Z7dasMQyhEhskDATpqr+Y0mjOBZcXQ7G5U+vgL22cI4T7MfvgtrM2jdopqWaw==", + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.33.tgz", + "integrity": "sha512-345tsIWMzoXaQndUTDv1qypDRiebFxGYx9pYkhwY4hBRaOLt8UGfiWKr9FSSHs25dFIf8ZqIFaPdy5MljdoawA==", "cpu": [ "x64" ], @@ -202,9 +202,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.0.4.tgz", - "integrity": "sha512-7Wv4PRiWIAWbm5XrGz3D8HUkCVDMMz9igffZG4NB1p4u1KoItwx9qjATHz88kwCEal/HXmbShucaslXCQXUM5w==", + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.33.tgz", + "integrity": "sha512-nscpt0G6UCTkrT2ppnJnFsYbPDQwmum4GNXYTeoTIdsmMydSKFz9Iny2jpaRupTb+Wl298+Rh82WKzt9LCcqSQ==", "cpu": [ "arm64" ], @@ -218,9 +218,9 @@ } }, "node_modules/@next/swc-win32-ia32-msvc": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.0.4.tgz", - "integrity": "sha512-zLeNEAPULsl0phfGb4kdzF/cAVIfaC7hY+kt0/d+y9mzcZHsMS3hAS829WbJ31DkSlVKQeHEjZHIdhN+Pg7Gyg==", + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.33.tgz", + "integrity": "sha512-pc9LpGNKhJ0dXQhZ5QMmYxtARwwmWLpeocFmVG5Z0DzWq5Uf0izcI8tLc+qOpqxO1PWqZ5A7J1blrUIKrIFc7Q==", "cpu": [ "ia32" ], @@ -234,9 +234,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.0.4.tgz", - "integrity": "sha512-yEh2+R8qDlDCjxVpzOTEpBLQTEFAcP2A8fUFLaWNap9GitYKkKv1//y2S6XY6zsR4rCOPRpU7plYDR+az2n30A==", + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.33.tgz", + "integrity": "sha512-nOjfZMy8B94MdisuzZo9/57xuFVLHJaDj5e/xrduJp9CV2/HrfxTRH2fbyLe+K9QT41WBLUd4iXX3R7jBp0EUg==", "cpu": [ "x64" ], @@ -298,12 +298,19 @@ "node": ">=14" } }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "license": "Apache-2.0" + }, "node_modules/@swc/helpers": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz", - "integrity": "sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==", + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.5.tgz", + "integrity": "sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==", "license": "Apache-2.0", "dependencies": { + "@swc/counter": "^0.1.3", "tslib": "^2.4.0" } }, @@ -330,6 +337,7 @@ "integrity": "sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -527,6 +535,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", @@ -1044,12 +1053,6 @@ "node": ">=10.13.0" } }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "license": "BSD-2-Clause" - }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -1208,6 +1211,7 @@ "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", "dev": true, "license": "MIT", + "peer": true, "bin": { "jiti": "bin/jiti.js" } @@ -1377,19 +1381,18 @@ } }, "node_modules/next": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/next/-/next-14.0.4.tgz", - "integrity": "sha512-qbwypnM7327SadwFtxXnQdGiKpkuhaRLE2uq62/nRul9cj9KhQ5LhHmlziTNqUidZotw/Q1I9OjirBROdUJNgA==", + "version": "14.2.35", + "resolved": "https://registry.npmjs.org/next/-/next-14.2.35.tgz", + "integrity": "sha512-KhYd2Hjt/O1/1aZVX3dCwGXM1QmOV4eNM2UTacK5gipDdPN/oHHK/4oVGy7X8GMfPMsUTUEmGlsy0EY1YGAkig==", "license": "MIT", "dependencies": { - "@next/env": "14.0.4", - "@swc/helpers": "0.5.2", + "@next/env": "14.2.35", + "@swc/helpers": "0.5.5", "busboy": "1.6.0", - "caniuse-lite": "^1.0.30001406", + "caniuse-lite": "^1.0.30001579", "graceful-fs": "^4.2.11", "postcss": "8.4.31", - "styled-jsx": "5.1.1", - "watchpack": "2.4.0" + "styled-jsx": "5.1.1" }, "bin": { "next": "dist/bin/next" @@ -1398,18 +1401,19 @@ "node": ">=18.17.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "14.0.4", - "@next/swc-darwin-x64": "14.0.4", - "@next/swc-linux-arm64-gnu": "14.0.4", - "@next/swc-linux-arm64-musl": "14.0.4", - "@next/swc-linux-x64-gnu": "14.0.4", - "@next/swc-linux-x64-musl": "14.0.4", - "@next/swc-win32-arm64-msvc": "14.0.4", - "@next/swc-win32-ia32-msvc": "14.0.4", - "@next/swc-win32-x64-msvc": "14.0.4" + "@next/swc-darwin-arm64": "14.2.33", + "@next/swc-darwin-x64": "14.2.33", + "@next/swc-linux-arm64-gnu": "14.2.33", + "@next/swc-linux-arm64-musl": "14.2.33", + "@next/swc-linux-x64-gnu": "14.2.33", + "@next/swc-linux-x64-musl": "14.2.33", + "@next/swc-win32-arm64-msvc": "14.2.33", + "@next/swc-win32-ia32-msvc": "14.2.33", + "@next/swc-win32-x64-msvc": "14.2.33" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.41.2", "react": "^18.2.0", "react-dom": "^18.2.0", "sass": "^1.3.0" @@ -1418,6 +1422,9 @@ "@opentelemetry/api": { "optional": true }, + "@playwright/test": { + "optional": true + }, "sass": { "optional": true } @@ -1598,6 +1605,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -1773,6 +1781,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -1785,6 +1794,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -2243,19 +2253,6 @@ "dev": true, "license": "MIT" }, - "node_modules/watchpack": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", - "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", - "license": "MIT", - "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - }, - "engines": { - "node": ">=10.13.0" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/CogniwareIms/frontend/package.json b/CogniwareIms/frontend/package.json index 0e37c4eed3..c9366e95d1 100644 --- a/CogniwareIms/frontend/package.json +++ b/CogniwareIms/frontend/package.json @@ -11,7 +11,7 @@ "type-check": "tsc --noEmit" }, "dependencies": { - "next": "^14.2.15", + "next": "^14.2.35", "react": "^18.2.0", "react-dom": "^18.2.0", "lucide-react": "^0.294.0", From 5ec99d69b4bb995ec310cb7ea7a20867032ffafb Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 1 Jan 2026 13:07:35 +0000 Subject: [PATCH 2/2] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- CogniwareIms/.pre-commit-config.yaml | 3 + CogniwareIms/README.md | 1 - CogniwareIms/backend/Dockerfile | 3 + CogniwareIms/backend/app/core/config.py | 21 ++---- CogniwareIms/backend/app/core/security.py | 21 ++---- .../backend/app/init_knowledge_base.py | 21 ++---- CogniwareIms/backend/app/main.py | 17 ++--- .../backend/app/services/csv_processor.py | 13 +--- .../backend/app/services/dbqna_service.py | 25 ++----- .../backend/app/services/doc_summarization.py | 32 ++------- .../backend/app/services/embedding_service.py | 25 ++----- .../app/services/file_upload_service.py | 21 ++---- .../backend/app/services/graph_generator.py | 21 ++---- .../backend/app/services/interactive_agent.py | 21 ++---- .../backend/app/services/knowledge_manager.py | 31 ++------ .../backend/app/services/llm_service.py | 25 ++----- .../backend/app/services/opea_client.py | 25 ++----- .../backend/app/services/retrieval_service.py | 33 +++------ CogniwareIms/backend/requirements.txt | 70 +++++++++---------- CogniwareIms/cogniwareims.py | 12 +--- .../docker_compose/intel/cpu/xeon/set_env.sh | 1 - CogniwareIms/frontend/Dockerfile | 3 + CogniwareIms/frontend/app/globals.css | 1 - CogniwareIms/frontend/next.config.js | 3 +- CogniwareIms/kubernetes/helm/Chart.yaml | 3 + CogniwareIms/tests/test_compose_on_xeon.sh | 21 +++--- CogniwareIms/tests/test_gmc_on_xeon.sh | 1 - 27 files changed, 145 insertions(+), 329 deletions(-) diff --git a/CogniwareIms/.pre-commit-config.yaml b/CogniwareIms/.pre-commit-config.yaml index e0849011e2..0d4c7f6d48 100644 --- a/CogniwareIms/.pre-commit-config.yaml +++ b/CogniwareIms/.pre-commit-config.yaml @@ -1,3 +1,6 @@ +# Copyright (C) 2026 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + # Pre-commit hooks configuration for OPEA compliance # See https://pre-commit.com for more information diff --git a/CogniwareIms/README.md b/CogniwareIms/README.md index 1067563f9a..0488a3c8bd 100644 --- a/CogniwareIms/README.md +++ b/CogniwareIms/README.md @@ -91,4 +91,3 @@ Apache 2.0 - See [LICENSE](LICENSE) file for details. ## Support For issues and questions, please open an issue in the OPEA GenAIExamples repository. - diff --git a/CogniwareIms/backend/Dockerfile b/CogniwareIms/backend/Dockerfile index b981c3712a..a1455a53f8 100644 --- a/CogniwareIms/backend/Dockerfile +++ b/CogniwareIms/backend/Dockerfile @@ -1,3 +1,6 @@ +# Copyright (C) 2026 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + # Multi-stage build for production optimization FROM python:3.11-slim as builder diff --git a/CogniwareIms/backend/app/core/config.py b/CogniwareIms/backend/app/core/config.py index 68ff5f132e..a7cc7cecc0 100644 --- a/CogniwareIms/backend/app/core/config.py +++ b/CogniwareIms/backend/app/core/config.py @@ -1,6 +1,5 @@ # Copyright (C) 2024 Intel Corporation # SPDX-License-Identifier: Apache-2.0 - """Application configuration Centralized settings management following 12-factor app principles.""" import os @@ -22,14 +21,10 @@ class Settings(BaseSettings): # API Configuration API_V1_PREFIX: str = "/api" - ALLOWED_ORIGINS: List[str] = os.getenv( - "ALLOWED_ORIGINS", "http://localhost:3000,http://frontend:3000" - ).split(",") + ALLOWED_ORIGINS: List[str] = os.getenv("ALLOWED_ORIGINS", "http://localhost:3000,http://frontend:3000").split(",") # Security - JWT_SECRET_KEY: str = os.getenv( - "JWT_SECRET_KEY", "CHANGE_THIS_IN_PRODUCTION_USE_openssl_rand_hex_32" - ) + JWT_SECRET_KEY: str = os.getenv("JWT_SECRET_KEY", "CHANGE_THIS_IN_PRODUCTION_USE_openssl_rand_hex_32") JWT_ALGORITHM: str = "HS256" ACCESS_TOKEN_EXPIRE_MINUTES: int = 30 REFRESH_TOKEN_EXPIRE_DAYS: int = 7 @@ -39,9 +34,7 @@ class Settings(BaseSettings): RATE_LIMIT_PER_MINUTE: int = int(os.getenv("RATE_LIMIT_PER_MINUTE", "60")) # Database - DATABASE_URL: str = os.getenv( - "DATABASE_URL", "postgresql://postgres:postgres@postgres:5432/opea_ims" - ) + DATABASE_URL: str = os.getenv("DATABASE_URL", "postgresql://postgres:postgres@postgres:5432/opea_ims") DB_POOL_SIZE: int = 10 DB_MAX_OVERFLOW: int = 20 @@ -50,13 +43,9 @@ class Settings(BaseSettings): REDIS_MAX_CONNECTIONS: int = 50 # OPEA Services - OPEA_EMBEDDING_URL: str = os.getenv( - "OPEA_EMBEDDING_URL", "http://embedding-service:6000" - ) + OPEA_EMBEDDING_URL: str = os.getenv("OPEA_EMBEDDING_URL", "http://embedding-service:6000") OPEA_LLM_URL: str = os.getenv("OPEA_LLM_URL", "http://llm-service:9000") - OPEA_RETRIEVAL_URL: str = os.getenv( - "OPEA_RETRIEVAL_URL", "http://retrieval-service:7000" - ) + OPEA_RETRIEVAL_URL: str = os.getenv("OPEA_RETRIEVAL_URL", "http://retrieval-service:7000") OPEA_GATEWAY_URL: str = os.getenv("OPEA_GATEWAY_URL", "http://opea-gateway:8888") # Models diff --git a/CogniwareIms/backend/app/core/security.py b/CogniwareIms/backend/app/core/security.py index d28863eb70..7be2063458 100644 --- a/CogniwareIms/backend/app/core/security.py +++ b/CogniwareIms/backend/app/core/security.py @@ -1,6 +1,5 @@ # Copyright (C) 2024 Intel Corporation # SPDX-License-Identifier: Apache-2.0 - """ Security utilities - JWT, password hashing, authentication Industry-standard security implementation @@ -53,9 +52,7 @@ def get_password_hash(password: str) -> str: return pwd_context.hash(password) @staticmethod - def create_access_token( - data: Dict[str, Any], expires_delta: Optional[timedelta] = None - ) -> str: + def create_access_token(data: Dict[str, Any], expires_delta: Optional[timedelta] = None) -> str: """Create a JWT access token. Args: @@ -141,9 +138,7 @@ def protected_route(user: Dict = Depends(get_current_user)): # Extract user info from payload email = payload.get("sub") if email is None: - raise HTTPException( - status_code=401, detail="Invalid authentication credentials" - ) + raise HTTPException(status_code=401, detail="Invalid authentication credentials") return payload @@ -160,9 +155,7 @@ def admin_route(user: Dict = Depends(require_role("Super Admin"))): def role_checker(current_user: Dict = Depends(get_current_user)): user_role = current_user.get("role") if user_role != required_role: - raise HTTPException( - status_code=403, detail=f"Access denied. Required role: {required_role}" - ) + raise HTTPException(status_code=403, detail=f"Access denied. Required role: {required_role}") return current_user return role_checker @@ -241,9 +234,7 @@ class RateLimiter: def __init__(self): self.requests = {} - def is_allowed( - self, identifier: str, max_requests: int = 60, window_seconds: int = 60 - ) -> bool: + def is_allowed(self, identifier: str, max_requests: int = 60, window_seconds: int = 60) -> bool: """Check if request is allowed under rate limit. Args: @@ -261,9 +252,7 @@ def is_allowed( # Clean old requests cutoff = now - timedelta(seconds=window_seconds) - self.requests[identifier] = [ - req_time for req_time in self.requests[identifier] if req_time > cutoff - ] + self.requests[identifier] = [req_time for req_time in self.requests[identifier] if req_time > cutoff] # Check limit if len(self.requests[identifier]) >= max_requests: diff --git a/CogniwareIms/backend/app/init_knowledge_base.py b/CogniwareIms/backend/app/init_knowledge_base.py index ac7ff511a2..6dd3c596cf 100644 --- a/CogniwareIms/backend/app/init_knowledge_base.py +++ b/CogniwareIms/backend/app/init_knowledge_base.py @@ -1,6 +1,5 @@ # Copyright (C) 2024 Intel Corporation # SPDX-License-Identifier: Apache-2.0 - """Knowledge Base Initialization Script Processes all CSV files and creates initial embeddings Run this after first deployment to populate the knowledge base.""" @@ -19,9 +18,7 @@ from app.services.knowledge_manager import knowledge_manager from app.services.retrieval_service import retrieval_service -logging.basicConfig( - level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s" -) +logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s") logger = logging.getLogger(__name__) @@ -49,17 +46,13 @@ async def initialize_knowledge_base(): for i in range(0, len(documents), batch_size): batch = documents[i : i + batch_size] - logger.info( - f" Processing batch {i//batch_size + 1}/{(len(documents)-1)//batch_size + 1}..." - ) + logger.info(f" Processing batch {i//batch_size + 1}/{(len(documents)-1)//batch_size + 1}...") # Extract texts texts = [doc["text"] for doc in batch] # Generate embeddings in batch - embeddings = await embedding_service.embed_batch( - texts, batch_size=batch_size - ) + embeddings = await embedding_service.embed_batch(texts, batch_size=batch_size) # Index each document for doc, embedding in zip(batch, embeddings): @@ -97,11 +90,11 @@ async def initialize_knowledge_base(): logger.info("\n" + "=" * 60) logger.info("šŸŽ‰ Knowledge Base Initialization Complete!") logger.info("=" * 60) - logger.info(f"\nšŸ“Š Summary:") + logger.info("\nšŸ“Š Summary:") logger.info(f" CSV Files Processed: {len(dataframes)}") logger.info(f" Documents Indexed: {total_indexed}") logger.info(f" Vector Store Count: {doc_count}") - logger.info(f"\nāœ… System is ready for AI-powered queries!") + logger.info("\nāœ… System is ready for AI-powered queries!") return { "success": True, @@ -134,9 +127,7 @@ async def quick_test(): # Test knowledge manager stats = await knowledge_manager.get_knowledge_stats() - logger.info( - f"āœ… Knowledge manager: OK ({stats.get('total_documents', 0)} documents)" - ) + logger.info(f"āœ… Knowledge manager: OK ({stats.get('total_documents', 0)} documents)") logger.info("\nšŸŽ‰ All systems operational!") diff --git a/CogniwareIms/backend/app/main.py b/CogniwareIms/backend/app/main.py index fea2602f65..48e0984fce 100644 --- a/CogniwareIms/backend/app/main.py +++ b/CogniwareIms/backend/app/main.py @@ -1,6 +1,5 @@ # Copyright (C) 2024 Intel Corporation # SPDX-License-Identifier: Apache-2.0 - """ OPEA Inventory Management System - Complete Backend API Full integration with all OPEA GenAIComps microservices @@ -160,9 +159,7 @@ async def health_check(): db_health = await dbqna_service.health_check() return { - "status": ( - "healthy" if all([embedding_health, llm_health, db_health]) else "degraded" - ), + "status": ("healthy" if all([embedding_health, llm_health, db_health]) else "degraded"), "timestamp": datetime.now().isoformat(), "services": { "api": "up", @@ -325,9 +322,7 @@ async def upload_csv_knowledge(file: UploadFile = File(...)): content = await file.read() # Process using file upload service - result = await file_upload_service.upload_and_process( - filename=file.filename, content=content - ) + result = await file_upload_service.upload_and_process(filename=file.filename, content=content) return result @@ -345,9 +340,7 @@ async def upload_knowledge_file(file: UploadFile = File(...)): content = await file.read() # Process using file upload service - result = await file_upload_service.upload_and_process( - filename=file.filename, content=content - ) + result = await file_upload_service.upload_and_process(filename=file.filename, content=content) return result @@ -658,9 +651,7 @@ async def startup_event(): # Load knowledge base stats stats = await knowledge_manager.get_knowledge_stats() - logger.info( - f" Knowledge Base: {stats.get('total_documents', 0)} documents indexed" - ) + logger.info(f" Knowledge Base: {stats.get('total_documents', 0)} documents indexed") logger.info("āœ… OPEA IMS Platform started successfully!") diff --git a/CogniwareIms/backend/app/services/csv_processor.py b/CogniwareIms/backend/app/services/csv_processor.py index ca567a8a73..c3ecfe4954 100644 --- a/CogniwareIms/backend/app/services/csv_processor.py +++ b/CogniwareIms/backend/app/services/csv_processor.py @@ -1,6 +1,5 @@ # Copyright (C) 2024 Intel Corporation # SPDX-License-Identifier: Apache-2.0 - """CSV Data Processor Ingests CSV files and prepares them for OPEA knowledge base.""" import json @@ -37,9 +36,7 @@ def load_all_csv_files(self) -> Dict[str, pd.DataFrame]: return dataframes - def prepare_for_embedding( - self, dataframes: Dict[str, pd.DataFrame] - ) -> List[Dict[str, Any]]: + def prepare_for_embedding(self, dataframes: Dict[str, pd.DataFrame]) -> List[Dict[str, Any]]: """Prepare data for OPEA embedding service.""" documents = [] @@ -66,9 +63,7 @@ def prepare_for_embedding( logger.info(f"Prepared {len(documents)} documents for embedding") return documents - def extract_inventory_data( - self, dataframes: Dict[str, pd.DataFrame] - ) -> Dict[str, Any]: + def extract_inventory_data(self, dataframes: Dict[str, pd.DataFrame]) -> Dict[str, Any]: """Extract structured inventory data.""" inventory_data = { "products": [], @@ -117,9 +112,7 @@ def create_knowledge_base(self) -> Dict[str, Any]: with open(output_dir / "knowledge_base.json", "w") as f: json.dump(knowledge_base, f, indent=2, default=str) - logger.info( - f"Knowledge base created with {len(knowledge_base['documents'])} documents" - ) + logger.info(f"Knowledge base created with {len(knowledge_base['documents'])} documents") return knowledge_base diff --git a/CogniwareIms/backend/app/services/dbqna_service.py b/CogniwareIms/backend/app/services/dbqna_service.py index acda2584c4..ff1a03c6de 100644 --- a/CogniwareIms/backend/app/services/dbqna_service.py +++ b/CogniwareIms/backend/app/services/dbqna_service.py @@ -1,6 +1,5 @@ # Copyright (C) 2024 Intel Corporation # SPDX-License-Identifier: Apache-2.0 - """ OPEA DBQnA Service - Database Query & Answer Converts natural language to SQL and executes against inventory database @@ -22,9 +21,7 @@ class DBQnAService: """Database Query & Answer service using OPEA LLM for SQL generation.""" def __init__(self): - self.database_url = os.getenv( - "DATABASE_URL", "postgresql://postgres:postgres@postgres:5432/opea_ims" - ) + self.database_url = os.getenv("DATABASE_URL", "postgresql://postgres:postgres@postgres:5432/opea_ims") self.engine = None self.schema_cache = None @@ -66,15 +63,9 @@ async def get_schema(self) -> Dict[str, Any]: ORDER BY ordinal_position """ ) - columns = conn.execute( - columns_query, {"table_name": table_name} - ).fetchall() - - schema["tables"][table_name] = { - "columns": [ - {"name": col, "type": dtype} for col, dtype in columns - ] - } + columns = conn.execute(columns_query, {"table_name": table_name}).fetchall() + + schema["tables"][table_name] = {"columns": [{"name": col, "type": dtype} for col, dtype in columns]} self.schema_cache = schema return schema @@ -83,9 +74,7 @@ async def get_schema(self) -> Dict[str, Any]: logger.error(f"Error getting schema: {e}") return {"tables": {}, "relationships": []} - async def natural_language_query( - self, question: str, include_explanation: bool = True - ) -> Dict[str, Any]: + async def natural_language_query(self, question: str, include_explanation: bool = True) -> Dict[str, Any]: """Convert natural language question to SQL and execute. Args: @@ -112,9 +101,7 @@ async def natural_language_query( columns = result.keys() # Convert to dict format - data = [ - {col: value for col, value in zip(columns, row)} for row in rows - ] + data = [{col: value for col, value in zip(columns, row)} for row in rows] response = { "success": True, diff --git a/CogniwareIms/backend/app/services/doc_summarization.py b/CogniwareIms/backend/app/services/doc_summarization.py index 60c17c366c..dd92775f6d 100644 --- a/CogniwareIms/backend/app/services/doc_summarization.py +++ b/CogniwareIms/backend/app/services/doc_summarization.py @@ -1,6 +1,5 @@ # Copyright (C) 2024 Intel Corporation # SPDX-License-Identifier: Apache-2.0 - """OPEA DocSummarization Service Handles document summarization and analysis.""" import json @@ -69,9 +68,7 @@ async def summarize_document( "original_length": len(text.split()), "summary": summary.strip(), "summary_length": len(summary.split()), - "compression_ratio": round( - len(summary.split()) / max(len(text.split()), 1), 2 - ), + "compression_ratio": round(len(summary.split()) / max(len(text.split()), 1), 2), "type": summary_type, } @@ -79,9 +76,7 @@ async def summarize_document( logger.error(f"Summarization error: {e}") return {"success": False, "error": str(e)} - async def summarize_inventory_report( - self, report_data: Dict[str, Any] - ) -> Dict[str, Any]: + async def summarize_inventory_report(self, report_data: Dict[str, Any]) -> Dict[str, Any]: """Summarize inventory report data Specialized for inventory metrics.""" try: # Convert report data to narrative text @@ -124,9 +119,7 @@ def _format_report_for_summarization(self, report_data: Dict[str, Any]) -> str: if "stock_by_category" in report_data: parts.append("\nStock by Category:") for cat in report_data["stock_by_category"]: - parts.append( - f" - {cat['category']}: {cat['count']} units ({cat['percentage']}%)" - ) + parts.append(f" - {cat['category']}: {cat['count']} units ({cat['percentage']}%)") if "recent_activity" in report_data: parts.append("\nRecent Activity:") @@ -179,9 +172,7 @@ async def extract_key_information(self, text: str) -> Dict[str, Any]: logger.error(f"Information extraction error: {e}") return {"success": False, "error": str(e)} - async def summarize_csv_data( - self, csv_path: str, sample_size: int = 100 - ) -> Dict[str, Any]: + async def summarize_csv_data(self, csv_path: str, sample_size: int = 100) -> Dict[str, Any]: """Summarize CSV file contents.""" try: df = pd.read_csv(csv_path) @@ -207,25 +198,16 @@ async def summarize_csv_data( "success": True, "file": csv_path, "statistics": stats, - "summary": ( - summary["summary"] if summary["success"] else "Summary unavailable" - ), + "summary": (summary["summary"] if summary["success"] else "Summary unavailable"), } except Exception as e: logger.error(f"CSV summarization error: {e}") return {"success": False, "error": str(e)} - async def generate_report_narrative( - self, title: str, data_points: List[Dict[str, Any]] - ) -> str: + async def generate_report_narrative(self, title: str, data_points: List[Dict[str, Any]]) -> str: """Generate narrative report from data points.""" - data_text = "\n".join( - [ - f"- {dp.get('label', 'Item')}: {dp.get('value', 'N/A')}" - for dp in data_points - ] - ) + data_text = "\n".join([f"- {dp.get('label', 'Item')}: {dp.get('value', 'N/A')}" for dp in data_points]) prompt = f"""Generate a professional narrative report titled "{title}" based on the following data: diff --git a/CogniwareIms/backend/app/services/embedding_service.py b/CogniwareIms/backend/app/services/embedding_service.py index 1c83968005..c06d979fc3 100644 --- a/CogniwareIms/backend/app/services/embedding_service.py +++ b/CogniwareIms/backend/app/services/embedding_service.py @@ -1,6 +1,5 @@ # Copyright (C) 2024 Intel Corporation # SPDX-License-Identifier: Apache-2.0 - """OPEA Embedding Service Integration Handles text vectorization and embedding generation.""" import logging @@ -60,9 +59,7 @@ async def embed_text(self, text: str) -> List[float]: logger.error(f"Error generating embedding: {e}") raise - async def embed_batch( - self, texts: List[str], batch_size: int = 32 - ) -> List[List[float]]: + async def embed_batch(self, texts: List[str], batch_size: int = 32) -> List[List[float]]: """Generate embeddings for multiple texts in batches More efficient for large datasets.""" embeddings = [] @@ -80,9 +77,7 @@ async def embed_batch( # Extract embeddings if "data" in result: - batch_embeddings = [ - item["embedding"] for item in result["data"] - ] + batch_embeddings = [item["embedding"] for item in result["data"]] else: # Fallback: generate one by one batch_embeddings = [] @@ -105,9 +100,7 @@ async def embed_batch( return embeddings - async def embed_documents( - self, documents: List[Dict[str, Any]] - ) -> List[Dict[str, Any]]: + async def embed_documents(self, documents: List[Dict[str, Any]]) -> List[Dict[str, Any]]: """Embed a list of documents with metadata Returns documents with added embedding field.""" texts = [doc.get("text", "") for doc in documents] embeddings = await self.embed_batch(texts) @@ -137,9 +130,7 @@ def cosine_similarity(self, vec1_tuple: tuple, vec2_tuple: tuple) -> float: return float(dot_product / (norm1 * norm2)) - async def find_similar( - self, query_text: str, candidate_texts: List[str], top_k: int = 5 - ) -> List[Dict[str, Any]]: + async def find_similar(self, query_text: str, candidate_texts: List[str], top_k: int = 5) -> List[Dict[str, Any]]: """Find most similar texts to query using cosine similarity.""" # Generate query embedding query_embedding = await self.embed_text(query_text) @@ -149,12 +140,8 @@ async def find_similar( # Calculate similarities similarities = [] - for idx, (text, embedding) in enumerate( - zip(candidate_texts, candidate_embeddings) - ): - similarity = self.cosine_similarity( - tuple(query_embedding), tuple(embedding) - ) + for idx, (text, embedding) in enumerate(zip(candidate_texts, candidate_embeddings)): + similarity = self.cosine_similarity(tuple(query_embedding), tuple(embedding)) similarities.append({"text": text, "index": idx, "similarity": similarity}) # Sort by similarity and return top k diff --git a/CogniwareIms/backend/app/services/file_upload_service.py b/CogniwareIms/backend/app/services/file_upload_service.py index f75ba5e9ab..2a5c488d80 100644 --- a/CogniwareIms/backend/app/services/file_upload_service.py +++ b/CogniwareIms/backend/app/services/file_upload_service.py @@ -1,6 +1,5 @@ # Copyright (C) 2024 Intel Corporation # SPDX-License-Identifier: Apache-2.0 - """File Upload Service Handles xlsx, csv, pdf, docx file uploads and processing for knowledge base Optimized for Intel Xeon processors.""" @@ -107,9 +106,7 @@ async def process_csv(self, file_path: Path) -> Dict[str, Any]: documents = [] for idx, row in df.iterrows(): # Create text representation - text_parts = [ - f"{col}: {row[col]}" for col in df.columns if pd.notna(row[col]) - ] + text_parts = [f"{col}: {row[col]}" for col in df.columns if pd.notna(row[col])] text = " | ".join(text_parts) documents.append( @@ -160,9 +157,7 @@ async def process_xlsx(self, file_path: Path) -> Dict[str, Any]: df = pd.read_excel(file_path, sheet_name=sheet_name) for idx, row in df.iterrows(): - text_parts = [ - f"{col}: {row[col]}" for col in df.columns if pd.notna(row[col]) - ] + text_parts = [f"{col}: {row[col]}" for col in df.columns if pd.notna(row[col])] text = " | ".join(text_parts) all_documents.append( @@ -369,9 +364,7 @@ async def upload_and_process(self, filename: str, content: bytes) -> Dict[str, A return result - def list_uploaded_files( - self, file_type: Optional[str] = None - ) -> List[Dict[str, Any]]: + def list_uploaded_files(self, file_type: Optional[str] = None) -> List[Dict[str, Any]]: """List all uploaded files.""" files = [] @@ -392,9 +385,7 @@ def list_uploaded_files( "filename": file_path.name, "type": file_path.suffix[1:], "size": stat.st_size, - "uploaded_at": datetime.fromtimestamp( - stat.st_ctime - ).isoformat(), + "uploaded_at": datetime.fromtimestamp(stat.st_ctime).isoformat(), "path": str(file_path), } ) @@ -403,6 +394,4 @@ def list_uploaded_files( # Global instance -file_upload_service = FileUploadService( - upload_dir=os.getenv("UPLOAD_DIR", "/app/uploads") -) +file_upload_service = FileUploadService(upload_dir=os.getenv("UPLOAD_DIR", "/app/uploads")) diff --git a/CogniwareIms/backend/app/services/graph_generator.py b/CogniwareIms/backend/app/services/graph_generator.py index 054ee7c4b8..626187b0ac 100644 --- a/CogniwareIms/backend/app/services/graph_generator.py +++ b/CogniwareIms/backend/app/services/graph_generator.py @@ -1,6 +1,5 @@ # Copyright (C) 2024 Intel Corporation # SPDX-License-Identifier: Apache-2.0 - """Graph Generation Service Generates data for charts and visualizations.""" import logging @@ -14,9 +13,7 @@ class GraphGenerator: """Generate data structures for frontend charts and graphs.""" - async def generate_stock_trend( - self, product_sku: str, days: int = 30 - ) -> Dict[str, Any]: + async def generate_stock_trend(self, product_sku: str, days: int = 30) -> Dict[str, Any]: """Generate stock level trend data for time-series charts.""" # In production, this would query actual historical data # For now, generate realistic sample data @@ -178,9 +175,7 @@ async def generate_heatmap_data(self) -> Dict[str, Any]: for day_idx, day in enumerate(days): for hour in range(24): - activity = ( - random.randint(5, 95) if 8 <= hour <= 18 else random.randint(0, 30) - ) + activity = random.randint(5, 95) if 8 <= hour <= 18 else random.randint(0, 30) heatmap.append({"day": day, "hour": hour, "activity": activity}) return { @@ -189,9 +184,7 @@ async def generate_heatmap_data(self) -> Dict[str, Any]: "dimensions": {"days": days, "hours": 24}, } - async def generate_forecast( - self, product_sku: str, forecast_days: int = 30 - ) -> Dict[str, Any]: + async def generate_forecast(self, product_sku: str, forecast_days: int = 30) -> Dict[str, Any]: """Generate demand forecast using simple moving average In production, would use ML models.""" # Get historical data (simulated) historical = [] @@ -210,9 +203,7 @@ async def generate_forecast( # Generate forecast forecast = [] - avg_demand = ( - sum(h["actual"] for h in historical[-7:]) / 7 - ) # 7-day moving average + avg_demand = sum(h["actual"] for h in historical[-7:]) / 7 # 7-day moving average for i in range(forecast_days): date = datetime.now() + timedelta(days=i + 1) @@ -236,9 +227,7 @@ async def generate_forecast( "method": "moving_average", } - async def generate_comparison_chart( - self, items: List[str], metric: str = "stock_level" - ) -> Dict[str, Any]: + async def generate_comparison_chart(self, items: List[str], metric: str = "stock_level") -> Dict[str, Any]: """Generate comparison data for multiple items.""" comparison_data = [] diff --git a/CogniwareIms/backend/app/services/interactive_agent.py b/CogniwareIms/backend/app/services/interactive_agent.py index 382355ea41..a741ec7cde 100644 --- a/CogniwareIms/backend/app/services/interactive_agent.py +++ b/CogniwareIms/backend/app/services/interactive_agent.py @@ -1,6 +1,5 @@ # Copyright (C) 2024 Intel Corporation # SPDX-License-Identifier: Apache-2.0 - """OPEA Interactive Agent Service Handles conversational AI interactions with context awareness.""" import json @@ -32,9 +31,7 @@ def _get_session_history(self, session_id: str) -> List[Dict[str, str]]: def _add_to_history(self, session_id: str, role: str, content: str): """Add message to conversation history.""" history = self._get_session_history(session_id) - history.append( - {"role": role, "content": content, "timestamp": datetime.now().isoformat()} - ) + history.append({"role": role, "content": content, "timestamp": datetime.now().isoformat()}) # Keep only last N messages if len(history) > self.max_history * 2: # *2 for user+assistant pairs @@ -82,9 +79,7 @@ async def chat( db_result = await dbqna_service.query_inventory(message) if db_result.get("success"): context_parts.append("Current Database Information:") - context_parts.append( - json.dumps(db_result.get("result", {}), indent=2) - ) + context_parts.append(json.dumps(db_result.get("result", {}), indent=2)) sources.append({"type": "database", "query": message}) # Step 3: Get conversation history @@ -99,9 +94,7 @@ async def chat( ) # Step 5: Generate response - response_text = await llm_service.chat_completion( - messages=messages, temperature=0.7 - ) + response_text = await llm_service.chat_completion(messages=messages, temperature=0.7) # Step 6: Update conversation history self._add_to_history(session_id, "user", message) @@ -150,18 +143,14 @@ async def _is_database_query(self, message: str) -> bool: message_lower = message.lower() return any(keyword in message_lower for keyword in db_keywords) - async def _get_rag_context( - self, query: str, top_k: int = 3 - ) -> Optional[Dict[str, Any]]: + async def _get_rag_context(self, query: str, top_k: int = 3) -> Optional[Dict[str, Any]]: """Get relevant context from knowledge base using RAG.""" try: # Generate query embedding query_embedding = await embedding_service.embed_text(query) # Search vector store - results = await retrieval_service.search( - query_embedding=query_embedding, top_k=top_k - ) + results = await retrieval_service.search(query_embedding=query_embedding, top_k=top_k) if not results: return None diff --git a/CogniwareIms/backend/app/services/knowledge_manager.py b/CogniwareIms/backend/app/services/knowledge_manager.py index 5ed81b2884..cded749bbd 100644 --- a/CogniwareIms/backend/app/services/knowledge_manager.py +++ b/CogniwareIms/backend/app/services/knowledge_manager.py @@ -1,6 +1,5 @@ # Copyright (C) 2024 Intel Corporation # SPDX-License-Identifier: Apache-2.0 - """Knowledge Base Manager Handles continuous learning and knowledge base updates Allows users to add new knowledge and retrain on combined old+new data.""" @@ -107,9 +106,7 @@ async def add_knowledge_from_text( logger.error(f"Error adding knowledge: {e}") return {"success": False, "error": str(e)} - async def add_knowledge_from_csv( - self, csv_file: Path, auto_train: bool = True - ) -> Dict[str, Any]: + async def add_knowledge_from_csv(self, csv_file: Path, auto_train: bool = True) -> Dict[str, Any]: """Add knowledge from CSV file Each row becomes a document in the knowledge base.""" try: df = pd.read_csv(csv_file) @@ -117,9 +114,7 @@ async def add_knowledge_from_csv( for idx, row in df.iterrows(): # Create text representation - text_parts = [ - f"{col}: {row[col]}" for col in df.columns if pd.notna(row[col]) - ] + text_parts = [f"{col}: {row[col]}" for col in df.columns if pd.notna(row[col])] text = " | ".join(text_parts) # Add to knowledge base @@ -284,9 +279,7 @@ async def search_knowledge( query_embedding = await embedding_service.embed_text(query) # Search vector store - results = await retrieval_service.search( - query_embedding=query_embedding, top_k=top_k, filters=filters - ) + results = await retrieval_service.search(query_embedding=query_embedding, top_k=top_k, filters=filters) return results @@ -332,9 +325,7 @@ async def retrain_all(self) -> Dict[str, Any]: ) self.save_history() - logger.info( - f"Retraining complete: {success_count}/{len(documents)} documents" - ) + logger.info(f"Retraining complete: {success_count}/{len(documents)} documents") return { "success": True, @@ -355,9 +346,7 @@ async def get_knowledge_stats(self) -> Dict[str, Any]: "total_documents": total_docs, "last_update": self.history.get("last_update"), "training_runs": len(self.history.get("training_runs", [])), - "recent_runs": self.history.get("training_runs", [])[ - -5: - ], # Last 5 runs + "recent_runs": self.history.get("training_runs", [])[-5:], # Last 5 runs "storage": {"vector_store": "Redis", "indexed": total_docs}, } except Exception as e: @@ -377,10 +366,7 @@ async def export_knowledge_base(self, output_file: Optional[Path] = None) -> Pat } if not output_file: - output_file = ( - self.knowledge_dir - / f"export_{datetime.now().strftime('%Y%m%d%H%M%S')}.json" - ) + output_file = self.knowledge_dir / f"export_{datetime.now().strftime('%Y%m%d%H%M%S')}.json" with open(output_file, "w") as f: json.dump(export_data, f, indent=2) @@ -402,10 +388,7 @@ async def import_knowledge_base(self, import_file: Path) -> Dict[str, Any]: # Add all documents result = await self.add_knowledge_batch( - documents=[ - {"text": doc["text"], "metadata": doc.get("metadata", {})} - for doc in documents - ], + documents=[{"text": doc["text"], "metadata": doc.get("metadata", {})} for doc in documents], source=f"import_{import_file.stem}", ) diff --git a/CogniwareIms/backend/app/services/llm_service.py b/CogniwareIms/backend/app/services/llm_service.py index 66ff25484c..be55f8eea8 100644 --- a/CogniwareIms/backend/app/services/llm_service.py +++ b/CogniwareIms/backend/app/services/llm_service.py @@ -1,6 +1,5 @@ # Copyright (C) 2024 Intel Corporation # SPDX-License-Identifier: Apache-2.0 - """OPEA LLM Service Integration Handles text generation, chat, and intelligent responses.""" import json @@ -44,9 +43,7 @@ async def chat_completion( "max_tokens": max_tokens or self.max_tokens, } - response = await client.post( - f"{self.base_url}/v1/chat/completions", json=payload - ) + response = await client.post(f"{self.base_url}/v1/chat/completions", json=payload) response.raise_for_status() result = response.json() @@ -67,9 +64,7 @@ async def generate_text(self, prompt: str, temperature: float = 0.7) -> str: messages = [{"role": "user", "content": prompt}] return await self.chat_completion(messages, temperature) - async def query_with_context( - self, question: str, context: str, system_prompt: Optional[str] = None - ) -> str: + async def query_with_context(self, question: str, context: str, system_prompt: Optional[str] = None) -> str: """Query LLM with context (RAG pattern) Args: @@ -92,13 +87,9 @@ async def query_with_context( messages.append({"role": "user", "content": prompt}) - return await self.chat_completion( - messages, temperature=0.3 - ) # Lower temp for factual responses + return await self.chat_completion(messages, temperature=0.3) # Lower temp for factual responses - async def generate_sql_query( - self, natural_language_query: str, schema: Dict[str, Any] - ) -> str: + async def generate_sql_query(self, natural_language_query: str, schema: Dict[str, Any]) -> str: """Generate SQL query from natural language (for DBQnA) Args: @@ -191,9 +182,7 @@ async def generate_inventory_insights(self, data: Dict[str, Any]) -> str: return await self.generate_text(prompt, temperature=0.5) - async def answer_inventory_question( - self, question: str, inventory_context: List[Dict[str, Any]] - ) -> str: + async def answer_inventory_question(self, question: str, inventory_context: List[Dict[str, Any]]) -> str: """Answer inventory-related questions with context.""" # Format inventory context context_parts = [] @@ -210,9 +199,7 @@ async def answer_inventory_question( return await self.query_with_context(question, context, system_prompt) - async def stream_chat( - self, messages: List[Dict[str, str]], temperature: float = 0.7 - ) -> AsyncGenerator[str, None]: + async def stream_chat(self, messages: List[Dict[str, str]], temperature: float = 0.7) -> AsyncGenerator[str, None]: """Stream chat responses (for real-time UI updates)""" try: async with httpx.AsyncClient(timeout=self.timeout) as client: diff --git a/CogniwareIms/backend/app/services/opea_client.py b/CogniwareIms/backend/app/services/opea_client.py index 27e27f7752..24bbb36b21 100644 --- a/CogniwareIms/backend/app/services/opea_client.py +++ b/CogniwareIms/backend/app/services/opea_client.py @@ -1,6 +1,5 @@ # Copyright (C) 2024 Intel Corporation # SPDX-License-Identifier: Apache-2.0 - """OPEA Microservices Client Handles communication with OPEA GenAIComps microservices.""" import logging @@ -26,37 +25,27 @@ async def generate_embedding(self, text: str) -> List[float]: """Generate embeddings using OPEA embedding service.""" try: async with httpx.AsyncClient(timeout=self.timeout) as client: - response = await client.post( - f"{self.embedding_url}/v1/embeddings", json={"text": text} - ) + response = await client.post(f"{self.embedding_url}/v1/embeddings", json={"text": text}) response.raise_for_status() result = response.json() return result.get("embedding", []) except Exception as e: logger.error(f"Embedding generation failed: {e}") - raise HTTPException( - status_code=500, detail=f"Embedding service error: {str(e)}" - ) + raise HTTPException(status_code=500, detail=f"Embedding service error: {str(e)}") - async def query_with_rag( - self, query: str, context: Optional[str] = None - ) -> Dict[str, Any]: + async def query_with_rag(self, query: str, context: Optional[str] = None) -> Dict[str, Any]: """Query using Retrieval-Augmented Generation.""" try: async with httpx.AsyncClient(timeout=self.timeout) as client: payload = {"question": query, "context": context or ""} - response = await client.post( - f"{self.llm_url}/v1/chat/completions", json=payload - ) + response = await client.post(f"{self.llm_url}/v1/chat/completions", json=payload) response.raise_for_status() return response.json() except Exception as e: logger.error(f"RAG query failed: {e}") raise HTTPException(status_code=500, detail=f"LLM service error: {str(e)}") - async def query_database( - self, question: str, database_schema: Optional[Dict] = None - ) -> Dict[str, Any]: + async def query_database(self, question: str, database_schema: Optional[Dict] = None) -> Dict[str, Any]: """Query database using OPEA DBQnA agent.""" try: async with httpx.AsyncClient(timeout=self.timeout) as client: @@ -87,9 +76,7 @@ async def summarize_document(self, text: str) -> str: """Summarize document using OPEA DocSummarization agent.""" try: async with httpx.AsyncClient(timeout=self.timeout) as client: - response = await client.post( - f"{self.llm_url}/v1/summarize", json={"text": text} - ) + response = await client.post(f"{self.llm_url}/v1/summarize", json={"text": text}) response.raise_for_status() result = response.json() return result.get("summary", "") diff --git a/CogniwareIms/backend/app/services/retrieval_service.py b/CogniwareIms/backend/app/services/retrieval_service.py index 0454da4872..3bf86cc88c 100644 --- a/CogniwareIms/backend/app/services/retrieval_service.py +++ b/CogniwareIms/backend/app/services/retrieval_service.py @@ -1,6 +1,5 @@ # Copyright (C) 2024 Intel Corporation # SPDX-License-Identifier: Apache-2.0 - """OPEA Retrieval Service Integration Handles semantic search and document retrieval using Redis vector store.""" import json @@ -27,14 +26,10 @@ def __init__(self): async def get_redis_client(self): """Get or create Redis client.""" if self.redis_client is None: - self.redis_client = await redis.from_url( - self.redis_url, encoding="utf-8", decode_responses=False - ) + self.redis_client = await redis.from_url(self.redis_url, encoding="utf-8", decode_responses=False) return self.redis_client - async def index_document( - self, doc_id: str, text: str, embedding: List[float], metadata: Dict[str, Any] - ) -> bool: + async def index_document(self, doc_id: str, text: str, embedding: List[float], metadata: Dict[str, Any]) -> bool: """Index a document in the vector store.""" try: # Store in Redis @@ -88,9 +83,7 @@ async def search( return result.get("results", []) except Exception as e: - logger.warning( - f"OPEA retrieval service unavailable, using direct Redis: {e}" - ) + logger.warning(f"OPEA retrieval service unavailable, using direct Redis: {e}") # Fallback to direct Redis search return await self._redis_search(query_embedding, top_k, filters) @@ -111,9 +104,7 @@ async def _redis_search( for doc_id in doc_ids: # Get document - doc_json = await client.get( - f"doc:{doc_id.decode() if isinstance(doc_id, bytes) else doc_id}" - ) + doc_json = await client.get(f"doc:{doc_id.decode() if isinstance(doc_id, bytes) else doc_id}") if doc_json: doc = json.loads(doc_json) doc_embedding = np.array(doc.get("embedding", [])) @@ -170,9 +161,7 @@ async def delete_document(self, doc_id: str) -> bool: logger.error(f"Error deleting document {doc_id}: {e}") return False - async def update_document( - self, doc_id: str, text: str, embedding: List[float], metadata: Dict[str, Any] - ) -> bool: + async def update_document(self, doc_id: str, text: str, embedding: List[float], metadata: Dict[str, Any]) -> bool: """Update an existing document.""" # Delete old version await self.delete_document(doc_id) @@ -194,9 +183,7 @@ async def get_document(self, doc_id: str) -> Optional[Dict[str, Any]]: logger.error(f"Error retrieving document {doc_id}: {e}") return None - async def get_all_documents( - self, limit: int = 100, offset: int = 0 - ) -> List[Dict[str, Any]]: + async def get_all_documents(self, limit: int = 100, offset: int = 0) -> List[Dict[str, Any]]: """Get all indexed documents.""" try: client = await self.get_redis_client() @@ -204,9 +191,7 @@ async def get_all_documents( documents = [] for i, doc_id in enumerate(list(doc_ids)[offset : offset + limit]): - doc = await self.get_document( - doc_id.decode() if isinstance(doc_id, bytes) else doc_id - ) + doc = await self.get_document(doc_id.decode() if isinstance(doc_id, bytes) else doc_id) if doc: documents.append(doc) @@ -233,9 +218,7 @@ async def clear_all_documents(self) -> bool: doc_ids = await client.smembers("document_ids") for doc_id in doc_ids: - await self.delete_document( - doc_id.decode() if isinstance(doc_id, bytes) else doc_id - ) + await self.delete_document(doc_id.decode() if isinstance(doc_id, bytes) else doc_id) logger.warning("Cleared all documents from vector store") return True diff --git a/CogniwareIms/backend/requirements.txt b/CogniwareIms/backend/requirements.txt index 052cbb82f9..176aca10b6 100644 --- a/CogniwareIms/backend/requirements.txt +++ b/CogniwareIms/backend/requirements.txt @@ -1,50 +1,39 @@ # Copyright (C) 2024 Intel Corporation # SPDX-License-Identifier: Apache-2.0 -# Web Framework -fastapi==0.115.0 -uvicorn[standard]==0.31.0 - -# Security - FIXED: Migrated from python-jose (CRITICAL CVE) to PyJWT -PyJWT>=2.9.0 # Replaced python-jose[cryptography]==3.3.0 -cryptography>=43.0.7 # FIXED: Updated from 43.0.1 (OpenSSL vulnerability) -bcrypt==4.2.0 -passlib[bcrypt]==1.7.4 # HTTP Client - FIXED: Updated aiohttp (memory leak and smuggling fixes) aiohttp>=3.11.0 # FIXED: Updated from 3.10.10 -httpx==0.27.2 -respx>=0.22.0 # Mocking library for httpx (replaces non-existent httpx-mock) - License: BSD-3-Clause - -# Form Data - FIXED: Updated python-multipart (DoS vulnerability) -python-multipart>=0.0.9 # FIXED: Updated from 0.0.12 - -# Database -psycopg2-binary==2.9.10 -sqlalchemy==2.0.35 alembic==1.13.3 +bcrypt==4.2.0 -# Redis & Caching -redis==5.2.0 +# Code Quality (dev dependencies) +black==24.10.0 +cryptography>=43.0.7 # FIXED: Updated from 43.0.1 (OpenSSL vulnerability) +email-validator==2.2.0 +# Web Framework +fastapi==0.115.0 +flake8==7.1.1 hiredis==3.0.0 - -# Data Processing - FIXED: Migrated from PyPDF2 to pypdf (infinite loop fix) -pypdf>=4.0.0 # Replaced PyPDF2==3.0.1 (License: BSD-3-Clause, verified) +httpx==0.27.2 +mypy==1.11.2 +numpy==2.1.2 openpyxl==3.1.5 -python-docx==1.1.2 pandas==2.2.3 -numpy==2.1.2 -scikit-learn==1.5.2 +passlib[bcrypt]==1.7.4 + +# Database +psycopg2-binary==2.9.10 # Validation pydantic==2.9.2 pydantic-settings==2.5.2 -email-validator==2.2.0 -# Utilities -python-dotenv==1.0.1 -python-json-logger==2.0.7 -PyYAML==6.0.2 +# Security - FIXED: Migrated from python-jose (CRITICAL CVE) to PyJWT +PyJWT>=2.9.0 # Replaced python-jose[cryptography]==3.3.0 + +# Data Processing - FIXED: Migrated from PyPDF2 to pypdf (infinite loop fix) +pypdf>=4.0.0 # Replaced PyPDF2==3.0.1 (License: BSD-3-Clause, verified) # Logging & Monitoring # (using standard library and python-json-logger) @@ -53,8 +42,19 @@ PyYAML==6.0.2 pytest==8.3.3 pytest-asyncio==0.24.0 pytest-cov==6.0.0 +python-docx==1.1.2 -# Code Quality (dev dependencies) -black==24.10.0 -flake8==7.1.1 -mypy==1.11.2 +# Utilities +python-dotenv==1.0.1 +python-json-logger==2.0.7 + +# Form Data - FIXED: Updated python-multipart (DoS vulnerability) +python-multipart>=0.0.9 # FIXED: Updated from 0.0.12 +PyYAML==6.0.2 + +# Redis & Caching +redis==5.2.0 +respx>=0.22.0 # Mocking library for httpx (replaces non-existent httpx-mock) - License: BSD-3-Clause +scikit-learn==1.5.2 +sqlalchemy==2.0.35 +uvicorn[standard]==0.31.0 diff --git a/CogniwareIms/cogniwareims.py b/CogniwareIms/cogniwareims.py index b4c810618e..46954be657 100644 --- a/CogniwareIms/cogniwareims.py +++ b/CogniwareIms/cogniwareims.py @@ -84,9 +84,7 @@ def add_remote_service(self): ) # Add services to megaservice - self.megaservice.add(embedding_service).add(retriever_service).add( - rerank_service - ).add(llm_service) + self.megaservice.add(embedding_service).add(retriever_service).add(rerank_service).add(llm_service) self.megaservice.add(dataprep_service) # Define service flow for RAG pipeline @@ -96,9 +94,7 @@ def add_remote_service(self): self.megaservice.flow_to(rerank_service, llm_service) -def align_inputs( - self, inputs: dict, cur_node: MicroService, runtime_graph: dict -) -> dict: +def align_inputs(self, inputs: dict, cur_node: MicroService, runtime_graph: dict) -> dict: """Align input format for different microservices. Args: @@ -156,9 +152,7 @@ async def cogniwareims_endpoint(request: Request): chat_request = ChatCompletionRequest(**data) # Process through megaservice pipeline - result = await cogniwareims_service.megaservice.schedule( - initial_inputs={"messages": chat_request.messages} - ) + result = await cogniwareims_service.megaservice.schedule(initial_inputs={"messages": chat_request.messages}) return result diff --git a/CogniwareIms/docker_compose/intel/cpu/xeon/set_env.sh b/CogniwareIms/docker_compose/intel/cpu/xeon/set_env.sh index b5ea6ae39f..9d896078fe 100644 --- a/CogniwareIms/docker_compose/intel/cpu/xeon/set_env.sh +++ b/CogniwareIms/docker_compose/intel/cpu/xeon/set_env.sh @@ -21,4 +21,3 @@ export https_proxy=${https_proxy:-""} export no_proxy=${no_proxy:-"localhost,127.0.0.1"} echo "Environment variables set for Cogniware IMS deployment on Intel Xeon" - diff --git a/CogniwareIms/frontend/Dockerfile b/CogniwareIms/frontend/Dockerfile index abdbb1e8b9..152cee0408 100644 --- a/CogniwareIms/frontend/Dockerfile +++ b/CogniwareIms/frontend/Dockerfile @@ -1,3 +1,6 @@ +# Copyright (C) 2026 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + # Multi-stage build for Next.js production optimization FROM node:18-alpine AS base diff --git a/CogniwareIms/frontend/app/globals.css b/CogniwareIms/frontend/app/globals.css index a0958fed19..0827df32ce 100644 --- a/CogniwareIms/frontend/app/globals.css +++ b/CogniwareIms/frontend/app/globals.css @@ -66,4 +66,3 @@ ::-webkit-scrollbar-thumb:hover { background: #555; } - diff --git a/CogniwareIms/frontend/next.config.js b/CogniwareIms/frontend/next.config.js index 71e6dbdeae..a7ea05ffef 100644 --- a/CogniwareIms/frontend/next.config.js +++ b/CogniwareIms/frontend/next.config.js @@ -45,8 +45,7 @@ const nextConfig = { // Environment variables env: { - NEXT_PUBLIC_API_URL: - process.env.NEXT_PUBLIC_API_URL || "http://localhost:8000", + NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL || "http://localhost:8000", NEXT_PUBLIC_WS_URL: process.env.NEXT_PUBLIC_WS_URL || "ws://localhost:8000", }, diff --git a/CogniwareIms/kubernetes/helm/Chart.yaml b/CogniwareIms/kubernetes/helm/Chart.yaml index 0fc140151a..3c089333ba 100644 --- a/CogniwareIms/kubernetes/helm/Chart.yaml +++ b/CogniwareIms/kubernetes/helm/Chart.yaml @@ -1,3 +1,6 @@ +# Copyright (C) 2026 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + apiVersion: v2 name: cogniwareims description: OPEA Cogniware IMS - AI-powered Inventory Management System built with Cogn DREAM diff --git a/CogniwareIms/tests/test_compose_on_xeon.sh b/CogniwareIms/tests/test_compose_on_xeon.sh index a873c3c4f0..809a55e7a4 100644 --- a/CogniwareIms/tests/test_compose_on_xeon.sh +++ b/CogniwareIms/tests/test_compose_on_xeon.sh @@ -70,7 +70,7 @@ wait_for_service() { local service_name=$2 local max_attempts=${3:-30} local attempt=0 - + echo "Waiting for $service_name..." while [ $attempt -lt $max_attempts ]; do if curl -s -f "$url" > /dev/null 2>&1; then @@ -81,7 +81,7 @@ wait_for_service() { echo "Waiting for $service_name... (attempt $attempt/$max_attempts)" sleep 10 done - + echo "ERROR: $service_name failed to become ready after $((max_attempts * 10)) seconds" return 1 } @@ -97,7 +97,7 @@ function build_docker_images() { echo "ERROR: docker_image_build directory not found" exit 1 fi - + cd "$build_dir" echo "Building from: $(pwd)" echo "Verifying build context..." @@ -136,7 +136,7 @@ function start_services() { fi exit 1 fi - + echo "Changing to compose directory: $compose_dir" cd "$compose_dir" || { echo "ERROR: Failed to cd to $compose_dir" @@ -157,7 +157,7 @@ function start_services() { # Wait for services to be ready echo "Waiting for services to initialize..." sleep 90 - + # Check if containers are running echo "Checking container status..." docker compose ps @@ -181,7 +181,7 @@ function validate_services() { echo "Waiting for Redis container... (attempt $attempt/$max_attempts)" sleep 5 done - + if [ $attempt -eq $max_attempts ]; then echo "ERROR: Redis failed to become ready" docker logs redis-vector-db || true @@ -203,7 +203,7 @@ function validate_services() { echo "Waiting for PostgreSQL container... (attempt $attempt/$max_attempts)" sleep 5 done - + if [ $attempt -eq $max_attempts ]; then echo "ERROR: PostgreSQL failed to become ready" docker logs postgres-db || true @@ -246,14 +246,14 @@ function validate_backend() { "session_id": "test_session", "user_role": "Inventory Manager" }' || echo "") - + if [ -z "$response" ]; then echo "Empty response from chat endpoint (attempt $((attempt + 1))/$max_attempts)" attempt=$((attempt + 1)) sleep 5 continue fi - + if echo "$response" | grep -qi "error"; then echo "Chat test failed!" echo "Response: $response" @@ -299,7 +299,7 @@ function stop_services() { } return fi - + if [ -n "$compose_dir" ]; then cd "$compose_dir" || { echo "Warning: Failed to cd to $compose_dir, attempting cleanup from current directory" @@ -330,4 +330,3 @@ function main() { } main - diff --git a/CogniwareIms/tests/test_gmc_on_xeon.sh b/CogniwareIms/tests/test_gmc_on_xeon.sh index 1aba986b04..1bce32dc04 100644 --- a/CogniwareIms/tests/test_gmc_on_xeon.sh +++ b/CogniwareIms/tests/test_gmc_on_xeon.sh @@ -96,4 +96,3 @@ function main() { } main -