From a65c8ab402959513fc7a714ef32e7e3188480c95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Fri, 14 Nov 2025 11:03:06 +0800 Subject: [PATCH 01/17] test --- .github/workflows/deploy.yml | 99 ------------------------------ .github/workflows/deploy_pages.yml | 49 +++++++++++++++ 2 files changed, 49 insertions(+), 99 deletions(-) delete mode 100644 .github/workflows/deploy.yml create mode 100644 .github/workflows/deploy_pages.yml diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml deleted file mode 100644 index d56e284..0000000 --- a/.github/workflows/deploy.yml +++ /dev/null @@ -1,99 +0,0 @@ -name: Deploy to GitHub Pages - -on: - push: - branches: - - main - workflow_dispatch: - -permissions: - contents: read - pages: write - id-token: write - -concurrency: - group: "pages" - cancel-in-progress: false - -jobs: - build: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '20' - - - name: Clean cache - run: | - cd docs/website - rm -rf .docusaurus node_modules/.cache build || true - - - name: Sync documentation files - run: | - # Delete all files in docs/website/docs directory - echo "Cleaning docs/website/docs directory..." - rm -rf docs/website/docs/* - find docs/website/docs -mindepth 1 -maxdepth 1 ! -name '.git' -exec rm -rf {} + 2>/dev/null || true - - # Copy all files from docs/ to docs/website/docs/ (excluding website folder) - echo "Copying documentation files from docs/ to docs/website/docs/..." - cd docs - for item in */; do - if [ "$item" != "website/" ]; then - dirname="${item%/}" # Remove trailing slash - echo " Copying directory: $dirname" - cp -r "$dirname" website/docs/ - fi - done - - # Copy any files directly in docs/ (not in subdirectories) - for file in *; do - if [ -f "$file" ] && [ "$file" != "website" ]; then - echo " Copying file: $file" - cp "$file" website/docs/ - fi - done - - cd .. - - # List copied files for verification - echo "" - echo "Copied documentation files:" - ls -la docs/website/docs/ - echo "" - echo "Verifying copied directories:" - find docs/website/docs -type d -maxdepth 1 | sort - - - name: Install dependencies - run: | - cd docs/website - npm ci --prefer-offline=false - - - name: Build - run: | - cd docs/website - npm run build - - - name: Setup Pages - uses: actions/configure-pages@v4 - - - name: Upload artifact - uses: actions/upload-pages-artifact@v3 - with: - path: docs/website/build - - deploy: - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - runs-on: ubuntu-latest - needs: build - steps: - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v4 - diff --git a/.github/workflows/deploy_pages.yml b/.github/workflows/deploy_pages.yml new file mode 100644 index 0000000..549afe8 --- /dev/null +++ b/.github/workflows/deploy_pages.yml @@ -0,0 +1,49 @@ +# Simple workflow for deploying static content to GitHub Pages +name: Deploy static content to Pages + +on: + # Runs on pushes targeting the default branch + push: + branches: ["main"] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + # Single deploy job since we're just deploying + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + - name: Deploy frontend + run: bash scripts/deploy-frontend.sh + - name: Setup Pages + uses: actions/configure-pages@v5 + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + # Upload entire repository + path: 'docs/website/build' + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 From 7b6328ad59ebecc2b82c1c755be87db47e0db3b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Fri, 14 Nov 2025 11:16:14 +0800 Subject: [PATCH 02/17] update --- scripts/deploy-frontend.sh | 7 ------- 1 file changed, 7 deletions(-) diff --git a/scripts/deploy-frontend.sh b/scripts/deploy-frontend.sh index 23e5f6b..e03717c 100755 --- a/scripts/deploy-frontend.sh +++ b/scripts/deploy-frontend.sh @@ -61,13 +61,6 @@ for item in */; do fi done -# Copy any files directly in docs/ (not in subdirectories) -for file in *; do - if [ -f "$file" ] && [ "$file" != "website" ]; then - echo " Copying file: $file" - cp "$file" website/docs/ - fi -done cd "$PROJECT_ROOT" From 0a2e22e937d02af13c25d5f4adcc65d24dac9702 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Fri, 14 Nov 2025 11:20:07 +0800 Subject: [PATCH 03/17] 1 --- scripts/deploy-frontend.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/deploy-frontend.sh b/scripts/deploy-frontend.sh index e03717c..2ca276d 100755 --- a/scripts/deploy-frontend.sh +++ b/scripts/deploy-frontend.sh @@ -57,6 +57,7 @@ for item in */; do if [ "$item" != "website/" ]; then dirname="${item%/}" # Remove trailing slash echo " Copying directory: $dirname" + echo "cp -r $dirname website/docs/" cp -r "$dirname" website/docs/ fi done From f210ed8f8fe1245a186c1e4bba38554ecb7619ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Fri, 14 Nov 2025 11:24:27 +0800 Subject: [PATCH 04/17] 1 --- scripts/deploy-frontend.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/deploy-frontend.sh b/scripts/deploy-frontend.sh index 2ca276d..59e4b58 100755 --- a/scripts/deploy-frontend.sh +++ b/scripts/deploy-frontend.sh @@ -61,6 +61,7 @@ for item in */; do cp -r "$dirname" website/docs/ fi done +tree website/docs/ cd "$PROJECT_ROOT" From 85bf6dc6d4e09a666b8c2fd3ea12da4e1d77222d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Fri, 14 Nov 2025 11:30:05 +0800 Subject: [PATCH 05/17] 1 --- scripts/deploy-frontend.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/deploy-frontend.sh b/scripts/deploy-frontend.sh index 59e4b58..145e5a9 100755 --- a/scripts/deploy-frontend.sh +++ b/scripts/deploy-frontend.sh @@ -50,14 +50,14 @@ echo " Cleaning docs/website/docs directory..." rm -rf docs/website/docs/* find docs/website/docs -mindepth 1 -maxdepth 1 ! -name '.git' -exec rm -rf {} + 2>/dev/null || true -# Copy all files from docs/ to docs/website/docs/ (excluding website folder) +# Copy all files from docs/ to docs/website/docs/ (excluding website and images folders) echo " Copying documentation files from docs/ to docs/website/docs/..." cd docs -for item in */; do - if [ "$item" != "website/" ]; then - dirname="${item%/}" # Remove trailing slash +# List all directories and copy them (excluding website and images folders) +for dirname in $(ls -d */ 2>/dev/null | grep -vE "^(website|images)/$"); do + dirname="${dirname%/}" # Remove trailing slash + if [ -d "$dirname" ]; then echo " Copying directory: $dirname" - echo "cp -r $dirname website/docs/" cp -r "$dirname" website/docs/ fi done From ecc4403137066f1826c220416056457872983fd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Fri, 14 Nov 2025 11:33:28 +0800 Subject: [PATCH 06/17] 1 --- scripts/deploy-frontend.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/deploy-frontend.sh b/scripts/deploy-frontend.sh index 145e5a9..1271b7c 100755 --- a/scripts/deploy-frontend.sh +++ b/scripts/deploy-frontend.sh @@ -54,14 +54,15 @@ find docs/website/docs -mindepth 1 -maxdepth 1 ! -name '.git' -exec rm -rf {} + echo " Copying documentation files from docs/ to docs/website/docs/..." cd docs # List all directories and copy them (excluding website and images folders) -for dirname in $(ls -d */ 2>/dev/null | grep -vE "^(website|images)/$"); do +for dirname in $(ls -d */ 2>/dev/null | grep -vE "^(website|images|api)/$"); do dirname="${dirname%/}" # Remove trailing slash + echo "dirname: $dirname" if [ -d "$dirname" ]; then echo " Copying directory: $dirname" cp -r "$dirname" website/docs/ fi done -tree website/docs/ +cp -r api/* website/docs/api/ cd "$PROJECT_ROOT" From 4ecae8f7481b1fdbacb2a4439dbdf0a88f7a7943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Fri, 14 Nov 2025 11:34:55 +0800 Subject: [PATCH 07/17] 1 --- scripts/deploy-frontend.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/deploy-frontend.sh b/scripts/deploy-frontend.sh index 1271b7c..6310fc7 100755 --- a/scripts/deploy-frontend.sh +++ b/scripts/deploy-frontend.sh @@ -62,6 +62,7 @@ for dirname in $(ls -d */ 2>/dev/null | grep -vE "^(website|images|api)/$"); do cp -r "$dirname" website/docs/ fi done +mkdir -p website/docs/api/ cp -r api/* website/docs/api/ From 44297985325d8af43b1c557b06f40fdf380f0930 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Fri, 14 Nov 2025 11:36:37 +0800 Subject: [PATCH 08/17] 1 --- scripts/deploy-frontend.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/deploy-frontend.sh b/scripts/deploy-frontend.sh index 6310fc7..a221745 100755 --- a/scripts/deploy-frontend.sh +++ b/scripts/deploy-frontend.sh @@ -54,7 +54,7 @@ find docs/website/docs -mindepth 1 -maxdepth 1 ! -name '.git' -exec rm -rf {} + echo " Copying documentation files from docs/ to docs/website/docs/..." cd docs # List all directories and copy them (excluding website and images folders) -for dirname in $(ls -d */ 2>/dev/null | grep -vE "^(website|images|api)/$"); do +for dirname in $(ls -d */ 2>/dev/null | grep -vE "^(website|images)/$"); do dirname="${dirname%/}" # Remove trailing slash echo "dirname: $dirname" if [ -d "$dirname" ]; then @@ -62,6 +62,7 @@ for dirname in $(ls -d */ 2>/dev/null | grep -vE "^(website|images|api)/$"); do cp -r "$dirname" website/docs/ fi done +rm -rf website/docs/*.md mkdir -p website/docs/api/ cp -r api/* website/docs/api/ From a6fc072de7b5595dccdf42758426dc87eb1f7972 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Fri, 14 Nov 2025 12:13:28 +0800 Subject: [PATCH 09/17] update --- .../theme/NavbarItem/DefaultNavbarItem/Desktop/index.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/website/src/theme/NavbarItem/DefaultNavbarItem/Desktop/index.tsx b/docs/website/src/theme/NavbarItem/DefaultNavbarItem/Desktop/index.tsx index e9b20b1..189dcf2 100644 --- a/docs/website/src/theme/NavbarItem/DefaultNavbarItem/Desktop/index.tsx +++ b/docs/website/src/theme/NavbarItem/DefaultNavbarItem/Desktop/index.tsx @@ -9,10 +9,10 @@ function useGitHubStars() { const [stars, setStars] = useState(null); useEffect(() => { - fetch('https://api.github.com/repos/oceanbase/oceanbase') + fetch('https://api.github.com/repos/oceanbase/powermem') .then((res) => res.json()) .then((data) => { - if (data.stargazers_count && data.stargazers_count > 0) { + if (data.stargazers_count && data.stargazers_count > 1000) { setStars(data.stargazers_count); } }) @@ -47,7 +47,7 @@ export default function DefaultNavbarItemDesktop({ isDropdownItem ? 'dropdown__link' : 'navbar__item navbar__link', className, styles.iconNavbarLink, - isGitHub && stars && stars > 0 && styles.iconNavbarLinkWithStars + isGitHub && stars && stars > 100 && styles.iconNavbarLinkWithStars ) : clsx( isDropdownItem ? 'dropdown__link' : 'navbar__item navbar__link', @@ -80,7 +80,7 @@ export default function DefaultNavbarItemDesktop({ clipRule="evenodd" /> - {stars !== null && stars > 0 && ( + {stars !== null && stars > 100 && ( {stars.toLocaleString()} From 4cd798ebd954634da2c33bcb1a610e187d59c8de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Fri, 14 Nov 2025 12:18:42 +0800 Subject: [PATCH 10/17] 1 --- docs/website/src/components/Hero/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/website/src/components/Hero/index.tsx b/docs/website/src/components/Hero/index.tsx index b9eedd5..533a83b 100644 --- a/docs/website/src/components/Hero/index.tsx +++ b/docs/website/src/components/Hero/index.tsx @@ -15,7 +15,7 @@ function useGitHubStars() { fetch('https://api.github.com/repos/oceanbase/powermem') .then((res) => res.json()) .then((data) => { - if (data.stargazers_count) { + if (data.stargazers_count && data.stargazers_count > 1000) { setStars(data.stargazers_count); } }) @@ -111,7 +111,7 @@ memories = memory.search("user preferences", user_id="user123")`; > {isZh ? '查看代码' : 'View Code'} - {stars !== null && ( + {stars !== null && stars > 1000 && ( ⭐ {stars.toLocaleString()} From e1590a290acb01f67c4918885f2386c9373fbba2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Sat, 15 Nov 2025 13:27:56 +0800 Subject: [PATCH 11/17] update website --- docs/website/docusaurus.config.ts | 2 +- .../en/docusaurus-theme-classic/footer.json | 2 +- .../Features/icons/DeveloperIcon.tsx | 36 ++ .../Features/icons/MultimodalIcon.tsx | 52 +++ .../website/src/components/Features/index.tsx | 92 +++-- .../src/components/Features/styles.module.css | 365 ++++++++++++++++-- 6 files changed, 494 insertions(+), 55 deletions(-) create mode 100644 docs/website/src/components/Features/icons/DeveloperIcon.tsx create mode 100644 docs/website/src/components/Features/icons/MultimodalIcon.tsx diff --git a/docs/website/docusaurus.config.ts b/docs/website/docusaurus.config.ts index 78f2274..af85a05 100644 --- a/docs/website/docusaurus.config.ts +++ b/docs/website/docusaurus.config.ts @@ -168,7 +168,7 @@ const config: Config = { ], }, ], - copyright: `Copyright © ${new Date().getFullYear()} OceanBase. Built with Docusaurus.`, + copyright: `Copyright © ${new Date().getFullYear()} OceanBase.`, }, prism: { theme: prismThemes.github, diff --git a/docs/website/i18n/en/docusaurus-theme-classic/footer.json b/docs/website/i18n/en/docusaurus-theme-classic/footer.json index 2033a35..1bae8ed 100644 --- a/docs/website/i18n/en/docusaurus-theme-classic/footer.json +++ b/docs/website/i18n/en/docusaurus-theme-classic/footer.json @@ -48,7 +48,7 @@ "description": "The label of footer link with label=Community linking to /community" }, "copyright": { - "message": "Copyright © 2025 OceanBase. Built with Docusaurus.", + "message": "Copyright © 2025 OceanBase.", "description": "The footer copyright" } } diff --git a/docs/website/src/components/Features/icons/DeveloperIcon.tsx b/docs/website/src/components/Features/icons/DeveloperIcon.tsx new file mode 100644 index 0000000..0915e8e --- /dev/null +++ b/docs/website/src/components/Features/icons/DeveloperIcon.tsx @@ -0,0 +1,36 @@ +import React from 'react'; + +export default function DeveloperIcon({ className }: { className?: string }) { + return ( + + + + + + + ); +} + diff --git a/docs/website/src/components/Features/icons/MultimodalIcon.tsx b/docs/website/src/components/Features/icons/MultimodalIcon.tsx new file mode 100644 index 0000000..476c16d --- /dev/null +++ b/docs/website/src/components/Features/icons/MultimodalIcon.tsx @@ -0,0 +1,52 @@ +import React from 'react'; + +export default function MultimodalIcon({ className }: { className?: string }) { + return ( + + + + + + + + ); +} + diff --git a/docs/website/src/components/Features/index.tsx b/docs/website/src/components/Features/index.tsx index 79c72d1..b8f6a72 100644 --- a/docs/website/src/components/Features/index.tsx +++ b/docs/website/src/components/Features/index.tsx @@ -1,12 +1,22 @@ import React from 'react'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; import Heading from '@theme/Heading'; +import DeveloperIcon from './icons/DeveloperIcon'; import BrainIcon from './icons/BrainIcon'; import UsersIcon from './icons/UsersIcon'; +import MultimodalIcon from './icons/MultimodalIcon'; import DatabaseIcon from './icons/DatabaseIcon'; import styles from './styles.module.css'; const features = [ + { + icon: DeveloperIcon, + key: 'developer', + details: [ + 'detail1', + ], + color: 'from-orange-500 to-orange-600', + }, { icon: BrainIcon, key: 'intelligent', @@ -28,6 +38,14 @@ const features = [ ], color: 'from-purple-500 to-purple-600', }, + { + icon: MultimodalIcon, + key: 'multimodal', + details: [ + 'detail1', + ], + color: 'from-pink-500 to-pink-600', + }, { icon: DatabaseIcon, key: 'storage', @@ -44,48 +62,64 @@ const translations: Record> = { en: { 'features.title': 'Core Features', 'features.subtitle': 'Complete intelligent memory management solution for AI applications', - 'feature.intelligent.title': 'Intelligent Memory', + 'feature.developer.title': 'Developer Friendly', + 'feature.developer.en': 'Developer Friendly', + 'feature.developer.desc': 'Provides a simple Python SDK, automatically loads configuration from .env files, enabling developers to quickly integrate into existing projects', + 'feature.developer.detail1': 'Lightweight Integration', + 'feature.intelligent.title': 'Intelligent Memory Management', 'feature.intelligent.en': 'Intelligent Memory Management', - 'feature.intelligent.desc': 'Smart memory optimization based on Ebbinghaus forgetting curve, automatic importance scoring and context-aware retrieval', - 'feature.intelligent.detail1': 'Ebbinghaus Forgetting Curve Algorithm', - 'feature.intelligent.detail2': 'Automatic Importance Scoring', - 'feature.intelligent.detail3': 'Intelligent Memory Retrieval', + 'feature.intelligent.desc': 'Automatically extracts key facts from conversations through LLM, intelligently detects duplicates, updates conflicting information, and merges related memories. Based on cognitive science, implements time-decay weighting to prioritize recent and relevant memories.', + 'feature.intelligent.detail1': 'Intelligent Memory Extraction', + 'feature.intelligent.detail2': 'Ebbinghaus Forgetting Curve', + 'feature.intelligent.detail3': 'Automatic Duplicate Detection', 'feature.multiAgent.title': 'Multi-Agent Support', 'feature.multiAgent.en': 'Multi-Agent Support', - 'feature.multiAgent.desc': 'Independent agent memory spaces, cross-agent collaboration, permission control and privacy protection', - 'feature.multiAgent.detail1': 'Agent Isolation', + 'feature.multiAgent.desc': 'Provides independent memory spaces for each agent, supports cross-agent memory sharing and collaboration, and enables flexible permission management through scope control', + 'feature.multiAgent.detail1': 'Agent Shared/Isolated Memory', 'feature.multiAgent.detail2': 'Cross-Agent Collaboration', - 'feature.multiAgent.detail3': 'Permission Control', - 'feature.multiAgent.detail4': 'Privacy Protection', - 'feature.storage.title': 'Storage Backends', - 'feature.storage.en': 'Storage Backends', - 'feature.storage.desc': 'Support for OceanBase, PostgreSQL and other enterprise-grade storage with extensible architecture', - 'feature.storage.detail1': 'OceanBase (Default)', - 'feature.storage.detail2': 'PostgreSQL', - 'feature.storage.detail3': 'Extensible Architecture', + 'feature.multiAgent.detail3': 'Flexible Permission Management', + 'feature.multiAgent.detail4': 'Scope Control', + 'feature.multimodal.title': 'Multimodal Support', + 'feature.multimodal.en': 'Multimodal Support', + 'feature.multimodal.desc': 'Automatically converts images and audio to text descriptions for storage, supports retrieval of multimodal mixed content (text + image + audio), enabling AI systems to understand richer contextual information', + 'feature.multimodal.detail1': 'Text, Image, and Audio Memory', + 'feature.storage.title': 'Deeply Optimized Data Storage', + 'feature.storage.en': 'Deeply Optimized Data Storage', + 'feature.storage.desc': 'Implements data partition management through sub stores with automatic query routing. Combines multi-channel recall capabilities of vector retrieval, full-text search, and graph retrieval for precise retrieval of complex memory relationships.', + 'feature.storage.detail1': 'Sub Stores Support', + 'feature.storage.detail2': 'Hybrid Retrieval', + 'feature.storage.detail3': 'Multi-Hop Graph Traversal', }, zh: { 'features.title': '核心特性', 'features.subtitle': '为 AI 应用提供完整的智能内存管理解决方案', + 'feature.developer.title': '开发者友好', + 'feature.developer.en': 'Developer Friendly', + 'feature.developer.desc': '提供简单的 Python SDK,自动从 .env 文件加载配置,使开发者能够快速集成到现有项目中', + 'feature.developer.detail1': '轻量级集成', 'feature.intelligent.title': '智能内存管理', 'feature.intelligent.en': 'Intelligent Memory Management', - 'feature.intelligent.desc': '基于艾宾浩斯遗忘曲线的智能记忆优化,自动重要性评分和上下文感知检索', - 'feature.intelligent.detail1': '艾宾浩斯遗忘曲线算法', - 'feature.intelligent.detail2': '自动重要性评分', - 'feature.intelligent.detail3': '智能记忆检索', + 'feature.intelligent.desc': '通过 LLM 自动从对话中提取关键事实,智能检测重复、更新冲突信息并合并相关记忆。基于认知科学,实现时间衰减加权,优先考虑最近和相关的记忆。', + 'feature.intelligent.detail1': '智能记忆提取', + 'feature.intelligent.detail2': '艾宾浩斯遗忘曲线', + 'feature.intelligent.detail3': '自动重复检测', 'feature.multiAgent.title': '多Agent支持', 'feature.multiAgent.en': 'Multi-Agent Support', - 'feature.multiAgent.desc': '独立的代理记忆空间,支持跨代理协作、权限控制和隐私保护', - 'feature.multiAgent.detail1': '代理隔离', + 'feature.multiAgent.desc': '为每个代理提供独立的记忆空间,支持跨代理记忆共享和协作,并通过范围控制实现灵活的权限管理', + 'feature.multiAgent.detail1': '代理共享/隔离记忆', 'feature.multiAgent.detail2': '跨代理协作', - 'feature.multiAgent.detail3': '权限控制', - 'feature.multiAgent.detail4': '隐私保护', - 'feature.storage.title': '多种存储后端', - 'feature.storage.en': 'Storage Backends', - 'feature.storage.desc': '支持 OceanBase、PostgreSQL 等企业级存储,可扩展架构适配各种场景', - 'feature.storage.detail1': 'OceanBase(默认)', - 'feature.storage.detail2': 'PostgreSQL', - 'feature.storage.detail3': '可扩展架构', + 'feature.multiAgent.detail3': '灵活权限管理', + 'feature.multiAgent.detail4': '范围控制', + 'feature.multimodal.title': '多模态支持', + 'feature.multimodal.en': 'Multimodal Support', + 'feature.multimodal.desc': '自动将图像和音频转换为文本描述进行存储,支持检索多模态混合内容(文本 + 图像 + 音频),使 AI 系统能够理解更丰富的上下文信息', + 'feature.multimodal.detail1': '文本、图像和音频记忆', + 'feature.storage.title': '深度优化的数据存储', + 'feature.storage.en': 'Deeply Optimized Data Storage', + 'feature.storage.desc': '通过子存储实现数据分区管理,支持自动查询路由。结合向量检索、全文搜索和图检索的多通道召回能力,精确检索复杂的记忆关系。', + 'feature.storage.detail1': '子存储支持', + 'feature.storage.detail2': '混合检索', + 'feature.storage.detail3': '多跳图遍历', }, }; diff --git a/docs/website/src/components/Features/styles.module.css b/docs/website/src/components/Features/styles.module.css index 364f56a..abefb47 100644 --- a/docs/website/src/components/Features/styles.module.css +++ b/docs/website/src/components/Features/styles.module.css @@ -47,13 +47,43 @@ .card { background: rgba(17, 17, 17, 0.9); - border-radius: 12px; + border-radius: 16px; padding: 2rem; border: 1px solid rgba(59, 130, 246, 0.2); - transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); + transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1); position: relative; overflow: hidden; backdrop-filter: blur(10px); + opacity: 0; + transform: translateY(30px); + animation: cardFadeIn 0.8s cubic-bezier(0.4, 0, 0.2, 1) forwards; +} + +.card:nth-child(1) { + animation-delay: 0.1s; +} + +.card:nth-child(2) { + animation-delay: 0.2s; +} + +.card:nth-child(3) { + animation-delay: 0.3s; +} + +.card:nth-child(4) { + animation-delay: 0.4s; +} + +.card:nth-child(5) { + animation-delay: 0.5s; +} + +@keyframes cardFadeIn { + to { + opacity: 1; + transform: translateY(0); + } } .card::before { @@ -63,17 +93,22 @@ background: linear-gradient(135deg, rgba(59, 130, 246, 0.1), rgba(147, 51, 234, 0.1)); opacity: 0; transition: opacity 0.5s ease; + z-index: 0; } .card::after { content: ''; position: absolute; - top: 0; - left: -100%; - width: 100%; - height: 100%; - background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.05), transparent); - transition: left 0.5s ease; + top: -50%; + left: -50%; + width: 200%; + height: 200%; + background: radial-gradient(circle, rgba(255, 255, 255, 0.1) 0%, transparent 70%); + opacity: 0; + transition: opacity 0.6s ease, transform 0.6s ease; + transform: scale(0); + pointer-events: none; + z-index: 0; } .card:hover::before { @@ -81,42 +116,105 @@ } .card:hover::after { - left: 100%; + opacity: 1; + transform: scale(1); } .card:hover { - transform: translateY(-8px) scale(1.02); + transform: translateY(-12px) scale(1.03) rotateX(2deg); + box-shadow: + 0 25px 50px rgba(0, 0, 0, 0.8), + 0 0 60px rgba(59, 130, 246, 0.5), + 0 0 100px rgba(147, 51, 234, 0.3), + inset 0 0 30px rgba(59, 130, 246, 0.1); + border-color: rgba(59, 130, 246, 0.8); + border-width: 2px; +} + +/* Glow effect on border */ +.card::before { + border-radius: 16px; +} + +.card:hover::before { box-shadow: - 0 20px 40px rgba(0, 0, 0, 0.6), - 0 0 40px rgba(59, 130, 246, 0.4), - 0 0 80px rgba(147, 51, 234, 0.2); - border-color: rgba(59, 130, 246, 0.6); + 0 0 20px rgba(59, 130, 246, 0.4), + inset 0 0 20px rgba(59, 130, 246, 0.1); } .icon { width: 4rem; height: 4rem; - border-radius: 12px; + border-radius: 14px; display: flex; align-items: center; justify-content: center; margin-bottom: 1rem; - transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); + transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1); position: relative; z-index: 1; - overflow: hidden; + overflow: visible; + animation: iconPulse 3s ease-in-out infinite; +} + +@keyframes iconPulse { + 0%, 100% { + transform: scale(1); + filter: brightness(1); + } + 50% { + transform: scale(1.05); + filter: brightness(1.2); + } } .icon::before { + content: ''; + position: absolute; + inset: -4px; + border-radius: 16px; + background: inherit; + opacity: 0.3; + filter: blur(12px); + transition: all 0.5s ease; + z-index: -1; + animation: iconGlow 2s ease-in-out infinite; +} + +@keyframes iconGlow { + 0%, 100% { + opacity: 0.3; + transform: scale(1); + } + 50% { + opacity: 0.6; + transform: scale(1.1); + } +} + +.icon::after { content: ''; position: absolute; inset: 0; - background: linear-gradient(135deg, rgba(255, 255, 255, 0.1), transparent); + background: linear-gradient(135deg, rgba(255, 255, 255, 0.2), transparent); opacity: 0; - transition: opacity 0.3s ease; + transition: opacity 0.4s ease; + border-radius: 14px; + z-index: 1; +} + +.card:hover .icon { + transform: scale(1.15) rotateY(10deg) rotateX(-5deg); + animation: none; } .card:hover .icon::before { + opacity: 0.8; + transform: scale(1.3); + filter: blur(20px); +} + +.card:hover .icon::after { opacity: 1; } @@ -125,14 +223,104 @@ height: 2rem; color: white; filter: drop-shadow(0 0 10px currentColor); - transition: all 0.3s ease; - z-index: 1; + transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1); + z-index: 2; position: relative; + animation: iconFloat 3s ease-in-out infinite; +} + +@keyframes iconFloat { + 0%, 100% { + transform: translateY(0) rotate(0deg); + } + 50% { + transform: translateY(-5px) rotate(2deg); + } } .card:hover .iconSvg { - transform: scale(1.1) rotate(5deg); - filter: drop-shadow(0 0 20px currentColor); + transform: scale(1.2) rotate(15deg) translateY(-3px); + filter: drop-shadow(0 0 25px currentColor) drop-shadow(0 0 40px currentColor); + animation: iconSpin 0.6s ease-out; +} + +@keyframes iconSpin { + 0% { + transform: scale(1.2) rotate(0deg); + } + 50% { + transform: scale(1.3) rotate(180deg); + } + 100% { + transform: scale(1.2) rotate(15deg); + } +} + +.icon-intelligent { + background: linear-gradient(135deg, #3b82f6, #2563eb); + box-shadow: + 0 0 30px rgba(59, 130, 246, 0.5), + inset 0 0 20px rgba(59, 130, 246, 0.2); +} + +.card:hover .icon-intelligent { + box-shadow: + 0 0 50px rgba(59, 130, 246, 0.8), + inset 0 0 30px rgba(59, 130, 246, 0.3); +} + +.icon-multiAgent { + background: linear-gradient(135deg, #9333ea, #7e22ce); + box-shadow: + 0 0 30px rgba(147, 51, 234, 0.5), + inset 0 0 20px rgba(147, 51, 234, 0.2); +} + +.card:hover .icon-multiAgent { + box-shadow: + 0 0 50px rgba(147, 51, 234, 0.8), + inset 0 0 30px rgba(147, 51, 234, 0.3); +} + +.icon-developer { + background: linear-gradient(135deg, #f97316, #ea580c); + box-shadow: + 0 0 30px rgba(249, 115, 22, 0.5), + inset 0 0 20px rgba(249, 115, 22, 0.2); + animation: developerGlow 3s ease-in-out infinite; +} + +@keyframes developerGlow { + 0%, 100% { + box-shadow: + 0 0 30px rgba(249, 115, 22, 0.5), + inset 0 0 20px rgba(249, 115, 22, 0.2); + } + 50% { + box-shadow: + 0 0 40px rgba(249, 115, 22, 0.7), + inset 0 0 25px rgba(249, 115, 22, 0.3); + } +} + +.card:hover .icon-developer { + box-shadow: + 0 0 60px rgba(249, 115, 22, 1), + 0 0 100px rgba(249, 115, 22, 0.6), + inset 0 0 40px rgba(249, 115, 22, 0.4); + animation: developerPulse 0.6s ease-out; +} + +@keyframes developerPulse { + 0% { + transform: scale(1.15); + } + 50% { + transform: scale(1.25); + } + 100% { + transform: scale(1.15); + } } .icon-intelligent { @@ -161,6 +349,43 @@ inset 0 0 30px rgba(147, 51, 234, 0.3); } +.icon-multimodal { + background: linear-gradient(135deg, #ec4899, #db2777); + box-shadow: + 0 0 30px rgba(236, 72, 153, 0.5), + inset 0 0 20px rgba(236, 72, 153, 0.2); + animation: multimodalShimmer 4s ease-in-out infinite; +} + +@keyframes multimodalShimmer { + 0%, 100% { + background: linear-gradient(135deg, #ec4899, #db2777); + } + 50% { + background: linear-gradient(135deg, #f472b6, #ec4899); + } +} + +.card:hover .icon-multimodal { + box-shadow: + 0 0 60px rgba(236, 72, 153, 1), + 0 0 100px rgba(236, 72, 153, 0.6), + inset 0 0 40px rgba(236, 72, 153, 0.4); + animation: multimodalPulse 0.6s ease-out; +} + +@keyframes multimodalPulse { + 0% { + transform: scale(1.15); + } + 50% { + transform: scale(1.25); + } + 100% { + transform: scale(1.15); + } +} + .icon-storage { background: linear-gradient(135deg, #22c55e, #16a34a); box-shadow: @@ -181,6 +406,16 @@ margin-bottom: 0.5rem; position: relative; z-index: 1; + transition: all 0.4s ease; + text-shadow: 0 0 10px rgba(96, 165, 250, 0.3); +} + +.card:hover .cardTitle { + color: #ffffff; + text-shadow: + 0 0 20px rgba(96, 165, 250, 0.6), + 0 0 40px rgba(96, 165, 250, 0.3); + transform: translateX(4px); } .cardEn { @@ -189,6 +424,14 @@ margin-bottom: 0.75rem; position: relative; z-index: 1; + transition: all 0.4s ease; + letter-spacing: 0.5px; +} + +.card:hover .cardEn { + color: #d1d5db; + letter-spacing: 1px; + transform: translateX(2px); } .cardDesc { @@ -197,6 +440,12 @@ line-height: 1.6; position: relative; z-index: 1; + transition: all 0.4s ease; +} + +.card:hover .cardDesc { + color: #e5e7eb; + transform: translateX(2px); } .details { @@ -215,11 +464,47 @@ align-items: start; font-size: 0.875rem; color: #9ca3af; - transition: color 0.2s ease; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + opacity: 0.8; + transform: translateX(-10px); + animation: detailSlideIn 0.6s ease-out forwards; +} + +.details li:nth-child(1) { + animation-delay: 0.2s; +} + +.details li:nth-child(2) { + animation-delay: 0.3s; +} + +.details li:nth-child(3) { + animation-delay: 0.4s; +} + +.details li:nth-child(4) { + animation-delay: 0.5s; +} + +@keyframes detailSlideIn { + to { + opacity: 1; + transform: translateX(0); + } } .card:hover .details li { color: #d1d5db; + transform: translateX(6px); + opacity: 1; +} + +.card:hover .details li:nth-child(odd) { + transform: translateX(8px); +} + +.card:hover .details li:nth-child(even) { + transform: translateX(4px); } .bullet { @@ -228,6 +513,38 @@ flex-shrink: 0; font-weight: bold; text-shadow: 0 0 10px rgba(96, 165, 250, 0.5); + transition: all 0.3s ease; + display: inline-block; + animation: bulletPulse 2s ease-in-out infinite; +} + +@keyframes bulletPulse { + 0%, 100% { + opacity: 0.8; + transform: scale(1); + } + 50% { + opacity: 1; + transform: scale(1.2); + } +} + +.card:hover .bullet { + color: #93c5fd; + text-shadow: + 0 0 15px rgba(96, 165, 250, 0.8), + 0 0 30px rgba(96, 165, 250, 0.4); + transform: scale(1.3); + animation: bulletSpin 0.5s ease-out; +} + +@keyframes bulletSpin { + 0% { + transform: scale(1.3) rotate(0deg); + } + 100% { + transform: scale(1.3) rotate(360deg); + } } @media (max-width: 768px) { From 9d6183467e7ff9a720edc23e73eb49c88798686a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Mon, 19 Jan 2026 19:50:28 +0800 Subject: [PATCH 12/17] Feature (Docker): Manage database passwords using environment variables -Replace the hard coded password with the 'SEEKDB_ROOT PASSWORD' environment variable -Update health check commands to support optional passwords -Modify the document to explain the password management method --- docker/README.md | 74 ++++++++++++++++++++++++++++++++++--- docker/docker-compose.yml | 77 ++++++++++++++++++++++++++++++--------- 2 files changed, 128 insertions(+), 23 deletions(-) diff --git a/docker/README.md b/docker/README.md index c056cbd..27cf85d 100644 --- a/docker/README.md +++ b/docker/README.md @@ -5,7 +5,7 @@ This directory contains all Docker-related files for PowerMem Server. ## Files - `Dockerfile` - Multi-stage Docker build file for PowerMem Server -- `docker-compose.yml` - Docker Compose configuration file +- `docker-compose.yml` - Docker Compose configuration file with SeekDB support - `docker-entrypoint.sh` - Container entrypoint script - `.dockerignore` - Files to exclude from Docker build context - `DOCKER.md` - Complete Docker deployment documentation @@ -20,11 +20,19 @@ From the project root directory: docker build -t oceanbase/powermem-server:latest -f docker/Dockerfile . ``` -### Run with Docker Compose +### Run with Docker Compose (with SeekDB) From the project root directory: ```bash +# Without password (default) +docker-compose -f docker/docker-compose.yml up -d + +# With password (set via command line) +SEEKDB_ROOT_PASSWORD=your_password docker-compose -f docker/docker-compose.yml up -d + +# Alternatively, export the variable first +export SEEKDB_ROOT_PASSWORD=your_password docker-compose -f docker/docker-compose.yml up -d ``` @@ -36,11 +44,61 @@ From the project root directory: docker run -d \ --name powermem-server \ -p 8000:8000 \ - -v $(pwd)/.env:/app/.env:ro \ - --env-file .env \ oceanbase/powermem-server:latest ``` +## Services + +### PowerMem Server +- Port: 8000 +- Health check: `http://localhost:8000/api/v1/system/health` +- Database: Connected to SeekDB without password + +### SeekDB Database +- MySQL Port: 2881 +- Web Dashboard: 2886 +- Data persistence: Docker volume `seekdb_data` +- Default database: `powermem` +- Password: Controlled by `SEEKDB_ROOT_PASSWORD` environment variable + - Not set (default): No password + - Set via command line: Use specified password + +## Connecting to SeekDB + +### Without password (default) +```bash +mysql -h 127.0.0.1 -P 2881 -u root +``` + +### With password (if SEEKDB_ROOT_PASSWORD is set) +```bash +mysql -h 127.0.0.1 -P 2881 -u root -p +# Enter the password when prompted +``` + +### Web Dashboard +Open browser to: `http://localhost:2886` +- Username: `root` +- Password: Same as `SEEKDB_ROOT_PASSWORD` environment variable (not set by default) + +## Default Configuration + +The `docker-compose.yml` file includes default configuration values: + +**PowerMem Server:** +- Host: `0.0.0.0` +- Port: `8000` +- Workers: `4` +- Authentication: Disabled +- CORS: Enabled for all origins + +**SeekDB:** +- Password: Controlled by `SEEKDB_ROOT_PASSWORD` environment variable (not set by default) +- CPU: 4 cores +- Memory: 4GB +- Database: `powermem` +- Data persistence: Docker volume + ## Documentation For detailed documentation, see [DOCKER.md](./DOCKER.md). @@ -49,5 +107,9 @@ For detailed documentation, see [DOCKER.md](./DOCKER.md). - All Docker commands should be run from the **project root directory**, not from the `docker/` directory - The build context is the project root, so paths in Dockerfile are relative to the project root -- The `.env` file should be in the project root directory and will be mounted into the container - +- SeekDB data is persisted in a Docker volume named `seekdb_data` +- On macOS with Docker version > 4.9.0, there are known issues with SeekDB. Consider using an older Docker version if needed. +- **Password Management**: + - Default: No password (`SEEKDB_ROOT_PASSWORD` not set) + - To set a password: Use command line: `SEEKDB_ROOT_PASSWORD=your_password docker-compose -f docker/docker-compose.yml up -d` + - Password change: Stop services, set new password via command line, restart services \ No newline at end of file diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index a747772..e123547 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -8,26 +8,31 @@ services: image: oceanbase/powermem-server:latest container_name: powermem-server ports: - - "${POWERMEM_SERVER_PORT:-8000}:8000" + - "8000:8000" environment: - - POWERMEM_SERVER_HOST=${POWERMEM_SERVER_HOST:-0.0.0.0} - - POWERMEM_SERVER_PORT=${POWERMEM_SERVER_PORT:-8000} - - POWERMEM_SERVER_WORKERS=${POWERMEM_SERVER_WORKERS:-4} - - POWERMEM_SERVER_API_KEYS=${POWERMEM_SERVER_API_KEYS:-} - - POWERMEM_SERVER_AUTH_ENABLED=${POWERMEM_SERVER_AUTH_ENABLED:-false} - - POWERMEM_SERVER_RATE_LIMIT_ENABLED=${POWERMEM_SERVER_RATE_LIMIT_ENABLED:-true} - - POWERMEM_SERVER_RATE_LIMIT_PER_MINUTE=${POWERMEM_SERVER_RATE_LIMIT_PER_MINUTE:-100} - - POWERMEM_SERVER_LOG_LEVEL=${POWERMEM_SERVER_LOG_LEVEL:-INFO} - - POWERMEM_SERVER_LOG_FORMAT=${POWERMEM_SERVER_LOG_FORMAT:-json} - - POWERMEM_SERVER_CORS_ENABLED=${POWERMEM_SERVER_CORS_ENABLED:-true} - - POWERMEM_SERVER_CORS_ORIGINS=${POWERMEM_SERVER_CORS_ORIGINS:-*} - - POWERMEM_DATABASE_URL=${POWERMEM_DATABASE_URL:-} - env_file: - - .env + - POWERMEM_SERVER_HOST=0.0.0.0 + - POWERMEM_SERVER_PORT=8000 + - POWERMEM_SERVER_WORKERS=4 + - POWERMEM_SERVER_API_KEYS= + - POWERMEM_SERVER_AUTH_ENABLED=false + - POWERMEM_SERVER_RATE_LIMIT_ENABLED=true + - POWERMEM_SERVER_RATE_LIMIT_PER_MINUTE=100 + - POWERMEM_SERVER_LOG_LEVEL=INFO + - POWERMEM_SERVER_LOG_FORMAT=json + - POWERMEM_SERVER_CORS_ENABLED=true + - POWERMEM_SERVER_CORS_ORIGINS=* + - POWERMEM_DATABASE_URL= + # Database configuration for connecting to SeekDB + # Use SEEKDB_ROOT_PASSWORD variable for unified password management + - DATABASE_PROVIDER=oceanbase + - OCEANBASE_HOST=seekdb + - OCEANBASE_PORT=2881 + - OCEANBASE_USER=root@sys + - OCEANBASE_PASSWORD=${SEEKDB_ROOT_PASSWORD:-} + - OCEANBASE_DATABASE=powermem + - OCEANBASE_COLLECTION=memories volumes: - ./logs:/app/logs - # Mount .env file so both SDK and Server can use the same configuration - - ./.env:/app/.env:ro restart: unless-stopped healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8000/api/v1/system/health"] @@ -40,4 +45,42 @@ services: options: max-size: "10m" max-file: "3" + depends_on: + - seekdb + + seekdb: + image: oceanbase/seekdb:latest + container_name: powermem-seekdb + ports: + - "2881:2881" + - "2886:2886" + environment: + # Unified password variable for both SeekDB and PowerMem Server + - ROOT_PASSWORD=${SEEKDB_ROOT_PASSWORD:-} + - CPU_COUNT=4 + - MEMORY_LIMIT=4G + - LOG_DISK_SIZE=2G + - DATAFILE_SIZE=2G + - DATAFILE_NEXT=2G + - DATAFILE_MAXSIZE=50G + - SEEKDB_DATABASE=powermem + volumes: + - seekdb_data:/var/lib/oceanbase + # Mount init.sql for database initialization (optional) + # - ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro + restart: unless-stopped + healthcheck: + test: ["CMD-SHELL", "if [ -z \"${SEEKDB_ROOT_PASSWORD}\" ]; then mysqladmin ping -h localhost -P 2881 -u root; else mysqladmin ping -h localhost -P 2881 -u root -p${SEEKDB_ROOT_PASSWORD}; fi"] + interval: 30s + timeout: 10s + retries: 5 + start_period: 60s + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + +volumes: + seekdb_data: From 749e53ee1d46bb56e7e889f01f51e8d7a947e2bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Tue, 20 Jan 2026 15:26:43 +0800 Subject: [PATCH 13/17] Chore (Docker): Add custom network configuration -Add powermem network configuration for service -Add powermem server and seeddb services to the network --- docker/docker-compose.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index e123547..67a2d1e 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -1,5 +1,10 @@ version: '3.8' +networks: + powermem-network: + driver: bridge + name: powermem-network + services: powermem-server: build: @@ -47,6 +52,8 @@ services: max-file: "3" depends_on: - seekdb + networks: + - powermem-network seekdb: image: oceanbase/seekdb:latest @@ -80,6 +87,8 @@ services: options: max-size: "10m" max-file: "3" + networks: + - powermem-network volumes: seekdb_data: From 726e3d5d81755343aaf9c2d065a17524fa63eb8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Tue, 20 Jan 2026 17:06:01 +0800 Subject: [PATCH 14/17] Chore (Docker): Use lowercase seeddb names uniformly -Update database names in docker-compose.yml and README.md -Add. env file support to Docker Compose configuration --- docker/README.md | 22 ++++++++++++---------- docker/docker-compose.yml | 6 ++++-- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/docker/README.md b/docker/README.md index 27cf85d..fe98c3f 100644 --- a/docker/README.md +++ b/docker/README.md @@ -5,7 +5,7 @@ This directory contains all Docker-related files for PowerMem Server. ## Files - `Dockerfile` - Multi-stage Docker build file for PowerMem Server -- `docker-compose.yml` - Docker Compose configuration file with SeekDB support +- `docker-compose.yml` - Docker Compose configuration file with seekdb support - `docker-entrypoint.sh` - Container entrypoint script - `.dockerignore` - Files to exclude from Docker build context - `DOCKER.md` - Complete Docker deployment documentation @@ -20,7 +20,7 @@ From the project root directory: docker build -t oceanbase/powermem-server:latest -f docker/Dockerfile . ``` -### Run with Docker Compose (with SeekDB) +### Run with Docker Compose (with seekdb) From the project root directory: @@ -44,6 +44,8 @@ From the project root directory: docker run -d \ --name powermem-server \ -p 8000:8000 \ + -v $(pwd)/.env:/app/.env:ro \ + --env-file .env \ oceanbase/powermem-server:latest ``` @@ -52,18 +54,18 @@ docker run -d \ ### PowerMem Server - Port: 8000 - Health check: `http://localhost:8000/api/v1/system/health` -- Database: Connected to SeekDB without password +- Database: Connected to seekdb without password -### SeekDB Database +### seekdb Database - MySQL Port: 2881 -- Web Dashboard: 2886 +- seekdb Web Dashboard: 2886 - Data persistence: Docker volume `seekdb_data` - Default database: `powermem` - Password: Controlled by `SEEKDB_ROOT_PASSWORD` environment variable - Not set (default): No password - Set via command line: Use specified password -## Connecting to SeekDB +## Connecting to seekdb ### Without password (default) ```bash @@ -76,7 +78,7 @@ mysql -h 127.0.0.1 -P 2881 -u root -p # Enter the password when prompted ``` -### Web Dashboard +### seekdb Web Dashboard Open browser to: `http://localhost:2886` - Username: `root` - Password: Same as `SEEKDB_ROOT_PASSWORD` environment variable (not set by default) @@ -92,7 +94,7 @@ The `docker-compose.yml` file includes default configuration values: - Authentication: Disabled - CORS: Enabled for all origins -**SeekDB:** +**seekdb:** - Password: Controlled by `SEEKDB_ROOT_PASSWORD` environment variable (not set by default) - CPU: 4 cores - Memory: 4GB @@ -107,8 +109,8 @@ For detailed documentation, see [DOCKER.md](./DOCKER.md). - All Docker commands should be run from the **project root directory**, not from the `docker/` directory - The build context is the project root, so paths in Dockerfile are relative to the project root -- SeekDB data is persisted in a Docker volume named `seekdb_data` -- On macOS with Docker version > 4.9.0, there are known issues with SeekDB. Consider using an older Docker version if needed. +- seekdb data is persisted in a Docker volume named `seekdb_data` +- On macOS with Docker version > 4.9.0, there are known issues with seekdb. Consider using an older Docker version if needed. - **Password Management**: - Default: No password (`SEEKDB_ROOT_PASSWORD` not set) - To set a password: Use command line: `SEEKDB_ROOT_PASSWORD=your_password docker-compose -f docker/docker-compose.yml up -d` diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 67a2d1e..d8c7303 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -27,7 +27,7 @@ services: - POWERMEM_SERVER_CORS_ENABLED=true - POWERMEM_SERVER_CORS_ORIGINS=* - POWERMEM_DATABASE_URL= - # Database configuration for connecting to SeekDB + # Database configuration for connecting to seekdb # Use SEEKDB_ROOT_PASSWORD variable for unified password management - DATABASE_PROVIDER=oceanbase - OCEANBASE_HOST=seekdb @@ -36,6 +36,8 @@ services: - OCEANBASE_PASSWORD=${SEEKDB_ROOT_PASSWORD:-} - OCEANBASE_DATABASE=powermem - OCEANBASE_COLLECTION=memories + env_file: + - .env volumes: - ./logs:/app/logs restart: unless-stopped @@ -62,7 +64,7 @@ services: - "2881:2881" - "2886:2886" environment: - # Unified password variable for both SeekDB and PowerMem Server + # Unified password variable for both seekdb and PowerMem Server - ROOT_PASSWORD=${SEEKDB_ROOT_PASSWORD:-} - CPU_COUNT=4 - MEMORY_LIMIT=4G From 4e97f98bd91e86e6c576900bfe05bf66feac0510 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Tue, 20 Jan 2026 17:07:31 +0800 Subject: [PATCH 15/17] Docs (Docker): Update Docker's readme document --- docker/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docker/README.md b/docker/README.md index fe98c3f..087e4bd 100644 --- a/docker/README.md +++ b/docker/README.md @@ -109,6 +109,7 @@ For detailed documentation, see [DOCKER.md](./DOCKER.md). - All Docker commands should be run from the **project root directory**, not from the `docker/` directory - The build context is the project root, so paths in Dockerfile are relative to the project root +- The `.env` file should be in the project root directory and will be mounted into the container - seekdb data is persisted in a Docker volume named `seekdb_data` - On macOS with Docker version > 4.9.0, there are known issues with seekdb. Consider using an older Docker version if needed. - **Password Management**: From e354818e5972dad95e145fc1649440e71da3c5f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Fri, 23 Jan 2026 15:20:17 +0800 Subject: [PATCH 16/17] Chore (Docker): Update Docker Compose configuration --- docker/docker-compose.yml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index d8c7303..9d92505 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -15,18 +15,18 @@ services: ports: - "8000:8000" environment: - - POWERMEM_SERVER_HOST=0.0.0.0 - - POWERMEM_SERVER_PORT=8000 - - POWERMEM_SERVER_WORKERS=4 - - POWERMEM_SERVER_API_KEYS= - - POWERMEM_SERVER_AUTH_ENABLED=false - - POWERMEM_SERVER_RATE_LIMIT_ENABLED=true - - POWERMEM_SERVER_RATE_LIMIT_PER_MINUTE=100 - - POWERMEM_SERVER_LOG_LEVEL=INFO - - POWERMEM_SERVER_LOG_FORMAT=json - - POWERMEM_SERVER_CORS_ENABLED=true - - POWERMEM_SERVER_CORS_ORIGINS=* - - POWERMEM_DATABASE_URL= + - POWERMEM_SERVER_HOST=${POWERMEM_SERVER_HOST:-0.0.0.0} + - POWERMEM_SERVER_PORT=${POWERMEM_SERVER_PORT:-8000} + - POWERMEM_SERVER_WORKERS=${POWERMEM_SERVER_WORKERS:-4} + - POWERMEM_SERVER_API_KEYS=${POWERMEM_SERVER_API_KEYS:-} + - POWERMEM_SERVER_AUTH_ENABLED=${POWERMEM_SERVER_AUTH_ENABLED:-false} + - POWERMEM_SERVER_RATE_LIMIT_ENABLED=${POWERMEM_SERVER_RATE_LIMIT_ENABLED:-true} + - POWERMEM_SERVER_RATE_LIMIT_PER_MINUTE=${POWERMEM_SERVER_RATE_LIMIT_PER_MINUTE:-100} + - POWERMEM_SERVER_LOG_LEVEL=${POWERMEM_SERVER_LOG_LEVEL:-INFO} + - POWERMEM_SERVER_LOG_FORMAT=${POWERMEM_SERVER_LOG_FORMAT:-json} + - POWERMEM_SERVER_CORS_ENABLED=${POWERMEM_SERVER_CORS_ENABLED:-true} + - POWERMEM_SERVER_CORS_ORIGINS=${POWERMEM_SERVER_CORS_ORIGINS:-*} + - POWERMEM_DATABASE_URL=${POWERMEM_DATABASE_URL:-} # Database configuration for connecting to seekdb # Use SEEKDB_ROOT_PASSWORD variable for unified password management - DATABASE_PROVIDER=oceanbase From 7f1f18ced8343934571123f874c779630f7eca17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Fri, 23 Jan 2026 17:12:01 +0800 Subject: [PATCH 17/17] Chore (Docker): Update Docker Compose configuration --- docker/docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 9d92505..67c6a69 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -13,7 +13,7 @@ services: image: oceanbase/powermem-server:latest container_name: powermem-server ports: - - "8000:8000" + - "${POWERMEM_SERVER_PORT:-8000}:8000" environment: - POWERMEM_SERVER_HOST=${POWERMEM_SERVER_HOST:-0.0.0.0} - POWERMEM_SERVER_PORT=${POWERMEM_SERVER_PORT:-8000}