diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3d8e1d7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +# Dependencies +node_modules/ + +# VitePress build output +docs/.vitepress/dist/ +docs/.vitepress/cache/ + +# Logs +*.log +npm-debug.log* + +# Editor directories +.idea/ +.vscode/ +*.swp +*.swo + +# OS files +.DS_Store +Thumbs.db + +# Temporary files +*.tmp +*.temp diff --git a/README.md b/README.md index 3e9378f..332cd03 100644 --- a/README.md +++ b/README.md @@ -1 +1,136 @@ -# learn-ai \ No newline at end of file +# AI学习之路 - 人工智能入门教程 + +面向软件工程专业毕业生的中文人工智能入门学习教程网站。 + +## ✨ 特性 + +- **内容与代码分离**:使用Markdown编写内容,方便更新维护 +- **VitePress驱动**:现代化静态站点生成器,构建速度快 +- **数学公式支持**:集成MathJax渲染数学公式 +- **代码高亮**:自动语法高亮,支持多种编程语言 +- **响应式设计**:支持桌面和移动端浏览 +- **全文搜索**:内置本地搜索功能 + +## 📚 教程大纲 + +### 第0章:前置知识 +- 数学基础 - 线性代数、微积分、概率论 +- Python科学计算 - NumPy、Pandas、Matplotlib +- 数据处理基础 - 数据预处理、特征工程 + +### 第1章:AI基础概念 +- 什么是人工智能 - AI定义、历史与分类 +- 机器学习概述 - 监督学习、无监督学习、强化学习 +- 开发环境搭建 - Anaconda、Jupyter、GPU配置 + +### 第2章:机器学习入门 +- 线性回归 - 模型原理、梯度下降、代码实现 + +### 第3章:深度学习入门 +- 神经网络基础 - 感知机、激活函数、反向传播 + +### 第4章:实战项目 +- 房价预测 - 完整的回归任务流程 + +## 🚀 快速开始 + +### 安装依赖 + +```bash +npm install +``` + +### 本地开发 + +```bash +npm run docs:dev +``` + +访问 http://localhost:5173 预览网站。 + +### 构建生产版本 + +```bash +npm run docs:build +``` + +构建产物在 `docs/.vitepress/dist` 目录。 + +### 预览构建结果 + +```bash +npm run docs:preview +``` + +## 📁 项目结构 + +``` +learn-ai/ +├── docs/ # 文档源文件 +│ ├── .vitepress/ # VitePress配置 +│ │ └── config.mts # 站点配置 +│ ├── chapters/ # 教程章节 +│ │ ├── prerequisites/ # 前置知识 +│ │ ├── basics/ # AI基础 +│ │ ├── machine-learning/ # 机器学习 +│ │ ├── deep-learning/ # 深度学习 +│ │ └── projects/ # 实战项目 +│ ├── public/ # 静态资源 +│ ├── index.md # 首页 +│ ├── outline.md # 学习大纲 +│ └── resources.md # 推荐资源 +├── package.json +└── README.md +``` + +## 📝 内容更新 + +所有教程内容都在 `docs/chapters/` 目录下,使用Markdown格式编写。 + +### 添加新章节 + +1. 在对应目录创建新的 `.md` 文件 +2. 在 `docs/.vitepress/config.mts` 中更新侧边栏配置 +3. 运行 `npm run docs:dev` 预览 + +### Markdown增强功能 + +```markdown +# 提示框 +::: info 信息 +这是一个信息提示 +::: + +::: tip 提示 +这是一个提示 +::: + +::: warning 警告 +这是一个警告 +::: + +# 数学公式 +行内公式: $E = mc^2$ + +块级公式: +$$ +\frac{\partial L}{\partial w} = \frac{2}{m}\sum_{i=1}^{m}(wx_i + b - y_i)x_i +$$ + +# 代码块 +```python +import numpy as np +print("Hello, AI!") +``` +``` + +## 🔗 参考资源 + +- [吴恩达机器学习课程](https://www.coursera.org/learn/machine-learning) +- [李沐《动手学深度学习》](https://d2l.ai/zh/) +- [Fast.ai深度学习课程](https://www.fast.ai/) +- [VitePress文档](https://vitepress.dev/) + +## 📄 许可证 + +MIT License \ No newline at end of file diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts new file mode 100644 index 0000000..49f3a02 --- /dev/null +++ b/docs/.vitepress/config.mts @@ -0,0 +1,180 @@ +import { defineConfig } from 'vitepress' +import mathjax3 from 'markdown-it-mathjax3' + +// 自定义MathJax元素标签 +const customElements = [ + 'mjx-container', + 'mjx-assistive-mml', + 'math', + 'maction', + 'maligngroup', + 'malignmark', + 'menclose', + 'merror', + 'mfenced', + 'mfrac', + 'mi', + 'mlongdiv', + 'mmultiscripts', + 'mn', + 'mo', + 'mover', + 'mpadded', + 'mphantom', + 'mroot', + 'mrow', + 'ms', + 'mscarries', + 'mscarry', + 'msgroup', + 'mstack', + 'msline', + 'mspace', + 'msqrt', + 'msrow', + 'mstyle', + 'msub', + 'msup', + 'msubsup', + 'mtable', + 'mtd', + 'mtext', + 'mtr', + 'munder', + 'munderover', + 'semantics', + 'annotation', + 'annotation-xml' +] + +export default defineConfig({ + lang: 'zh-CN', + title: 'AI学习之路', + description: '面向软件工程毕业生的人工智能入门教程', + + head: [ + ['link', { rel: 'icon', type: 'image/svg+xml', href: '/logo.svg' }], + ], + + markdown: { + config: (md) => { + md.use(mathjax3) + }, + lineNumbers: true, + }, + + vue: { + template: { + compilerOptions: { + isCustomElement: (tag) => customElements.includes(tag) + } + } + }, + + themeConfig: { + logo: '/logo.svg', + + nav: [ + { text: '首页', link: '/' }, + { text: '教程', link: '/chapters/prerequisites/math' }, + { text: '资源推荐', link: '/resources' }, + ], + + sidebar: { + '/chapters/': [ + { + text: '第0章:前置知识', + collapsed: false, + items: [ + { text: '数学基础', link: '/chapters/prerequisites/math' }, + { text: 'Python科学计算', link: '/chapters/prerequisites/python-scientific' }, + { text: '数据处理基础', link: '/chapters/prerequisites/data-processing' }, + ] + }, + { + text: '第1章:AI基础概念', + collapsed: false, + items: [ + { text: '什么是人工智能', link: '/chapters/basics/what-is-ai' }, + { text: '机器学习概述', link: '/chapters/basics/ml-overview' }, + { text: '开发环境搭建', link: '/chapters/basics/environment-setup' }, + ] + }, + { + text: '第2章:机器学习入门', + collapsed: false, + items: [ + { text: '线性回归', link: '/chapters/machine-learning/linear-regression' }, + ] + }, + { + text: '第3章:深度学习入门', + collapsed: false, + items: [ + { text: '神经网络基础', link: '/chapters/deep-learning/neural-networks' }, + ] + }, + { + text: '第4章:实战项目', + collapsed: false, + items: [ + { text: '房价预测', link: '/chapters/projects/house-price' }, + ] + }, + ], + }, + + socialLinks: [ + { icon: 'github', link: 'https://github.com/LeeGoDamn/learn-ai' } + ], + + footer: { + message: '面向软件工程毕业生的人工智能入门教程', + copyright: '© 2024 AI学习之路' + }, + + search: { + provider: 'local', + options: { + translations: { + button: { + buttonText: '搜索', + buttonAriaLabel: '搜索文档' + }, + modal: { + noResultsText: '无法找到相关结果', + resetButtonTitle: '清除查询条件', + footer: { + selectText: '选择', + navigateText: '切换' + } + } + } + } + }, + + outline: { + label: '页面导航', + level: [2, 3] + }, + + docFooter: { + prev: '上一页', + next: '下一页' + }, + + lastUpdated: { + text: '最后更新于', + formatOptions: { + dateStyle: 'short', + timeStyle: 'medium' + } + }, + + returnToTopLabel: '回到顶部', + sidebarMenuLabel: '菜单', + darkModeSwitchLabel: '主题', + lightModeSwitchTitle: '切换到浅色模式', + darkModeSwitchTitle: '切换到深色模式' + } +}) diff --git a/docs/chapters/basics/environment-setup.md b/docs/chapters/basics/environment-setup.md new file mode 100644 index 0000000..dc2e10e --- /dev/null +++ b/docs/chapters/basics/environment-setup.md @@ -0,0 +1,282 @@ +# 开发环境搭建 + +::: info 本章概述 +本章将指导你搭建完整的AI开发环境,包括Anaconda、Jupyter Notebook、常用库安装以及GPU配置。 +::: + +## 1. Python环境管理 + +### 1.1 为什么需要环境管理? + +不同的AI项目可能需要不同版本的Python和库。环境管理工具可以: +- 隔离不同项目的依赖,避免冲突 +- 方便复制和共享环境配置 +- 便于切换Python版本 + +### 1.2 Anaconda安装 + +**Anaconda** 是最流行的Python科学计算发行版,预装了大量常用库。 + +::: tip 下载安装 +1. 访问 [Anaconda官网](https://www.anaconda.com/download) +2. 下载对应操作系统的安装包 +3. 运行安装程序,按提示完成安装 +4. 建议勾选"添加到环境变量"选项 +::: + +### 1.3 Conda常用命令 + +```bash +# 查看版本 +conda --version + +# 创建新环境 +conda create -n ai_env python=3.10 + +# 激活环境 +conda activate ai_env + +# 退出环境 +conda deactivate + +# 查看所有环境 +conda env list + +# 删除环境 +conda remove -n ai_env --all + +# 导出环境配置 +conda env export > environment.yml + +# 从配置文件创建环境 +conda env create -f environment.yml +``` + +### 1.4 安装常用库 + +```bash +# 激活环境后安装库 +conda activate ai_env + +# 基础科学计算库 +conda install numpy pandas matplotlib seaborn + +# 机器学习库 +conda install scikit-learn + +# 深度学习框架(二选一) +# PyTorch(推荐) +conda install pytorch torchvision torchaudio -c pytorch + +# TensorFlow +conda install tensorflow + +# 其他常用库 +conda install jupyter jupyterlab +pip install tqdm # 进度条 +``` + +## 2. Jupyter Notebook + +**Jupyter Notebook** 是交互式编程环境,非常适合数据分析和机器学习实验。 + +### 2.1 启动Jupyter + +```bash +# 启动 Jupyter Notebook +jupyter notebook + +# 或启动 Jupyter Lab(更现代的界面) +jupyter lab +``` + +执行后会自动打开浏览器,访问 `http://localhost:8888` + +### 2.2 常用快捷键 + +| 快捷键 | 功能 | 模式 | +|--------|------|------| +| Shift + Enter | 运行当前单元格,跳到下一个 | 通用 | +| Ctrl + Enter | 运行当前单元格 | 通用 | +| Esc | 进入命令模式 | 编辑模式 | +| Enter | 进入编辑模式 | 命令模式 | +| A / B | 在上方/下方插入单元格 | 命令模式 | +| D + D | 删除当前单元格 | 命令模式 | +| M / Y | 切换为Markdown/代码 | 命令模式 | + +### 2.3 Notebook最佳实践 + +- 每个单元格只做一件事,保持简洁 +- 使用Markdown单元格添加说明文档 +- 定期保存,使用版本控制 +- 运行顺序很重要,建议从头到尾运行 +- 重要实验结果要截图或导出 + +## 3. Google Colab(免费GPU) + +**Google Colab** 是谷歌提供的免费云端Jupyter环境,无需本地配置,还提供免费GPU。 + +### 3.1 使用Colab + +1. 访问 [Google Colab](https://colab.research.google.com) +2. 登录Google账号 +3. 新建笔记本或上传本地.ipynb文件 + +### 3.2 启用GPU + +::: tip 启用GPU加速 +1. 菜单栏 → 修改 → 笔记本设置 +2. 硬件加速器选择"GPU"或"TPU" +3. 点击保存 +::: + +```python +# 检查GPU是否可用 +import torch +print(f"PyTorch版本: {torch.__version__}") +print(f"CUDA可用: {torch.cuda.is_available()}") +if torch.cuda.is_available(): + print(f"GPU型号: {torch.cuda.get_device_name(0)}") +``` + +### 3.3 Colab实用技巧 + +```python +# 挂载Google Drive(持久存储) +from google.colab import drive +drive.mount('/content/drive') + +# 安装额外的库 +!pip install transformers + +# 下载文件 +!wget https://example.com/data.csv + +# 查看GPU使用情况 +!nvidia-smi +``` + +## 4. GPU配置(本地) + +如果你有NVIDIA GPU,可以配置本地CUDA环境以加速深度学习训练。 + +### 4.1 检查GPU + +```bash +# Windows: 打开命令提示符 +nvidia-smi + +# 如果能显示GPU信息,说明驱动已安装 +``` + +### 4.2 安装CUDA工具包 + +1. 确认GPU支持的CUDA版本 +2. 安装对应版本的CUDA Toolkit +3. 安装cuDNN库 +4. 配置环境变量 + +::: warning 版本兼容性 +PyTorch和TensorFlow对CUDA版本有要求。建议先确认框架需要的CUDA版本,再安装对应版本。 + +最简单的方式是使用conda安装,它会自动处理依赖: +::: + +```bash +# PyTorch with CUDA 11.8 +conda install pytorch torchvision torchaudio pytorch-cuda=11.8 -c pytorch -c nvidia + +# TensorFlow with GPU support +pip install tensorflow[and-cuda] +``` + +## 5. 常用IDE配置 + +### 5.1 VS Code + +Visual Studio Code是最流行的代码编辑器,对Python和Jupyter有很好的支持。 + +::: tip 推荐扩展 +- **Python** - 微软官方Python支持 +- **Jupyter** - 在VS Code中运行Notebook +- **Pylance** - Python语言服务器 +- **GitHub Copilot** - AI编程助手 +- **GitLens** - Git增强 +::: + +### 5.2 PyCharm + +PyCharm是专业的Python IDE,社区版免费,对大型项目支持较好。 + +## 6. 验证环境 + +运行以下代码验证环境是否正确配置: + +```python +import sys +print(f"Python版本: {sys.version}") + +import numpy as np +print(f"NumPy版本: {np.__version__}") + +import pandas as pd +print(f"Pandas版本: {pd.__version__}") + +import sklearn +print(f"Scikit-learn版本: {sklearn.__version__}") + +import matplotlib +print(f"Matplotlib版本: {matplotlib.__version__}") + +# 深度学习框架 +try: + import torch + print(f"PyTorch版本: {torch.__version__}") + print(f"CUDA可用: {torch.cuda.is_available()}") +except ImportError: + print("PyTorch未安装") + +try: + import tensorflow as tf + print(f"TensorFlow版本: {tf.__version__}") + print(f"GPU可用: {len(tf.config.list_physical_devices('GPU')) > 0}") +except ImportError: + print("TensorFlow未安装") + +print("\n环境配置完成!可以开始学习了!") +``` + +## 7. 推荐的项目结构 + +``` +my_ai_project/ +├── data/ # 数据文件 +│ ├── raw/ # 原始数据 +│ └── processed/ # 处理后的数据 +├── notebooks/ # Jupyter笔记本 +│ ├── 01_eda.ipynb # 探索性分析 +│ ├── 02_training.ipynb # 模型训练 +│ └── 03_evaluation.ipynb +├── src/ # 源代码 +│ ├── __init__.py +│ ├── data_processing.py +│ ├── models.py +│ └── utils.py +├── models/ # 保存的模型 +├── results/ # 结果和图表 +├── requirements.txt # 依赖列表 +├── environment.yml # Conda环境配置 +└── README.md # 项目说明 +``` + +## 8. 本章小结 + +- 使用Anaconda管理Python环境和依赖 +- Jupyter Notebook是交互式实验的首选工具 +- Google Colab提供免费GPU,适合没有本地GPU的学习者 +- 本地GPU配置需要注意CUDA版本兼容性 +- 良好的项目结构有助于代码管理和协作 + +::: tip 下一步 +环境配置完成后,我们将开始学习机器学习的核心算法——从线性回归开始! +::: diff --git a/docs/chapters/basics/ml-overview.md b/docs/chapters/basics/ml-overview.md new file mode 100644 index 0000000..3ed091e --- /dev/null +++ b/docs/chapters/basics/ml-overview.md @@ -0,0 +1,218 @@ +# 机器学习概述 + +::: info 本章概述 +本章深入介绍机器学习的三大范式(监督学习、无监督学习、强化学习),以及机器学习工作流程和常用算法分类。 +::: + +## 1. 什么是机器学习 + +**机器学习(Machine Learning)** 是人工智能的核心分支,它使计算机能够从数据中自动学习规律,无需显式编程。 + +::: tip 经典定义 +**汤姆·米切尔(Tom Mitchell)**:如果一个程序在任务T上的性能P随着经验E的增加而提高,则称该程序从经验E中学习。 +::: + +举个例子:垃圾邮件过滤器 + +- **任务T**:将邮件分类为垃圾邮件或正常邮件 +- **性能P**:分类准确率 +- **经验E**:用户标记的邮件数据 + +## 2. 监督学习(Supervised Learning) + +监督学习是最常见的机器学习类型,使用带有标签的数据进行训练。 + +### 2.1 基本概念 + +- **特征(Features)**:输入变量,用于描述样本的属性,通常表示为 X +- **标签(Label)**:目标变量,我们要预测的值,通常表示为 y +- **训练集**:用于训练模型的数据 +- **测试集**:用于评估模型性能的数据 + +### 2.2 问题类型 + +| 类型 | 描述 | 例子 | 常用算法 | +|------|------|------|----------| +| **回归** | 预测连续数值 | 房价预测、温度预测 | 线性回归、随机森林 | +| **分类** | 预测离散类别 | 垃圾邮件识别、图像分类 | 逻辑回归、SVM、神经网络 | + +### 2.3 代码示例 + +```python +from sklearn.model_selection import train_test_split +from sklearn.linear_model import LinearRegression +from sklearn.metrics import mean_squared_error +import numpy as np + +# 1. 准备数据 +X = np.array([[1], [2], [3], [4], [5], [6], [7], [8], [9], [10]]) +y = np.array([2.1, 4.2, 5.8, 8.1, 9.9, 12.1, 14.0, 16.2, 17.9, 20.1]) + +# 2. 划分训练集和测试集 +X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) + +# 3. 创建并训练模型 +model = LinearRegression() +model.fit(X_train, y_train) + +# 4. 预测 +y_pred = model.predict(X_test) + +# 5. 评估 +mse = mean_squared_error(y_test, y_pred) +print(f"均方误差: {mse:.4f}") +print(f"模型参数: y = {model.coef_[0]:.2f}x + {model.intercept_:.2f}") +``` + +## 3. 无监督学习(Unsupervised Learning) + +无监督学习使用没有标签的数据,目标是发现数据中隐藏的结构和模式。 + +### 3.1 主要任务 + +| 任务 | 描述 | 例子 | 常用算法 | +|------|------|------|----------| +| **聚类** | 将相似样本分组 | 客户分群、文档分类 | K-means、DBSCAN、层次聚类 | +| **降维** | 减少特征数量 | 数据可视化、特征提取 | PCA、t-SNE、UMAP | +| **异常检测** | 识别异常样本 | 欺诈检测、故障诊断 | Isolation Forest、One-class SVM | + +### 3.2 聚类示例 + +```python +from sklearn.cluster import KMeans +from sklearn.datasets import make_blobs +import matplotlib.pyplot as plt + +# 生成示例数据 +X, _ = make_blobs(n_samples=300, centers=4, cluster_std=0.6, random_state=42) + +# K-means聚类 +kmeans = KMeans(n_clusters=4, random_state=42) +labels = kmeans.fit_predict(X) + +# 可视化 +plt.figure(figsize=(8, 6)) +plt.scatter(X[:, 0], X[:, 1], c=labels, cmap='viridis') +plt.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1], + c='red', marker='x', s=200, linewidths=3) +plt.title('K-means聚类结果') +plt.savefig('kmeans_result.png') +plt.show() +``` + +## 4. 强化学习(Reinforcement Learning) + +强化学习与监督学习和无监督学习不同,它通过智能体与环境的交互来学习最优策略。 + +### 4.1 核心概念 + +- **智能体(Agent)**:学习者,做出决策 +- **环境(Environment)**:智能体交互的外部世界 +- **状态(State)**:环境的当前情况 +- **动作(Action)**:智能体可执行的操作 +- **奖励(Reward)**:动作后环境给予的反馈 +- **策略(Policy)**:从状态到动作的映射 + +``` +┌──────────┐ 动作 ┌──────────┐ +│ │ ──────────────────▶ │ │ +│ 智能体 │ │ 环境 │ +│ │ ◀────────────────── │ │ +└──────────┘ 状态 + 奖励 └──────────┘ +``` + +### 4.2 典型应用 + +- **游戏AI**:AlphaGo、Atari游戏、星际争霸 +- **机器人控制**:机械臂操作、自主导航 +- **推荐系统**:个性化推荐、广告投放 +- **自动驾驶**:决策规划 + +## 5. 机器学习工作流程 + +一个完整的机器学习项目通常包含以下步骤: + +1. **问题定义** → 明确业务目标和评估指标 +2. **数据收集** → 获取相关数据 +3. **数据探索** → EDA,理解数据特征 +4. **数据预处理** → 清洗、转换、特征工程 +5. **模型选择** → 根据问题类型选择合适的算法 +6. **模型训练** → 在训练集上拟合模型 +7. **模型评估** → 在测试集上评估性能 +8. **模型调优** → 超参数优化、特征选择 +9. **模型部署** → 将模型投入生产环境 +10. **监控维护** → 持续监控和更新 + +## 6. 常用算法概览 + +### 6.1 线性模型 +- 线性回归(Linear Regression) +- 逻辑回归(Logistic Regression) +- 正则化:Ridge、Lasso + +### 6.2 树模型 +- 决策树(Decision Tree) +- 随机森林(Random Forest) +- 梯度提升树(XGBoost、LightGBM) + +### 6.3 支持向量机 +- 线性SVM +- 核SVM(RBF、多项式核) + +### 6.4 神经网络 +- 多层感知机(MLP) +- 卷积神经网络(CNN) +- 循环神经网络(RNN/LSTM) +- Transformer + +## 7. 模型评估指标 + +### 7.1 回归问题 + +| 指标 | 公式描述 | 特点 | +|------|----------|------| +| MSE | 均方误差 | 对大误差敏感 | +| RMSE | 均方根误差 | 与原始单位相同 | +| MAE | 平均绝对误差 | 对异常值鲁棒 | +| R² | 决定系数 | 解释方差比例 | + +### 7.2 分类问题 + +| 指标 | 描述 | 适用场景 | +|------|------|----------| +| 准确率 | 正确预测的比例 | 类别平衡时 | +| 精确率 | 预测为正中真正为正的比例 | 关注假阳性时 | +| 召回率 | 真正为正中被预测为正的比例 | 关注假阴性时 | +| F1分数 | 精确率和召回率的调和平均 | 综合评估 | +| AUC-ROC | ROC曲线下面积 | 类别不平衡时 | + +```python +from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score +from sklearn.metrics import confusion_matrix, classification_report + +# 假设有真实标签和预测标签 +y_true = [1, 0, 1, 1, 0, 1, 0, 0, 1, 0] +y_pred = [1, 0, 1, 0, 0, 1, 1, 0, 1, 0] + +# 计算各项指标 +print(f"准确率: {accuracy_score(y_true, y_pred):.4f}") +print(f"精确率: {precision_score(y_true, y_pred):.4f}") +print(f"召回率: {recall_score(y_true, y_pred):.4f}") +print(f"F1分数: {f1_score(y_true, y_pred):.4f}") + +# 混淆矩阵 +print("\n混淆矩阵:") +print(confusion_matrix(y_true, y_pred)) + +# 详细报告 +print("\n分类报告:") +print(classification_report(y_true, y_pred)) +``` + +## 8. 本章小结 + +- **监督学习**:从带标签数据学习,用于分类和回归问题 +- **无监督学习**:从无标签数据发现结构,用于聚类和降维 +- **强化学习**:通过交互学习最优策略 +- 机器学习项目包含数据准备、模型训练、评估调优等多个阶段 +- 选择合适的评估指标对于模型选择至关重要 diff --git a/docs/chapters/basics/what-is-ai.md b/docs/chapters/basics/what-is-ai.md new file mode 100644 index 0000000..7bb01e3 --- /dev/null +++ b/docs/chapters/basics/what-is-ai.md @@ -0,0 +1,141 @@ +# 什么是人工智能 + +::: info 本章概述 +本章将帮助你建立对人工智能领域的整体认识,了解AI的定义、发展历程、主要分支以及核心概念,为后续深入学习奠定基础。 +::: + +## 1. 人工智能的定义 + +人工智能(Artificial Intelligence,简称AI)是一个广泛的概念,指的是机器模拟人类智能行为的能力。不同学者和机构对AI有不同的定义: + +| 定义视角 | 描述 | +|----------|------| +| 像人一样思考 | 模拟人类认知过程的系统(认知科学方法) | +| 像人一样行动 | 通过图灵测试的系统(行为主义方法) | +| 理性地思考 | 使用逻辑进行推理的系统(逻辑学方法) | +| 理性地行动 | 在给定知识下做出最优决策的智能代理(现代主流定义) | + +::: tip 经典定义 +**约翰·麦卡锡(John McCarthy)** 在1956年首次提出"人工智能"这一术语,将其定义为:"研究如何使计算机做本来只有人才能做的智能工作。" +::: + +## 2. AI、机器学习与深度学习的关系 + +这三个概念经常被混用,但它们是包含关系: + +``` +┌─────────────────────────────────────────┐ +│ 人工智能 (AI) │ +│ ┌─────────────────────────────────┐ │ +│ │ 机器学习 (ML) │ │ +│ │ ┌─────────────────────────┐ │ │ +│ │ │ 深度学习 (DL) │ │ │ +│ │ └─────────────────────────┘ │ │ +│ └─────────────────────────────────┘ │ +└─────────────────────────────────────────┘ +``` + +- **人工智能(AI)**:最广泛的概念,包括所有使机器表现出智能行为的技术 +- **机器学习(ML)**:AI的子集,让机器从数据中学习规律,无需显式编程 +- **深度学习(DL)**:ML的子集,使用深层神经网络进行学习 + +## 3. AI发展历史 + +### 3.1 重要里程碑 + +| 年份 | 事件 | 意义 | +|------|------|------| +| 1950 | 图灵提出图灵测试 | 定义了机器智能的评判标准 | +| 1956 | 达特茅斯会议 | "人工智能"术语诞生,AI成为独立学科 | +| 1957 | 感知机诞生 | 最早的神经网络模型 | +| 1986 | 反向传播算法 | 使多层神经网络训练成为可能 | +| 1997 | 深蓝击败卡斯帕罗夫 | AI首次在国际象棋击败人类冠军 | +| 2012 | AlexNet赢得ImageNet | 深度学习革命开始 | +| 2016 | AlphaGo击败李世石 | AI在围棋领域超越人类 | +| 2022 | ChatGPT发布 | 大语言模型引发AI应用浪潮 | + +### 3.2 AI的三次浪潮 + +- **第一次浪潮(1956-1970s)**:符号主义AI,专家系统,因计算能力限制而衰退 +- **第二次浪潮(1980s-2000s)**:统计机器学习方法兴起,SVM、随机森林等 +- **第三次浪潮(2010s-至今)**:深度学习革命,大模型时代 + +## 4. AI的主要分支 + +### 4.1 按问题类型分类 + +**机器学习三大范式:** + +| 类型 | 描述 | 典型应用 | +|------|------|----------| +| **监督学习** | 从带标签的数据中学习,预测新数据的标签 | 图像分类、垃圾邮件过滤、房价预测 | +| **无监督学习** | 从无标签数据中发现结构和模式 | 用户分群、异常检测、降维 | +| **强化学习** | 通过与环境交互,最大化累积奖励 | 游戏AI、机器人控制、推荐系统 | + +### 4.2 按应用领域分类 + +- **计算机视觉(CV)**:图像识别、目标检测、人脸识别、自动驾驶 +- **自然语言处理(NLP)**:机器翻译、情感分析、问答系统、ChatGPT +- **语音识别**:语音转文字、语音助手、声纹识别 +- **推荐系统**:电商推荐、内容推荐、广告投放 +- **机器人学**:工业机器人、服务机器人、无人机 + +## 5. 核心概念解析 + +### 5.1 模型(Model) + +模型是机器学习的核心,它是从数据中学习到的规律的数学表示。简单来说: + +``` +输入(X) → 模型(f) → 输出(Y) +``` + +- 模型接收输入数据,产生预测结果 +- 模型通过训练过程从数据中学习参数 +- 不同的模型适用于不同类型的问题 + +### 5.2 训练与推理 + +| 阶段 | 描述 | 计算需求 | +|------|------|----------| +| **训练(Training)** | 使用训练数据调整模型参数 | 高(需要大量计算和数据) | +| **推理(Inference)** | 使用训练好的模型进行预测 | 相对低 | + +### 5.3 过拟合与欠拟合 + +- **过拟合(Overfitting)**:模型在训练数据上表现很好,但在新数据上表现差。就像死记硬背考试答案,换个题就不会了。 +- **欠拟合(Underfitting)**:模型太简单,无法捕捉数据中的规律。就像只学了皮毛,理解不深入。 + +### 5.4 损失函数与优化 + +- **损失函数(Loss Function)**:衡量模型预测值与真实值之间差距的函数。训练的目标是最小化损失。 +- **优化器(Optimizer)**:用于更新模型参数以减小损失的算法。最常用的是梯度下降及其变体。 + +## 6. AI的现实应用 + +AI已经深入我们生活的方方面面: + +- **智能手机**:人脸解锁、语音助手、照片增强 +- **社交媒体**:内容推荐、广告定向、内容审核 +- **电商**:商品推荐、智能客服、价格优化 +- **医疗**:医学影像分析、疾病预测、药物研发 +- **交通**:自动驾驶、路线优化、交通预测 +- **金融**:风控评估、量化交易、欺诈检测 + +## 7. 学习AI需要什么? + +::: tip 技能要求 +- **编程能力**:Python是首选语言(你已经具备!) +- **数学基础**:线性代数、微积分、概率统计(前一章已覆盖) +- **数据处理能力**:NumPy、Pandas、数据清洗(前一章已覆盖) +- **算法思维**:理解算法原理,不只是调用API +- **实践经验**:多做项目,在实践中学习 +::: + +## 8. 本章小结 + +- 人工智能是让机器表现出智能行为的技术,机器学习和深度学习是其子集 +- AI经历了三次浪潮,当前处于深度学习和大模型驱动的第三次浪潮 +- 机器学习主要分为监督学习、无监督学习和强化学习三种范式 +- 理解模型、训练、过拟合等核心概念是学习AI的基础 +- AI已广泛应用于各行各业,是当今最热门的技术领域之一 diff --git a/docs/chapters/deep-learning/neural-networks.md b/docs/chapters/deep-learning/neural-networks.md new file mode 100644 index 0000000..3eb7db6 --- /dev/null +++ b/docs/chapters/deep-learning/neural-networks.md @@ -0,0 +1,302 @@ +# 神经网络基础 + +::: info 本章概述 +神经网络是深度学习的基础。本章将介绍神经网络的核心概念:感知机、激活函数、前向传播和反向传播算法。 +::: + +## 1. 从感知机到神经网络 + +### 1.1 感知机(Perceptron) + +感知机是最简单的神经网络模型,由Frank Rosenblatt于1957年提出。它模拟了生物神经元的工作方式。 + +$$y = \begin{cases} 1 & \text{if } \sum_{i} w_i x_i + b > 0 \\ 0 & \text{otherwise} \end{cases}$$ + +``` + x₁ ─────┐ + │ w₁ + x₂ ─────┼──────►[Σ]──────►[激活]──────► y + │ w₂ + x₃ ─────┘ + w₃ +``` + +### 1.2 多层感知机(MLP) + +单层感知机只能解决线性可分问题。通过堆叠多层神经元,我们可以学习复杂的非线性关系。 + +``` +输入层 隐藏层1 隐藏层2 输出层 + ●──────────●───────────●──────────● + ●──────────●───────────●──────────● + ●──────────●───────────● + ●───────────● +``` + +## 2. 激活函数 + +激活函数引入非线性,使神经网络能够学习复杂模式。 + +### 2.1 常用激活函数 + +| 函数 | 公式 | 特点 | +|------|------|------| +| **Sigmoid** | $\sigma(x) = \frac{1}{1+e^{-x}}$ | 输出(0,1),易梯度消失 | +| **Tanh** | $\tanh(x) = \frac{e^x - e^{-x}}{e^x + e^{-x}}$ | 输出(-1,1),零中心化 | +| **ReLU** | $f(x) = \max(0, x)$ | 计算简单,最常用 | +| **Leaky ReLU** | $f(x) = \max(0.01x, x)$ | 解决ReLU死神经元问题 | +| **Softmax** | $\sigma(x_i) = \frac{e^{x_i}}{\sum_j e^{x_j}}$ | 多分类输出层 | + +```python +import numpy as np + +# 激活函数实现 +def sigmoid(x): + return 1 / (1 + np.exp(-x)) + +def tanh(x): + return np.tanh(x) + +def relu(x): + return np.maximum(0, x) + +def leaky_relu(x, alpha=0.01): + return np.where(x > 0, x, alpha * x) + +def softmax(x): + exp_x = np.exp(x - np.max(x)) # 数值稳定性 + return exp_x / np.sum(exp_x) + +# 导数(用于反向传播) +def sigmoid_derivative(x): + s = sigmoid(x) + return s * (1 - s) + +def relu_derivative(x): + return np.where(x > 0, 1, 0) +``` + +## 3. 前向传播 + +前向传播是数据从输入层经过隐藏层到输出层的计算过程。 + +$$\mathbf{z}^{[l]} = \mathbf{W}^{[l]}\mathbf{a}^{[l-1]} + \mathbf{b}^{[l]}$$ + +$$\mathbf{a}^{[l]} = g^{[l]}(\mathbf{z}^{[l]})$$ + +```python +class NeuralNetwork: + def __init__(self, layer_dims): + """ + layer_dims: 各层神经元数量,如 [784, 128, 64, 10] + """ + self.L = len(layer_dims) - 1 # 层数 + self.parameters = {} + + # 初始化参数(He初始化) + for l in range(1, self.L + 1): + self.parameters[f'W{l}'] = np.random.randn( + layer_dims[l], layer_dims[l-1] + ) * np.sqrt(2 / layer_dims[l-1]) + self.parameters[f'b{l}'] = np.zeros((layer_dims[l], 1)) + + def forward(self, X): + """前向传播""" + self.cache = {'A0': X} + A = X + + for l in range(1, self.L + 1): + W = self.parameters[f'W{l}'] + b = self.parameters[f'b{l}'] + + Z = np.dot(W, A) + b + + # 最后一层用softmax,其他用ReLU + if l == self.L: + A = self.softmax(Z) + else: + A = np.maximum(0, Z) # ReLU + + self.cache[f'Z{l}'] = Z + self.cache[f'A{l}'] = A + + return A + + def softmax(self, Z): + exp_Z = np.exp(Z - np.max(Z, axis=0, keepdims=True)) + return exp_Z / np.sum(exp_Z, axis=0, keepdims=True) +``` + +## 4. 反向传播 + +反向传播是计算损失函数对每个参数梯度的算法,基于链式法则。 + +### 4.1 链式法则回顾 + +$$\frac{\partial L}{\partial w} = \frac{\partial L}{\partial a} \cdot \frac{\partial a}{\partial z} \cdot \frac{\partial z}{\partial w}$$ + +### 4.2 反向传播公式 + +对于输出层(交叉熵损失 + Softmax): + +$$\mathbf{dZ}^{[L]} = \mathbf{A}^{[L]} - \mathbf{Y}$$ + +对于隐藏层(ReLU激活): + +$$\mathbf{dZ}^{[l]} = \mathbf{W}^{[l+1]T}\mathbf{dZ}^{[l+1]} * g'^{[l]}(\mathbf{Z}^{[l]})$$ + +参数梯度: + +$$\mathbf{dW}^{[l]} = \frac{1}{m}\mathbf{dZ}^{[l]}\mathbf{A}^{[l-1]T}$$ + +$$\mathbf{db}^{[l]} = \frac{1}{m}\sum\mathbf{dZ}^{[l]}$$ + +```python +def backward(self, Y): + """反向传播""" + m = Y.shape[1] + grads = {} + + # 输出层梯度 + dZ = self.cache[f'A{self.L}'] - Y + + for l in reversed(range(1, self.L + 1)): + A_prev = self.cache[f'A{l-1}'] + + grads[f'dW{l}'] = (1/m) * np.dot(dZ, A_prev.T) + grads[f'db{l}'] = (1/m) * np.sum(dZ, axis=1, keepdims=True) + + if l > 1: + W = self.parameters[f'W{l}'] + dA = np.dot(W.T, dZ) + # ReLU导数 + dZ = dA * (self.cache[f'Z{l-1}'] > 0) + + return grads + +def update_parameters(self, grads, learning_rate): + """更新参数""" + for l in range(1, self.L + 1): + self.parameters[f'W{l}'] -= learning_rate * grads[f'dW{l}'] + self.parameters[f'b{l}'] -= learning_rate * grads[f'db{l}'] +``` + +## 5. 完整实现示例 + +```python +import numpy as np +from sklearn.datasets import make_moons +from sklearn.model_selection import train_test_split +import matplotlib.pyplot as plt + +# 生成数据 +X, y = make_moons(n_samples=1000, noise=0.2, random_state=42) +X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2) + +# 转换为正确的形状 +X_train = X_train.T # (2, 800) +X_test = X_test.T # (2, 200) +y_train = y_train.reshape(1, -1) # (1, 800) +y_test = y_test.reshape(1, -1) # (1, 200) + +class SimpleNN: + def __init__(self, n_input, n_hidden, n_output): + # He初始化 + self.W1 = np.random.randn(n_hidden, n_input) * np.sqrt(2/n_input) + self.b1 = np.zeros((n_hidden, 1)) + self.W2 = np.random.randn(n_output, n_hidden) * np.sqrt(2/n_hidden) + self.b2 = np.zeros((n_output, 1)) + + def forward(self, X): + self.Z1 = np.dot(self.W1, X) + self.b1 + self.A1 = np.maximum(0, self.Z1) # ReLU + self.Z2 = np.dot(self.W2, self.A1) + self.b2 + self.A2 = 1 / (1 + np.exp(-self.Z2)) # Sigmoid + return self.A2 + + def compute_loss(self, Y, A2): + m = Y.shape[1] + loss = -np.mean(Y * np.log(A2 + 1e-8) + (1-Y) * np.log(1-A2 + 1e-8)) + return loss + + def backward(self, X, Y): + m = X.shape[1] + + dZ2 = self.A2 - Y + dW2 = (1/m) * np.dot(dZ2, self.A1.T) + db2 = (1/m) * np.sum(dZ2, axis=1, keepdims=True) + + dA1 = np.dot(self.W2.T, dZ2) + dZ1 = dA1 * (self.Z1 > 0) + dW1 = (1/m) * np.dot(dZ1, X.T) + db1 = (1/m) * np.sum(dZ1, axis=1, keepdims=True) + + return dW1, db1, dW2, db2 + + def update(self, grads, lr): + dW1, db1, dW2, db2 = grads + self.W1 -= lr * dW1 + self.b1 -= lr * db1 + self.W2 -= lr * dW2 + self.b2 -= lr * db2 + + def train(self, X, Y, epochs, lr): + losses = [] + for epoch in range(epochs): + A2 = self.forward(X) + loss = self.compute_loss(Y, A2) + grads = self.backward(X, Y) + self.update(grads, lr) + losses.append(loss) + if epoch % 100 == 0: + print(f"Epoch {epoch}, Loss: {loss:.4f}") + return losses + + def predict(self, X): + A2 = self.forward(X) + return (A2 > 0.5).astype(int) + +# 训练 +nn = SimpleNN(n_input=2, n_hidden=16, n_output=1) +losses = nn.train(X_train, y_train, epochs=1000, lr=0.5) + +# 评估 +predictions = nn.predict(X_test) +accuracy = np.mean(predictions == y_test) +print(f"\n测试集准确率: {accuracy:.4f}") +``` + +## 6. 常见问题与解决方案 + +### 6.1 梯度消失/爆炸 + +| 问题 | 原因 | 解决方案 | +|------|------|----------| +| 梯度消失 | Sigmoid/Tanh在饱和区梯度接近0 | 使用ReLU激活函数 | +| 梯度爆炸 | 权重过大导致梯度累积 | 梯度裁剪、BatchNorm | + +### 6.2 过拟合 + +- **正则化**:L1/L2正则化 +- **Dropout**:随机丢弃神经元 +- **数据增强**:增加训练数据 +- **早停**:验证集性能不再提升时停止训练 + +### 6.3 参数初始化 + +| 方法 | 公式 | 适用场景 | +|------|------|----------| +| Xavier | $\mathcal{N}(0, \frac{1}{n_{in}})$ | Tanh/Sigmoid | +| He | $\mathcal{N}(0, \frac{2}{n_{in}})$ | ReLU | + +## 7. 本章小结 + +- **感知机** 是神经网络的基本单元 +- **激活函数** 引入非线性,ReLU是最常用的选择 +- **前向传播** 计算网络输出 +- **反向传播** 利用链式法则计算梯度 +- 理解这些基础对于使用深度学习框架至关重要 + +::: tip 下一步 +掌握了神经网络基础后,可以学习PyTorch或TensorFlow等深度学习框架,它们会自动处理反向传播和参数更新。 +::: diff --git a/docs/chapters/machine-learning/linear-regression.md b/docs/chapters/machine-learning/linear-regression.md new file mode 100644 index 0000000..ff72f0f --- /dev/null +++ b/docs/chapters/machine-learning/linear-regression.md @@ -0,0 +1,286 @@ +# 线性回归 + +::: info 本章概述 +线性回归是最基础的机器学习算法,理解它对于掌握更复杂的模型至关重要。本章将从原理讲起,手把手实现梯度下降,并使用sklearn进行实战。 +::: + +## 1. 什么是线性回归 + +线性回归是一种用于预测连续数值的监督学习算法。它假设输入特征和输出之间存在线性关系。 + +### 1.1 一元线性回归 + +最简单的情况是只有一个特征的线性回归: + +$$y = wx + b$$ + +- $y$ - 预测值(目标变量) +- $x$ - 输入特征 +- $w$ - 权重(斜率) +- $b$ - 偏置(截距) + +### 1.2 多元线性回归 + +当有多个特征时: + +$$y = w_1x_1 + w_2x_2 + ... + w_nx_n + b = \mathbf{w}^T\mathbf{x} + b$$ + +用矩阵形式表示更简洁。 + +## 2. 损失函数 + +为了训练模型,我们需要一个衡量预测好坏的指标——损失函数。线性回归通常使用**均方误差(MSE)**: + +$$L(w, b) = \frac{1}{m}\sum_{i=1}^{m}(y_i - \hat{y}_i)^2 = \frac{1}{m}\sum_{i=1}^{m}(y_i - (wx_i + b))^2$$ + +其中 $m$ 是样本数量,$y_i$ 是真实值,$\hat{y}_i$ 是预测值。 + +::: tip 为什么用平方? +- 平方可以放大大误差,使模型更关注大偏差 +- 平方使正负误差不会相互抵消 +- 平方函数可导,便于优化 +::: + +## 3. 梯度下降 + +梯度下降是求解最优参数的核心算法。其思想是:沿着损失函数梯度的反方向更新参数,逐步找到最小值。 + +### 3.1 算法步骤 + +1. 随机初始化参数 $w$ 和 $b$ +2. 计算损失函数对参数的梯度 +3. 更新参数:$w = w - \eta \frac{\partial L}{\partial w}$ +4. 重复步骤2-3直到收敛 + +### 3.2 梯度计算 + +对于一元线性回归,梯度公式为: + +$$\frac{\partial L}{\partial w} = \frac{2}{m}\sum_{i=1}^{m}(wx_i + b - y_i)x_i$$ + +$$\frac{\partial L}{\partial b} = \frac{2}{m}\sum_{i=1}^{m}(wx_i + b - y_i)$$ + +## 4. 从零实现线性回归 + +```python +import numpy as np +import matplotlib.pyplot as plt + +# 生成模拟数据 +np.random.seed(42) +X = 2 * np.random.rand(100, 1) +y = 4 + 3 * X + np.random.randn(100, 1) # y = 4 + 3x + 噪声 + +# 可视化数据 +plt.scatter(X, y, alpha=0.6) +plt.xlabel('X') +plt.ylabel('y') +plt.title('训练数据') +plt.show() + +class LinearRegressionScratch: + def __init__(self, learning_rate=0.01, n_iterations=1000): + self.lr = learning_rate + self.n_iterations = n_iterations + self.w = None + self.b = None + self.losses = [] + + def fit(self, X, y): + m, n_features = X.shape + + # 初始化参数 + self.w = np.zeros((n_features, 1)) + self.b = 0 + + # 梯度下降 + for i in range(self.n_iterations): + # 预测 + y_pred = np.dot(X, self.w) + self.b + + # 计算损失 + loss = np.mean((y - y_pred) ** 2) + self.losses.append(loss) + + # 计算梯度 + dw = -(2/m) * np.dot(X.T, (y - y_pred)) + db = -(2/m) * np.sum(y - y_pred) + + # 更新参数 + self.w -= self.lr * dw + self.b -= self.lr * db + + if i % 100 == 0: + print(f"Iteration {i}, Loss: {loss:.4f}") + + return self + + def predict(self, X): + return np.dot(X, self.w) + self.b + +# 训练模型 +model = LinearRegressionScratch(learning_rate=0.1, n_iterations=1000) +model.fit(X, y) + +print(f"\n学习到的参数:") +print(f"w = {model.w[0][0]:.4f} (真实值: 3)") +print(f"b = {model.b:.4f} (真实值: 4)") + +# 绘制结果 +plt.figure(figsize=(12, 4)) + +# 拟合曲线 +plt.subplot(1, 2, 1) +plt.scatter(X, y, alpha=0.6, label='数据点') +plt.plot(X, model.predict(X), color='red', label='拟合线') +plt.xlabel('X') +plt.ylabel('y') +plt.title('线性回归拟合结果') +plt.legend() + +# 损失曲线 +plt.subplot(1, 2, 2) +plt.plot(model.losses) +plt.xlabel('Iteration') +plt.ylabel('Loss') +plt.title('训练损失曲线') + +plt.tight_layout() +plt.show() +``` + +## 5. 使用sklearn实现 + +在实际项目中,我们通常使用成熟的库而不是从零实现: + +```python +from sklearn.linear_model import LinearRegression +from sklearn.model_selection import train_test_split +from sklearn.metrics import mean_squared_error, r2_score +import numpy as np + +# 生成数据 +np.random.seed(42) +X = 2 * np.random.rand(100, 1) +y = 4 + 3 * X.flatten() + np.random.randn(100) + +# 划分训练集和测试集 +X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) + +# 创建并训练模型 +model = LinearRegression() +model.fit(X_train, y_train) + +# 预测 +y_pred = model.predict(X_test) + +# 评估 +print(f"权重 w: {model.coef_[0]:.4f}") +print(f"偏置 b: {model.intercept_:.4f}") +print(f"MSE: {mean_squared_error(y_test, y_pred):.4f}") +print(f"R² Score: {r2_score(y_test, y_pred):.4f}") +``` + +## 6. 多元线性回归实战 + +使用加州房价数据集进行多特征回归: + +```python +from sklearn.datasets import fetch_california_housing +from sklearn.linear_model import LinearRegression +from sklearn.model_selection import train_test_split +from sklearn.preprocessing import StandardScaler +from sklearn.metrics import mean_squared_error, r2_score +import pandas as pd +import numpy as np + +# 加载加州房价数据集 +housing = fetch_california_housing() +X = pd.DataFrame(housing.data, columns=housing.feature_names) +y = housing.target + +print("特征名称:", housing.feature_names) +print("数据形状:", X.shape) +print("\n数据预览:") +print(X.head()) + +# 划分数据 +X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) + +# 特征标准化 +scaler = StandardScaler() +X_train_scaled = scaler.fit_transform(X_train) +X_test_scaled = scaler.transform(X_test) + +# 训练模型 +model = LinearRegression() +model.fit(X_train_scaled, y_train) + +# 预测和评估 +y_pred = model.predict(X_test_scaled) +print(f"\nMSE: {mean_squared_error(y_test, y_pred):.4f}") +print(f"RMSE: {np.sqrt(mean_squared_error(y_test, y_pred)):.4f}") +print(f"R² Score: {r2_score(y_test, y_pred):.4f}") + +# 特征重要性 +importance = pd.DataFrame({ + 'Feature': housing.feature_names, + 'Coefficient': model.coef_ +}).sort_values('Coefficient', key=abs, ascending=False) +print("\n特征系数(绝对值排序):") +print(importance) +``` + +## 7. 正则化 + +当特征很多时,模型容易过拟合。正则化通过限制参数大小来防止过拟合。 + +### 7.1 Ridge回归(L2正则化) + +$$L = \frac{1}{m}\sum_{i=1}^{m}(y_i - \hat{y}_i)^2 + \alpha\sum_{j=1}^{n}w_j^2$$ + +### 7.2 Lasso回归(L1正则化) + +$$L = \frac{1}{m}\sum_{i=1}^{m}(y_i - \hat{y}_i)^2 + \alpha\sum_{j=1}^{n}|w_j|$$ + +```python +from sklearn.linear_model import Ridge, Lasso, ElasticNet + +# Ridge回归 +ridge = Ridge(alpha=1.0) +ridge.fit(X_train_scaled, y_train) +print(f"Ridge R²: {ridge.score(X_test_scaled, y_test):.4f}") + +# Lasso回归 +lasso = Lasso(alpha=0.1) +lasso.fit(X_train_scaled, y_train) +print(f"Lasso R²: {lasso.score(X_test_scaled, y_test):.4f}") + +# ElasticNet(L1和L2的组合) +elastic = ElasticNet(alpha=0.1, l1_ratio=0.5) +elastic.fit(X_train_scaled, y_train) +print(f"ElasticNet R²: {elastic.score(X_test_scaled, y_test):.4f}") +``` + +::: tip 正则化选择 +- **Ridge**:特征多且都有一定贡献时使用 +- **Lasso**:需要特征选择时使用(会使部分系数变为0) +- **ElasticNet**:结合两者优点 +::: + +## 8. 学习率的影响 + +| 学习率 | 效果 | 问题 | +|--------|------|------| +| 太小(0.0001) | 收敛很慢 | 需要很多迭代 | +| 适中(0.01-0.1) | 稳定收敛 | 理想选择 | +| 太大(1.0) | 不收敛 | 损失震荡或发散 | + +## 9. 本章小结 + +- **线性回归** 假设特征和目标之间存在线性关系 +- **损失函数**(MSE)衡量预测与真实值的差距 +- **梯度下降** 通过迭代更新参数来最小化损失 +- **学习率** 控制每次更新的步长,需要适当选择 +- **正则化**(Ridge/Lasso)防止过拟合 +- 实际项目中使用sklearn等成熟库,但理解原理很重要 diff --git a/docs/chapters/prerequisites/data-processing.md b/docs/chapters/prerequisites/data-processing.md new file mode 100644 index 0000000..c28e478 --- /dev/null +++ b/docs/chapters/prerequisites/data-processing.md @@ -0,0 +1,378 @@ +# 数据处理基础 + +::: info 本章概述 +在机器学习中,"数据决定上限,模型决定下限"。本章介绍数据预处理和特征工程的基本方法,这些技能在实际项目中至关重要。 +::: + +## 1. 数据预处理概述 + +真实世界的数据往往是"脏"的,需要经过清洗和转换才能用于模型训练。数据预处理的质量直接影响模型的性能。 + +### 1.1 数据质量问题 + +| 问题类型 | 描述 | 处理方法 | +|----------|------|----------| +| 缺失值 | 数据中存在空值或NaN | 删除、填充、插值 | +| 异常值 | 极端偏离正常范围的值 | 检测并处理或删除 | +| 重复值 | 相同的记录出现多次 | 去重 | +| 类型错误 | 数据类型不正确 | 类型转换 | +| 格式不一致 | 同类数据格式不统一 | 标准化格式 | + +## 2. 缺失值处理 + +### 2.1 检测缺失值 + +```python +import pandas as pd +import numpy as np + +# 创建包含缺失值的数据 +df = pd.DataFrame({ + 'age': [25, 30, np.nan, 35, 40], + 'salary': [50000, np.nan, 60000, np.nan, 80000], + 'city': ['北京', '上海', None, '广州', '深圳'] +}) + +# 检测缺失值 +print(df.isnull()) # 返回布尔矩阵 +print(df.isnull().sum()) # 每列缺失值数量 +print(df.isnull().sum().sum()) # 总缺失值数量 + +# 缺失值比例 +missing_ratio = df.isnull().sum() / len(df) +print(missing_ratio) +``` + +### 2.2 处理缺失值 + +```python +# 方法1:删除 +df_dropped = df.dropna() # 删除任何含缺失值的行 +df_dropped = df.dropna(subset=['age']) # 只考虑特定列 + +# 方法2:填充固定值 +df['age'] = df['age'].fillna(0) +df['city'] = df['city'].fillna('未知') + +# 方法3:统计量填充 +df['age'] = df['age'].fillna(df['age'].mean()) # 均值 +df['salary'] = df['salary'].fillna(df['salary'].median()) # 中位数 +df['city'] = df['city'].fillna(df['city'].mode()[0]) # 众数 + +# 方法4:前向/后向填充(时序数据) +df['value'] = df['value'].fillna(method='ffill') # 前向填充 +df['value'] = df['value'].fillna(method='bfill') # 后向填充 + +# 方法5:插值 +df['value'] = df['value'].interpolate(method='linear') +``` + +::: warning 注意事项 +选择缺失值处理方法时要考虑: +1. 缺失的原因(随机缺失 vs 系统性缺失) +2. 缺失比例(高于30%可能需要删除该特征) +3. 业务含义(有时缺失本身就是有意义的信息) +::: + +## 3. 异常值处理 + +### 3.1 检测异常值 + +```python +import numpy as np +import pandas as pd + +# 创建示例数据 +np.random.seed(42) +data = np.random.randn(100) * 10 + 50 +data[0] = 200 # 添加异常值 +data[50] = -50 + +df = pd.DataFrame({'value': data}) + +# 方法1:统计方法(3σ原则) +mean = df['value'].mean() +std = df['value'].std() +outliers_3sigma = df[(df['value'] < mean - 3*std) | (df['value'] > mean + 3*std)] +print(f"3σ异常值数量: {len(outliers_3sigma)}") + +# 方法2:IQR方法(箱线图原理) +Q1 = df['value'].quantile(0.25) +Q3 = df['value'].quantile(0.75) +IQR = Q3 - Q1 +lower = Q1 - 1.5 * IQR +upper = Q3 + 1.5 * IQR +outliers_iqr = df[(df['value'] < lower) | (df['value'] > upper)] +print(f"IQR异常值数量: {len(outliers_iqr)}") +``` + +### 3.2 处理异常值 + +```python +# 方法1:删除异常值 +df_cleaned = df[(df['value'] >= lower) & (df['value'] <= upper)] + +# 方法2:截断(Winsorization) +df['value_clipped'] = df['value'].clip(lower=lower, upper=upper) + +# 方法3:替换为边界值 +df.loc[df['value'] < lower, 'value'] = lower +df.loc[df['value'] > upper, 'value'] = upper + +# 方法4:用缺失值代替,再填充 +df.loc[df['value'] < lower, 'value'] = np.nan +df['value'] = df['value'].fillna(df['value'].median()) +``` + +## 4. 特征缩放 + +不同特征的量纲可能差异很大,这会影响某些算法(如梯度下降、KNN、SVM)的性能。 + +### 4.1 标准化(Standardization) + +将数据转换为均值为0,标准差为1的分布: + +```python +from sklearn.preprocessing import StandardScaler + +# 创建示例数据 +data = np.array([[1, 10000], [2, 20000], [3, 30000], [4, 40000]]) +df = pd.DataFrame(data, columns=['feature1', 'feature2']) + +# 使用StandardScaler +scaler = StandardScaler() +scaled_data = scaler.fit_transform(df) + +print("原始数据:") +print(df) +print("\n标准化后:") +print(pd.DataFrame(scaled_data, columns=['feature1', 'feature2'])) +``` + +### 4.2 归一化(Min-Max Scaling) + +将数据缩放到[0, 1]范围: + +```python +from sklearn.preprocessing import MinMaxScaler + +scaler = MinMaxScaler() +normalized_data = scaler.fit_transform(df) + +print("归一化后:") +print(pd.DataFrame(normalized_data, columns=['feature1', 'feature2'])) +# 所有值都在[0, 1]范围内 +``` + +::: tip 何时使用哪种方法? +- **标准化:** 数据近似正态分布,或算法假设数据是正态分布(如逻辑回归、神经网络) +- **归一化:** 需要有界数据,或使用距离计算的算法(如KNN、神经网络的图像输入) +- **不缩放:** 决策树、随机森林等基于规则的算法对特征缩放不敏感 +::: + +## 5. 类别特征编码 + +机器学习算法通常需要数值输入,因此需要将类别特征转换为数值。 + +### 5.1 标签编码(Label Encoding) + +```python +from sklearn.preprocessing import LabelEncoder + +# 适用于有序类别 +df = pd.DataFrame({ + 'size': ['small', 'medium', 'large', 'medium', 'small'] +}) + +le = LabelEncoder() +df['size_encoded'] = le.fit_transform(df['size']) +print(df) +# small -> 2, medium -> 1, large -> 0(按字母顺序) + +# 查看映射 +print(dict(zip(le.classes_, range(len(le.classes_))))) +``` + +### 5.2 独热编码(One-Hot Encoding) + +```python +from sklearn.preprocessing import OneHotEncoder +import pandas as pd + +# 适用于无序类别 +df = pd.DataFrame({ + 'color': ['red', 'blue', 'green', 'red', 'blue'] +}) + +# 使用pandas +df_encoded = pd.get_dummies(df, columns=['color'], prefix='color') +print(df_encoded) +# color_blue color_green color_red +# 0 0 0 1 +# 1 1 0 0 +# 2 0 1 0 +# ... + +# 使用sklearn +encoder = OneHotEncoder(sparse_output=False) +encoded = encoder.fit_transform(df[['color']]) +print(encoded) +``` + +### 5.3 目标编码(Target Encoding) + +```python +# 用于高基数类别特征(类别数量很多) +df = pd.DataFrame({ + 'city': ['北京', '上海', '北京', '广州', '上海', '北京'], + 'target': [1, 0, 1, 0, 1, 1] +}) + +# 计算每个类别的目标均值 +target_mean = df.groupby('city')['target'].mean() +df['city_encoded'] = df['city'].map(target_mean) +print(df) +``` + +## 6. 特征工程入门 + +特征工程是利用领域知识从原始数据中创造新特征的过程,好的特征可以显著提升模型性能。 + +### 6.1 特征创建 + +```python +import pandas as pd +import numpy as np + +# 原始数据 +df = pd.DataFrame({ + 'length': [10, 20, 15, 25], + 'width': [5, 10, 8, 12], + 'date': pd.to_datetime(['2024-01-15', '2024-03-20', '2024-06-10', '2024-12-25']) +}) + +# 数值特征组合 +df['area'] = df['length'] * df['width'] # 面积 +df['perimeter'] = 2 * (df['length'] + df['width']) # 周长 +df['ratio'] = df['length'] / df['width'] # 长宽比 + +# 日期特征提取 +df['year'] = df['date'].dt.year +df['month'] = df['date'].dt.month +df['day'] = df['date'].dt.day +df['dayofweek'] = df['date'].dt.dayofweek # 0=周一 +df['is_weekend'] = df['dayofweek'].isin([5, 6]).astype(int) +df['quarter'] = df['date'].dt.quarter + +print(df) +``` + +### 6.2 特征分箱(Binning) + +```python +# 将连续变量离散化 +df = pd.DataFrame({ + 'age': [22, 35, 45, 18, 60, 28, 55] +}) + +# 等宽分箱 +df['age_bin_equal'] = pd.cut(df['age'], bins=3, labels=['young', 'middle', 'old']) + +# 自定义分箱 +bins = [0, 25, 40, 60, 100] +labels = ['青年', '中年', '中老年', '老年'] +df['age_group'] = pd.cut(df['age'], bins=bins, labels=labels) + +# 等频分箱(每个箱的样本数相近) +df['age_quantile'] = pd.qcut(df['age'], q=3, labels=['low', 'medium', 'high']) + +print(df) +``` + +### 6.3 特征选择 + +```python +from sklearn.feature_selection import SelectKBest, f_classif +from sklearn.ensemble import RandomForestClassifier +import numpy as np + +# 生成示例数据 +np.random.seed(42) +X = np.random.randn(100, 10) +y = (X[:, 0] + X[:, 1] > 0).astype(int) # 只有前两个特征有用 + +# 方法1:基于统计的特征选择 +selector = SelectKBest(f_classif, k=5) +X_selected = selector.fit_transform(X, y) +print(f"选择的特征索引: {selector.get_support(indices=True)}") + +# 方法2:基于模型的特征重要性 +rf = RandomForestClassifier(n_estimators=100, random_state=42) +rf.fit(X, y) + +# 特征重要性 +importance = pd.DataFrame({ + 'feature': [f'feature_{i}' for i in range(10)], + 'importance': rf.feature_importances_ +}).sort_values('importance', ascending=False) +print(importance) +``` + +## 7. 数据预处理流水线 + +在实际项目中,通常使用Pipeline将多个预处理步骤组合起来。 + +```python +from sklearn.pipeline import Pipeline +from sklearn.compose import ColumnTransformer +from sklearn.preprocessing import StandardScaler, OneHotEncoder +from sklearn.impute import SimpleImputer + +# 定义数值和类别特征 +numeric_features = ['age', 'salary'] +categorical_features = ['city', 'gender'] + +# 数值特征处理流水线 +numeric_transformer = Pipeline(steps=[ + ('imputer', SimpleImputer(strategy='median')), # 填充缺失值 + ('scaler', StandardScaler()) # 标准化 +]) + +# 类别特征处理流水线 +categorical_transformer = Pipeline(steps=[ + ('imputer', SimpleImputer(strategy='constant', fill_value='missing')), + ('onehot', OneHotEncoder(handle_unknown='ignore')) +]) + +# 组合处理器 +preprocessor = ColumnTransformer( + transformers=[ + ('num', numeric_transformer, numeric_features), + ('cat', categorical_transformer, categorical_features) + ]) + +# 完整的机器学习流水线 +from sklearn.linear_model import LogisticRegression + +full_pipeline = Pipeline(steps=[ + ('preprocessor', preprocessor), + ('classifier', LogisticRegression()) +]) + +# 使用流水线 +# full_pipeline.fit(X_train, y_train) +# predictions = full_pipeline.predict(X_test) +``` + +::: danger 重要提示 +预处理操作必须先在训练集上fit,然后用同样的参数transform测试集。使用Pipeline可以避免数据泄露(data leakage)问题。 +::: + +## 8. 本章小结 + +- **缺失值处理:** 根据数据特点选择删除、填充或插值 +- **异常值处理:** 使用统计方法检测,选择合适的处理策略 +- **特征缩放:** 标准化和归一化是最常用的方法 +- **类别编码:** 标签编码用于有序类别,独热编码用于无序类别 +- **特征工程:** 创造新特征、分箱、特征选择等技术 +- **Pipeline:** 组织预处理步骤,确保一致性 diff --git a/docs/chapters/prerequisites/math.md b/docs/chapters/prerequisites/math.md new file mode 100644 index 0000000..0674dd1 --- /dev/null +++ b/docs/chapters/prerequisites/math.md @@ -0,0 +1,244 @@ +# 数学基础 + +::: info 本章概述 +数学是机器学习和深度学习的基础。本章将帮助你回顾并补充AI学习所需的核心数学知识,包括线性代数、微积分和概率统计。 +::: + +## 1. 线性代数基础 + +线性代数是机器学习中最重要的数学工具之一。几乎所有的机器学习算法都涉及到向量和矩阵运算。 + +### 1.1 向量 (Vector) + +向量是一个有序的数字列表,可以表示为列向量或行向量。在机器学习中,向量常用于表示数据特征。 + +$$\vec{x} = \begin{bmatrix} x_1 \\ x_2 \\ \vdots \\ x_n \end{bmatrix}$$ + +**常用向量运算:** + +- **向量加法:** 对应元素相加 +- **标量乘法:** 每个元素乘以标量 +- **点积(内积):** $\vec{a} \cdot \vec{b} = \sum_{i=1}^{n} a_i b_i$ +- **向量范数:** $||\vec{x}||_2 = \sqrt{\sum_{i=1}^{n} x_i^2}$(L2范数) + +```python +import numpy as np + +# 创建向量 +a = np.array([1, 2, 3]) +b = np.array([4, 5, 6]) + +# 向量加法 +print(a + b) # [5 7 9] + +# 标量乘法 +print(2 * a) # [2 4 6] + +# 点积 +print(np.dot(a, b)) # 32 + +# L2范数 +print(np.linalg.norm(a)) # 3.7416... +``` + +### 1.2 矩阵 (Matrix) + +矩阵是一个二维数组,在机器学习中用于表示数据集、权重参数等。 + +$$A = \begin{bmatrix} a_{11} & a_{12} & \cdots & a_{1n} \\ a_{21} & a_{22} & \cdots & a_{2n} \\ \vdots & \vdots & \ddots & \vdots \\ a_{m1} & a_{m2} & \cdots & a_{mn} \end{bmatrix}$$ + +**常用矩阵运算:** + +| 运算 | 描述 | 条件 | +|------|------|------| +| 矩阵加法 | 对应元素相加 | 相同形状 | +| 矩阵乘法 | $C_{ij} = \sum_k A_{ik} B_{kj}$ | A的列数 = B的行数 | +| 转置 | 行列互换 $A^T$ | 任意矩阵 | +| 逆矩阵 | $A^{-1}A = I$ | 方阵且可逆 | + +```python +import numpy as np + +# 创建矩阵 +A = np.array([[1, 2], [3, 4]]) +B = np.array([[5, 6], [7, 8]]) + +# 矩阵乘法 +print(np.dot(A, B)) +# [[19 22] +# [43 50]] + +# 转置 +print(A.T) +# [[1 3] +# [2 4]] + +# 逆矩阵 +print(np.linalg.inv(A)) +# [[-2. 1. ] +# [ 1.5 -0.5]] + +# 特征值和特征向量 +eigenvalues, eigenvectors = np.linalg.eig(A) +print("特征值:", eigenvalues) +``` + +::: tip 为什么重要? +在神经网络中,前向传播本质上就是矩阵乘法:$y = Wx + b$,其中W是权重矩阵,x是输入向量,b是偏置向量。 +::: + +## 2. 微积分基础 + +微积分在机器学习中主要用于优化算法,特别是梯度下降法。理解导数和偏导数对于理解模型训练过程至关重要。 + +### 2.1 导数 (Derivative) + +导数表示函数在某一点的变化率,几何意义是曲线在该点的切线斜率。 + +$$f'(x) = \lim_{h \to 0} \frac{f(x+h) - f(x)}{h}$$ + +**常用导数公式:** + +- $\frac{d}{dx}(x^n) = nx^{n-1}$ +- $\frac{d}{dx}(e^x) = e^x$ +- $\frac{d}{dx}(\ln x) = \frac{1}{x}$ +- $\frac{d}{dx}(\sin x) = \cos x$ + +### 2.2 偏导数与梯度 + +对于多变量函数,偏导数表示函数对某一变量的变化率。梯度是所有偏导数组成的向量,指向函数增长最快的方向。 + +$$\nabla f = \begin{bmatrix} \frac{\partial f}{\partial x_1} \\ \frac{\partial f}{\partial x_2} \\ \vdots \\ \frac{\partial f}{\partial x_n} \end{bmatrix}$$ + +```python +# 使用数值方法计算梯度 +import numpy as np + +def numerical_gradient(f, x, h=1e-5): + """计算函数f在点x处的数值梯度""" + grad = np.zeros_like(x) + for i in range(len(x)): + x_plus = x.copy() + x_minus = x.copy() + x_plus[i] += h + x_minus[i] -= h + grad[i] = (f(x_plus) - f(x_minus)) / (2 * h) + return grad + +# 示例:f(x, y) = x^2 + y^2 +def f(x): + return x[0]**2 + x[1]**2 + +point = np.array([3.0, 4.0]) +print(numerical_gradient(f, point)) # [6. 8.] +# 理论值:梯度 = [2x, 2y] = [6, 8] +``` + +### 2.3 链式法则 + +链式法则是反向传播算法的数学基础,用于计算复合函数的导数。 + +$$\frac{dz}{dx} = \frac{dz}{dy} \cdot \frac{dy}{dx}$$ + +::: warning 核心概念 +神经网络的反向传播算法本质上就是链式法则的应用。通过链式法则,我们可以高效地计算损失函数对每个参数的梯度。 +::: + +## 3. 概率论与统计基础 + +概率论为机器学习中的不确定性建模提供了数学框架,是理解贝叶斯学习、生成模型等的基础。 + +### 3.1 基本概念 + +- **概率:** 事件发生可能性的度量,范围[0, 1] +- **条件概率:** $P(A|B) = \frac{P(A \cap B)}{P(B)}$ +- **贝叶斯定理:** $P(A|B) = \frac{P(B|A)P(A)}{P(B)}$ + +### 3.2 常见概率分布 + +| 分布 | 公式 | 应用场景 | +|------|------|----------| +| 伯努利分布 | $P(X=1) = p$ | 二分类问题 | +| 高斯分布 | $f(x) = \frac{1}{\sqrt{2\pi}\sigma}e^{-\frac{(x-\mu)^2}{2\sigma^2}}$ | 连续变量建模 | +| 多项式分布 | 伯努利分布的推广 | 多分类问题 | + +### 3.3 期望、方差与协方差 + +- **期望(均值):** $E[X] = \sum_x x \cdot P(X=x)$ +- **方差:** $Var(X) = E[(X - E[X])^2]$ +- **协方差:** $Cov(X, Y) = E[(X - E[X])(Y - E[Y])]$ + +```python +import numpy as np +from scipy import stats + +# 生成正态分布数据 +data = np.random.normal(loc=0, scale=1, size=1000) + +# 计算统计量 +print(f"均值: {np.mean(data):.4f}") +print(f"方差: {np.var(data):.4f}") +print(f"标准差: {np.std(data):.4f}") + +# 正态分布PDF +x = np.linspace(-3, 3, 100) +pdf = stats.norm.pdf(x, loc=0, scale=1) +``` + +## 4. 最优化基础 + +机器学习模型训练的本质是求解优化问题,即找到使损失函数最小的参数。 + +### 4.1 梯度下降法 + +梯度下降是最常用的优化算法,通过沿着梯度的反方向迭代更新参数。 + +$$\theta_{t+1} = \theta_t - \eta \nabla L(\theta_t)$$ + +其中 $\eta$ 是学习率,$\nabla L$ 是损失函数的梯度。 + +```python +import numpy as np + +def gradient_descent(gradient_func, initial_params, learning_rate=0.01, epochs=100): + """基础梯度下降算法""" + params = initial_params.copy() + history = [params.copy()] + + for _ in range(epochs): + grad = gradient_func(params) + params = params - learning_rate * grad + history.append(params.copy()) + + return params, history + +# 示例:最小化 f(x) = x^2 +def gradient(x): + return 2 * x + +x0 = np.array([5.0]) +optimal_x, history = gradient_descent(gradient, x0) +print(f"最优解: {optimal_x[0]:.6f}") # 接近0 +``` + +### 4.2 梯度下降的变体 + +| 算法 | 特点 | +|------|------| +| 批量梯度下降 (BGD) | 使用全部数据计算梯度,稳定但慢 | +| 随机梯度下降 (SGD) | 每次使用单个样本,快但不稳定 | +| 小批量梯度下降 | 折中方案,最常用 | +| Adam | 自适应学习率,深度学习首选 | + +## 5. 本章小结 + +- **线性代数:** 向量和矩阵运算是数据表示和模型计算的基础 +- **微积分:** 导数和梯度用于模型优化,链式法则是反向传播的核心 +- **概率统计:** 为不确定性建模提供数学框架 +- **最优化:** 梯度下降法是训练模型的核心算法 + +::: info 推荐学习资源 +- 3Blue1Brown《线性代数的本质》视频系列 +- 《深度学习》(花书)第2-4章数学基础 +- Khan Academy 微积分和概率统计课程 +::: diff --git a/docs/chapters/prerequisites/python-scientific.md b/docs/chapters/prerequisites/python-scientific.md new file mode 100644 index 0000000..9f809ac --- /dev/null +++ b/docs/chapters/prerequisites/python-scientific.md @@ -0,0 +1,398 @@ +# Python科学计算 + +::: info 本章概述 +Python是AI和机器学习领域最流行的编程语言。本章介绍NumPy、Pandas、Matplotlib这三个核心科学计算库的基础用法。 +::: + +## 1. NumPy - 数值计算基础 + +NumPy(Numerical Python)是Python科学计算的基础包,提供了高效的多维数组对象和各种数学函数。 + +### 1.1 创建数组 + +```python +import numpy as np + +# 从列表创建数组 +arr = np.array([1, 2, 3, 4, 5]) +print(arr) # [1 2 3 4 5] + +# 创建二维数组 +matrix = np.array([[1, 2, 3], [4, 5, 6]]) +print(matrix.shape) # (2, 3) + +# 常用创建函数 +zeros = np.zeros((3, 4)) # 全零数组 +ones = np.ones((2, 3)) # 全一数组 +eye = np.eye(3) # 单位矩阵 +rand = np.random.rand(3, 3) # 随机数组 [0, 1) +randn = np.random.randn(3, 3) # 标准正态分布 + +# 等间隔数组 +linspace = np.linspace(0, 10, 5) # [0, 2.5, 5, 7.5, 10] +arange = np.arange(0, 10, 2) # [0, 2, 4, 6, 8] +``` + +### 1.2 数组属性与索引 + +```python +arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) + +# 数组属性 +print(arr.shape) # (3, 3) - 形状 +print(arr.dtype) # int64 - 数据类型 +print(arr.size) # 9 - 元素总数 +print(arr.ndim) # 2 - 维度数 + +# 索引和切片 +print(arr[0, 0]) # 1 - 单个元素 +print(arr[0, :]) # [1 2 3] - 第一行 +print(arr[:, 1]) # [2 5 8] - 第二列 +print(arr[0:2, 1:3]) # 子矩阵 + +# 布尔索引 +print(arr[arr > 5]) # [6 7 8 9] + +# 花式索引 +print(arr[[0, 2], :]) # 第0行和第2行 +``` + +### 1.3 数组运算 + +```python +a = np.array([1, 2, 3]) +b = np.array([4, 5, 6]) + +# 逐元素运算 +print(a + b) # [5 7 9] +print(a * b) # [4 10 18] +print(a ** 2) # [1 4 9] +print(np.sqrt(a)) # [1. 1.414 1.732] + +# 矩阵运算 +A = np.array([[1, 2], [3, 4]]) +B = np.array([[5, 6], [7, 8]]) + +print(np.dot(A, B)) # 矩阵乘法 +print(A @ B) # 矩阵乘法(Python 3.5+) +print(A * B) # 逐元素乘法 + +# 聚合运算 +arr = np.array([[1, 2, 3], [4, 5, 6]]) +print(np.sum(arr)) # 21 - 总和 +print(np.sum(arr, axis=0)) # [5 7 9] - 按列求和 +print(np.sum(arr, axis=1)) # [6 15] - 按行求和 +print(np.mean(arr)) # 3.5 - 均值 +print(np.max(arr)) # 6 - 最大值 +print(np.argmax(arr)) # 5 - 最大值索引 +``` + +### 1.4 广播机制 + +广播(Broadcasting)允许NumPy在形状不同的数组间进行算术运算。 + +```python +# 广播示例 +a = np.array([[1, 2, 3], [4, 5, 6]]) # 形状 (2, 3) +b = np.array([10, 20, 30]) # 形状 (3,) + +# b被"广播"成 [[10, 20, 30], [10, 20, 30]] +print(a + b) +# [[11 22 33] +# [14 25 36]] + +# 标量广播 +print(a * 2) +# [[ 2 4 6] +# [ 8 10 12]] +``` + +::: tip 广播规则 +1. 如果两个数组维度数不同,在维度少的数组前面补1 +2. 在任一维度上,大小为1的可以与任意大小匹配 +3. 两个数组在所有维度上兼容才能广播 +::: + +## 2. Pandas - 数据处理利器 + +Pandas提供了DataFrame和Series两种数据结构,非常适合处理表格型数据。 + +### 2.1 数据结构 + +```python +import pandas as pd + +# Series - 一维数据 +s = pd.Series([1, 2, 3, 4], index=['a', 'b', 'c', 'd']) +print(s['a']) # 1 + +# DataFrame - 二维表格数据 +df = pd.DataFrame({ + 'name': ['Alice', 'Bob', 'Charlie'], + 'age': [25, 30, 35], + 'city': ['北京', '上海', '广州'] +}) +print(df) +# name age city +# 0 Alice 25 北京 +# 1 Bob 30 上海 +# 2 Charlie 35 广州 + +# 从文件读取 +# df = pd.read_csv('data.csv') +# df = pd.read_excel('data.xlsx') +``` + +### 2.2 数据选择与过滤 + +```python +# 创建示例数据 +df = pd.DataFrame({ + 'name': ['Alice', 'Bob', 'Charlie', 'David'], + 'age': [25, 30, 35, 28], + 'salary': [50000, 60000, 70000, 55000] +}) + +# 选择列 +print(df['name']) # 单列,返回Series +print(df[['name', 'age']]) # 多列,返回DataFrame + +# 选择行 +print(df.iloc[0]) # 按位置索引 +print(df.loc[0]) # 按标签索引 +print(df.iloc[0:2]) # 切片 + +# 条件过滤 +print(df[df['age'] > 28]) # age大于28的行 +print(df[(df['age'] > 25) & (df['salary'] > 55000)]) + +# 使用query方法 +print(df.query('age > 28 and salary > 55000')) +``` + +### 2.3 数据处理 + +```python +# 处理缺失值 +df = pd.DataFrame({ + 'A': [1, 2, None, 4], + 'B': [5, None, 7, 8] +}) + +print(df.isnull().sum()) # 统计缺失值 +df_filled = df.fillna(0) # 填充缺失值 +df_dropped = df.dropna() # 删除含缺失值的行 + +# 数据转换 +df['A'] = df['A'].astype(float) # 类型转换 + +# 应用函数 +df['A_squared'] = df['A'].apply(lambda x: x**2 if pd.notna(x) else None) + +# 分组聚合 +df = pd.DataFrame({ + 'category': ['A', 'A', 'B', 'B'], + 'value': [10, 20, 30, 40] +}) +print(df.groupby('category')['value'].mean()) +# category +# A 15.0 +# B 35.0 + +# 排序 +df_sorted = df.sort_values('value', ascending=False) +``` + +### 2.4 合并数据 + +```python +# 合并DataFrame +df1 = pd.DataFrame({'id': [1, 2], 'name': ['A', 'B']}) +df2 = pd.DataFrame({'id': [1, 2], 'score': [90, 85]}) + +# merge - 类似SQL JOIN +merged = pd.merge(df1, df2, on='id') + +# concat - 拼接 +df3 = pd.concat([df1, df1], axis=0) # 垂直拼接 +df4 = pd.concat([df1, df2], axis=1) # 水平拼接 +``` + +## 3. Matplotlib - 数据可视化 + +Matplotlib是Python最基础的绘图库,可以创建各种静态、动态和交互式图表。 + +### 3.1 基础绘图 + +```python +import matplotlib.pyplot as plt +import numpy as np + +# 折线图 +x = np.linspace(0, 10, 100) +y = np.sin(x) + +plt.figure(figsize=(10, 6)) +plt.plot(x, y, label='sin(x)', color='blue', linestyle='-') +plt.plot(x, np.cos(x), label='cos(x)', color='red', linestyle='--') +plt.xlabel('x') +plt.ylabel('y') +plt.title('三角函数图像') +plt.legend() +plt.grid(True) +plt.savefig('plot.png') +plt.show() +``` + +### 3.2 常用图表类型 + +```python +# 散点图 +plt.scatter(x, y, c='blue', alpha=0.5) + +# 柱状图 +categories = ['A', 'B', 'C', 'D'] +values = [23, 45, 56, 78] +plt.bar(categories, values) + +# 直方图 +data = np.random.randn(1000) +plt.hist(data, bins=30, edgecolor='black') + +# 饼图 +sizes = [15, 30, 45, 10] +labels = ['A', 'B', 'C', 'D'] +plt.pie(sizes, labels=labels, autopct='%1.1f%%') + +# 热力图 +data = np.random.rand(10, 10) +plt.imshow(data, cmap='hot') +plt.colorbar() +``` + +### 3.3 子图布局 + +```python +# 创建子图 +fig, axes = plt.subplots(2, 2, figsize=(12, 10)) + +# 在各子图中绘制 +axes[0, 0].plot(x, np.sin(x)) +axes[0, 0].set_title('Sin') + +axes[0, 1].plot(x, np.cos(x)) +axes[0, 1].set_title('Cos') + +axes[1, 0].plot(x, np.tan(x)) +axes[1, 0].set_title('Tan') + +axes[1, 1].plot(x, np.exp(-x)) +axes[1, 1].set_title('Exp') + +plt.tight_layout() +plt.show() +``` + +::: tip 可视化最佳实践 +- 始终添加标题、轴标签和图例 +- 选择合适的图表类型展示数据 +- 使用适当的配色方案 +- 保持图表简洁,避免信息过载 +::: + +## 4. Seaborn - 统计可视化 + +Seaborn是基于Matplotlib的高级可视化库,特别适合统计数据可视化。 + +```python +import seaborn as sns + +# 使用内置数据集 +tips = sns.load_dataset('tips') + +# 分布图 +sns.histplot(tips['total_bill'], kde=True) + +# 散点图带回归线 +sns.regplot(x='total_bill', y='tip', data=tips) + +# 箱线图 +sns.boxplot(x='day', y='total_bill', data=tips) + +# 热力图(相关性矩阵) +corr = tips.select_dtypes(include=[np.number]).corr() +sns.heatmap(corr, annot=True, cmap='coolwarm') + +# 成对关系图 +sns.pairplot(tips, hue='sex') +``` + +## 5. 实战练习 + +::: details 练习:探索性数据分析 + +```python +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt + +# 1. 创建模拟数据 +np.random.seed(42) +n_samples = 200 + +data = pd.DataFrame({ + 'feature1': np.random.randn(n_samples), + 'feature2': np.random.randn(n_samples) * 2, + 'target': np.random.randint(0, 2, n_samples) +}) + +# 添加一些特征间的关系 +data['feature3'] = data['feature1'] * 2 + np.random.randn(n_samples) * 0.5 + +# 2. 数据探索 +print("数据形状:", data.shape) +print("\n数据统计:") +print(data.describe()) +print("\n缺失值:") +print(data.isnull().sum()) + +# 3. 可视化 +fig, axes = plt.subplots(2, 2, figsize=(12, 10)) + +# 特征分布 +axes[0, 0].hist(data['feature1'], bins=20, edgecolor='black') +axes[0, 0].set_title('Feature1 分布') + +# 散点图 +axes[0, 1].scatter(data['feature1'], data['feature3'], + c=data['target'], cmap='coolwarm', alpha=0.6) +axes[0, 1].set_xlabel('feature1') +axes[0, 1].set_ylabel('feature3') +axes[0, 1].set_title('Feature1 vs Feature3') + +# 箱线图 +data.boxplot(column=['feature1', 'feature2', 'feature3'], ax=axes[1, 0]) +axes[1, 0].set_title('特征箱线图') + +# 相关性热力图 +corr = data.corr() +im = axes[1, 1].imshow(corr, cmap='coolwarm') +axes[1, 1].set_xticks(range(len(corr.columns))) +axes[1, 1].set_yticks(range(len(corr.columns))) +axes[1, 1].set_xticklabels(corr.columns) +axes[1, 1].set_yticklabels(corr.columns) +axes[1, 1].set_title('相关性矩阵') +plt.colorbar(im, ax=axes[1, 1]) + +plt.tight_layout() +plt.savefig('eda_example.png', dpi=150) +plt.show() +``` +::: + +## 6. 本章小结 + +- **NumPy:** 高效的数组运算,是所有科学计算库的基础 +- **Pandas:** 强大的数据处理能力,适合表格数据的清洗和分析 +- **Matplotlib:** 基础可视化工具,支持各种图表类型 +- **Seaborn:** 高级统计可视化,更美观的默认样式 diff --git a/docs/chapters/projects/house-price.md b/docs/chapters/projects/house-price.md new file mode 100644 index 0000000..9e3a0ad --- /dev/null +++ b/docs/chapters/projects/house-price.md @@ -0,0 +1,351 @@ +# 房价预测实战 + +::: info 项目概述 +本项目将使用加州房价数据集,完整演示一个机器学习项目的全流程:数据探索、特征工程、模型训练、评估和优化。 +::: + +## 1. 项目背景 + +房价预测是经典的回归问题。我们的目标是根据房屋的各种特征(如位置、面积、房龄等)预测其价格。 + +### 1.1 数据集介绍 + +我们使用加州房价数据集(California Housing Dataset),包含以下特征: + +| 特征 | 描述 | +|------|------| +| MedInc | 街区居民收入中位数 | +| HouseAge | 房屋年龄中位数 | +| AveRooms | 平均房间数 | +| AveBedrms | 平均卧室数 | +| Population | 街区人口 | +| AveOccup | 平均入住人数 | +| Latitude | 纬度 | +| Longitude | 经度 | + +## 2. 数据探索(EDA) + +```python +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt +import seaborn as sns +from sklearn.datasets import fetch_california_housing + +# 加载数据 +housing = fetch_california_housing() +df = pd.DataFrame(housing.data, columns=housing.feature_names) +df['MedHouseVal'] = housing.target # 目标变量:房价中位数(单位:10万美元) + +print("数据形状:", df.shape) +print("\n数据预览:") +print(df.head()) + +print("\n基本统计信息:") +print(df.describe()) + +print("\n缺失值检查:") +print(df.isnull().sum()) +``` + +### 2.1 数据分布可视化 + +```python +# 目标变量分布 +plt.figure(figsize=(12, 4)) + +plt.subplot(1, 2, 1) +plt.hist(df['MedHouseVal'], bins=50, edgecolor='black') +plt.xlabel('房价中位数(10万美元)') +plt.ylabel('频数') +plt.title('房价分布') + +plt.subplot(1, 2, 2) +df['MedHouseVal'].plot(kind='box') +plt.ylabel('房价中位数') +plt.title('房价箱线图') + +plt.tight_layout() +plt.show() + +# 特征分布 +fig, axes = plt.subplots(2, 4, figsize=(16, 8)) +for i, col in enumerate(housing.feature_names): + ax = axes[i // 4, i % 4] + df[col].hist(bins=30, ax=ax, edgecolor='black') + ax.set_title(col) +plt.tight_layout() +plt.show() +``` + +### 2.2 相关性分析 + +```python +# 相关性矩阵 +plt.figure(figsize=(10, 8)) +corr_matrix = df.corr() +sns.heatmap(corr_matrix, annot=True, cmap='coolwarm', center=0, fmt='.2f') +plt.title('特征相关性矩阵') +plt.tight_layout() +plt.show() + +# 与目标变量的相关性 +print("\n与房价的相关性:") +print(corr_matrix['MedHouseVal'].sort_values(ascending=False)) +``` + +### 2.3 地理分布可视化 + +```python +# 地理位置与房价的关系 +plt.figure(figsize=(12, 8)) +plt.scatter(df['Longitude'], df['Latitude'], + c=df['MedHouseVal'], cmap='viridis', + alpha=0.5, s=df['Population']/100) +plt.colorbar(label='房价中位数') +plt.xlabel('经度') +plt.ylabel('纬度') +plt.title('加州房价地理分布') +plt.show() +``` + +## 3. 数据预处理 + +```python +from sklearn.model_selection import train_test_split +from sklearn.preprocessing import StandardScaler + +# 分离特征和目标 +X = df.drop('MedHouseVal', axis=1) +y = df['MedHouseVal'] + +# 划分训练集和测试集 +X_train, X_test, y_train, y_test = train_test_split( + X, y, test_size=0.2, random_state=42 +) + +print(f"训练集大小: {X_train.shape[0]}") +print(f"测试集大小: {X_test.shape[0]}") + +# 特征标准化 +scaler = StandardScaler() +X_train_scaled = scaler.fit_transform(X_train) +X_test_scaled = scaler.transform(X_test) + +print("\n标准化后的特征统计:") +print(f"均值: {X_train_scaled.mean(axis=0).round(2)}") +print(f"标准差: {X_train_scaled.std(axis=0).round(2)}") +``` + +## 4. 模型训练与比较 + +```python +from sklearn.linear_model import LinearRegression, Ridge, Lasso +from sklearn.tree import DecisionTreeRegressor +from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor +from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_error +import time + +# 定义评估函数 +def evaluate_model(model, X_train, X_test, y_train, y_test, name): + start = time.time() + model.fit(X_train, y_train) + train_time = time.time() - start + + y_train_pred = model.predict(X_train) + y_test_pred = model.predict(X_test) + + results = { + 'Model': name, + 'Train RMSE': np.sqrt(mean_squared_error(y_train, y_train_pred)), + 'Test RMSE': np.sqrt(mean_squared_error(y_test, y_test_pred)), + 'Train R²': r2_score(y_train, y_train_pred), + 'Test R²': r2_score(y_test, y_test_pred), + 'MAE': mean_absolute_error(y_test, y_test_pred), + 'Train Time': train_time + } + return results, model + +# 训练多个模型 +models = { + 'Linear Regression': LinearRegression(), + 'Ridge': Ridge(alpha=1.0), + 'Lasso': Lasso(alpha=0.1), + 'Decision Tree': DecisionTreeRegressor(max_depth=10, random_state=42), + 'Random Forest': RandomForestRegressor(n_estimators=100, max_depth=10, random_state=42), + 'Gradient Boosting': GradientBoostingRegressor(n_estimators=100, max_depth=5, random_state=42) +} + +results_list = [] +trained_models = {} + +for name, model in models.items(): + results, trained_model = evaluate_model( + model, X_train_scaled, X_test_scaled, y_train, y_test, name + ) + results_list.append(results) + trained_models[name] = trained_model + print(f"{name}: Test R² = {results['Test R²']:.4f}, Test RMSE = {results['Test RMSE']:.4f}") + +# 结果汇总 +results_df = pd.DataFrame(results_list) +print("\n模型对比:") +print(results_df.to_string(index=False)) +``` + +### 4.1 模型性能可视化 + +```python +# 模型对比图 +fig, axes = plt.subplots(1, 2, figsize=(14, 5)) + +# R² 分数对比 +ax1 = axes[0] +x = range(len(results_df)) +width = 0.35 +ax1.bar([i - width/2 for i in x], results_df['Train R²'], width, label='Train') +ax1.bar([i + width/2 for i in x], results_df['Test R²'], width, label='Test') +ax1.set_xlabel('模型') +ax1.set_ylabel('R² Score') +ax1.set_title('各模型R²分数对比') +ax1.set_xticks(x) +ax1.set_xticklabels(results_df['Model'], rotation=45, ha='right') +ax1.legend() + +# RMSE 对比 +ax2 = axes[1] +ax2.bar([i - width/2 for i in x], results_df['Train RMSE'], width, label='Train') +ax2.bar([i + width/2 for i in x], results_df['Test RMSE'], width, label='Test') +ax2.set_xlabel('模型') +ax2.set_ylabel('RMSE') +ax2.set_title('各模型RMSE对比') +ax2.set_xticks(x) +ax2.set_xticklabels(results_df['Model'], rotation=45, ha='right') +ax2.legend() + +plt.tight_layout() +plt.show() +``` + +## 5. 特征重要性分析 + +```python +# 使用随机森林的特征重要性 +rf_model = trained_models['Random Forest'] + +feature_importance = pd.DataFrame({ + 'Feature': housing.feature_names, + 'Importance': rf_model.feature_importances_ +}).sort_values('Importance', ascending=False) + +plt.figure(figsize=(10, 6)) +plt.barh(feature_importance['Feature'], feature_importance['Importance']) +plt.xlabel('重要性') +plt.title('随机森林特征重要性') +plt.gca().invert_yaxis() +plt.tight_layout() +plt.show() + +print("特征重要性排名:") +print(feature_importance) +``` + +## 6. 超参数调优 + +```python +from sklearn.model_selection import GridSearchCV, cross_val_score + +# 对随机森林进行超参数调优 +param_grid_small = { + 'n_estimators': [100, 200], + 'max_depth': [10, 15], + 'min_samples_split': [2, 5] +} + +rf = RandomForestRegressor(random_state=42) +grid_search = GridSearchCV( + rf, param_grid_small, cv=5, scoring='r2', n_jobs=-1, verbose=1 +) +grid_search.fit(X_train_scaled, y_train) + +print(f"\n最佳参数: {grid_search.best_params_}") +print(f"最佳交叉验证R²: {grid_search.best_score_:.4f}") + +# 用最佳模型评估 +best_model = grid_search.best_estimator_ +y_pred = best_model.predict(X_test_scaled) +print(f"测试集R²: {r2_score(y_test, y_pred):.4f}") +print(f"测试集RMSE: {np.sqrt(mean_squared_error(y_test, y_pred)):.4f}") +``` + +## 7. 预测结果分析 + +```python +# 使用最佳模型进行预测 +y_pred = best_model.predict(X_test_scaled) + +# 预测值 vs 真实值 +plt.figure(figsize=(10, 5)) + +plt.subplot(1, 2, 1) +plt.scatter(y_test, y_pred, alpha=0.5) +plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'r--', lw=2) +plt.xlabel('真实值') +plt.ylabel('预测值') +plt.title('预测值 vs 真实值') + +# 残差分布 +plt.subplot(1, 2, 2) +residuals = y_test - y_pred +plt.hist(residuals, bins=50, edgecolor='black') +plt.xlabel('残差') +plt.ylabel('频数') +plt.title('残差分布') +plt.axvline(x=0, color='r', linestyle='--') + +plt.tight_layout() +plt.show() + +# 残差统计 +print(f"残差均值: {residuals.mean():.4f}") +print(f"残差标准差: {residuals.std():.4f}") +``` + +## 8. 模型保存与加载 + +```python +import joblib + +# 保存模型和标准化器 +joblib.dump(best_model, 'house_price_model.pkl') +joblib.dump(scaler, 'scaler.pkl') +print("模型已保存!") + +# 加载模型 +loaded_model = joblib.load('house_price_model.pkl') +loaded_scaler = joblib.load('scaler.pkl') + +# 使用加载的模型进行预测 +new_data = np.array([[8.3, 41, 6.98, 1.02, 322, 2.56, 37.88, -122.23]]) +new_data_scaled = loaded_scaler.transform(new_data) +prediction = loaded_model.predict(new_data_scaled) +print(f"预测房价: ${prediction[0] * 100000:.2f}") +``` + +## 9. 项目总结 + +::: tip 关键收获 +- **数据探索**:理解数据分布和特征关系是建模的基础 +- **特征工程**:标准化对某些算法至关重要 +- **模型比较**:集成方法(如随机森林)通常优于单一模型 +- **超参数调优**:可以进一步提升模型性能 +- **模型评估**:关注训练集和测试集的差距,避免过拟合 +::: + +### 9.1 进一步改进方向 + +- 尝试更多特征工程(如交叉特征、多项式特征) +- 使用XGBoost或LightGBM等更强的模型 +- 进行更细致的超参数调优 +- 尝试神经网络模型 +- 集成多个模型(Stacking) diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..d04f584 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,41 @@ +--- +layout: home + +hero: + name: "AI学习之路" + text: "人工智能入门学习教程" + tagline: 面向软件工程专业毕业生的系统性AI学习路径 + actions: + - theme: brand + text: 开始学习 + link: /chapters/prerequisites/math + - theme: alt + text: 查看大纲 + link: /outline + +features: + - icon: 🎯 + title: 目标人群 + details: 专为具有编程基础的学习者设计,特别适合刚毕业的软件工程专业学生。无需从零学习编程语法,直接进入AI核心概念。 + - icon: 🛤️ + title: 学习路径 + details: 从必要的前置知识开始,逐步深入到机器学习和深度学习的核心算法,最后通过实战项目巩固所学。 + - icon: 💻 + title: 实战导向 + details: 每个章节都配有完整的代码示例和可视化演示,帮助你在实践中理解抽象概念。 + - icon: 📚 + title: 参考资源 + details: 本教程参考了吴恩达课程、李沐《动手学深度学习》、Fast.ai等业界顶尖资源,并结合中文学习者特点进行编排。 +--- + + diff --git a/docs/outline.md b/docs/outline.md new file mode 100644 index 0000000..0a2a7aa --- /dev/null +++ b/docs/outline.md @@ -0,0 +1,66 @@ +# 学习大纲 + +本教程专为具有编程基础的软件工程毕业生设计,系统性地介绍人工智能和机器学习的核心概念与实践技能。 + +## 第0章:前置知识 + +在正式学习AI之前,需要补充一些必要的基础知识。 + +| 章节 | 主要内容 | 预计时间 | +|------|----------|----------| +| [数学基础](/chapters/prerequisites/math) | 线性代数、微积分、概率论与统计 | 45分钟 | +| [Python科学计算](/chapters/prerequisites/python-scientific) | NumPy、Pandas、Matplotlib基础 | 40分钟 | +| [数据处理基础](/chapters/prerequisites/data-processing) | 数据预处理、特征工程入门 | 35分钟 | + +## 第1章:AI基础概念 + +建立对人工智能领域的整体认识。 + +| 章节 | 主要内容 | 预计时间 | +|------|----------|----------| +| [什么是人工智能](/chapters/basics/what-is-ai) | AI的定义、发展历史与分类 | 30分钟 | +| [机器学习概述](/chapters/basics/ml-overview) | 监督学习、无监督学习、强化学习 | 35分钟 | +| [开发环境搭建](/chapters/basics/environment-setup) | Anaconda、Jupyter、GPU配置 | 25分钟 | + +## 第2章:机器学习入门 + +学习经典机器学习算法的原理和实现。 + +| 章节 | 主要内容 | 预计时间 | +|------|----------|----------| +| [线性回归](/chapters/machine-learning/linear-regression) | 模型原理、梯度下降、代码实现 | 45分钟 | + +::: tip 更多章节开发中 +逻辑回归与分类、决策树与集成学习、模型评估与优化等章节即将上线。 +::: + +## 第3章:深度学习入门 + +探索神经网络和深度学习的世界。 + +| 章节 | 主要内容 | 预计时间 | +|------|----------|----------| +| [神经网络基础](/chapters/deep-learning/neural-networks) | 感知机、激活函数、反向传播 | 50分钟 | + +::: tip 更多章节开发中 +深度学习框架、CNN、RNN、Transformer等章节即将上线。 +::: + +## 第4章:实战项目 + +通过完整项目巩固所学知识。 + +| 章节 | 主要内容 | 预计时间 | +|------|----------|----------| +| [房价预测](/chapters/projects/house-price) | 完整的回归任务流程 | 60分钟 | + +::: tip 更多项目开发中 +图像分类器、情感分析等项目即将上线。 +::: + +## 学习建议 + +1. **按顺序学习**:建议按照章节顺序学习,因为后续内容会依赖前面的知识 +2. **动手实践**:每个章节的代码示例都要亲自运行,理解每一行的作用 +3. **做笔记**:记录关键概念和自己的理解,有助于加深记忆 +4. **完成项目**:实战项目是检验学习效果的最佳方式 diff --git a/docs/public/logo.svg b/docs/public/logo.svg new file mode 100644 index 0000000..1f3124a --- /dev/null +++ b/docs/public/logo.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/docs/resources.md b/docs/resources.md new file mode 100644 index 0000000..524e9f9 --- /dev/null +++ b/docs/resources.md @@ -0,0 +1,110 @@ +# 推荐资源 + +学习AI不仅需要系统的教程,还需要参考优质的外部资源。以下是经过精选的推荐资源列表。 + +## 📹 视频课程 + +### 入门课程 + +| 课程 | 讲师/机构 | 特点 | +|------|-----------|------| +| **机器学习** | 吴恩达 (Coursera) | 经典入门课程,讲解清晰 | +| **动手学深度学习** | 李沐 (B站) | 中文讲解,代码实践丰富 | +| **Deep Learning Specialization** | 吴恩达 (Coursera) | 系统性深度学习课程 | +| **Practical Deep Learning** | Fast.ai | 实战导向,快速上手 | +| **Introduction to Deep Learning** | MIT | 学术性强,理论深入 | + +### 进阶课程 + +| 课程 | 讲师/机构 | 特点 | +|------|-----------|------| +| **CS231n** | Stanford | 计算机视觉经典课程 | +| **CS224n** | Stanford | 自然语言处理经典课程 | +| **强化学习** | David Silver | 强化学习入门首选 | + +## 📚 经典书籍 + +### 机器学习 + +| 书籍 | 作者 | 难度 | +|------|------|------| +| **《机器学习》(西瓜书)** | 周志华 | ⭐⭐⭐ | +| **《统计学习方法》** | 李航 | ⭐⭐⭐⭐ | +| **《Pattern Recognition and Machine Learning》** | Bishop | ⭐⭐⭐⭐⭐ | + +### 深度学习 + +| 书籍 | 作者 | 难度 | +|------|------|------| +| **《深度学习》(花书)** | Ian Goodfellow | ⭐⭐⭐⭐ | +| **《动手学深度学习》** | 李沐等 | ⭐⭐⭐ | +| **《神经网络与深度学习》** | 邱锡鹏 | ⭐⭐⭐ | + +### 实践指南 + +| 书籍 | 作者 | 难度 | +|------|------|------| +| **《Python机器学习》** | Sebastian Raschka | ⭐⭐⭐ | +| **《Hands-On Machine Learning》** | Aurélien Géron | ⭐⭐⭐ | + +## 💻 实践平台 + +| 平台 | 描述 | 链接 | +|------|------|------| +| **Kaggle** | 数据科学竞赛平台,提供免费数据集和GPU | [kaggle.com](https://www.kaggle.com) | +| **Google Colab** | 免费的云端Jupyter环境,提供免费GPU | [colab.research.google.com](https://colab.research.google.com) | +| **天池** | 阿里云AI竞赛平台 | [tianchi.aliyun.com](https://tianchi.aliyun.com) | +| **HuggingFace** | 模型和数据集仓库 | [huggingface.co](https://huggingface.co) | + +## 🔧 常用工具 + +### 深度学习框架 + +| 工具 | 特点 | +|------|------| +| **PyTorch** | 动态图,调试方便,学术界首选 | +| **TensorFlow** | 静态图,部署方便,工业界常用 | +| **JAX** | 函数式编程,高性能计算 | + +### 数据处理 + +| 工具 | 用途 | +|------|------| +| **NumPy** | 数值计算基础 | +| **Pandas** | 表格数据处理 | +| **Scikit-learn** | 经典机器学习算法库 | + +### 可视化 + +| 工具 | 用途 | +|------|------| +| **Matplotlib** | 基础绑图 | +| **Seaborn** | 统计可视化 | +| **TensorBoard** | 训练过程可视化 | +| **Weights & Biases** | 实验跟踪和可视化 | + +## 🌐 社区资源 + +| 社区 | 描述 | +|------|------| +| **知乎** | 中文AI技术讨论 | +| **CSDN** | 技术博客和教程 | +| **GitHub** | 开源项目和代码 | +| **arXiv** | 最新学术论文 | +| **Papers with Code** | 论文配套代码 | + +## 🎯 学习路径建议 + +::: info 初学者路径 +1. 先学习 Python 基础和科学计算库 +2. 完成吴恩达《机器学习》课程 +3. 阅读《机器学习》(西瓜书)前几章 +4. 参加 Kaggle 入门竞赛 +::: + +::: info 进阶路径 +1. 学习《动手学深度学习》 +2. 根据兴趣选择 CV 或 NLP 方向 +3. 阅读经典论文,复现关键算法 +4. 参与开源项目或实际业务 +::: diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..ca438bc --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2951 @@ +{ + "name": "learn-ai", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "learn-ai", + "version": "1.0.0", + "license": "ISC", + "devDependencies": { + "markdown-it-mathjax3": "^4.3.2", + "vitepress": "^1.6.4" + } + }, + "node_modules/@algolia/abtesting": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.11.0.tgz", + "integrity": "sha512-a7oQ8dwiyoyVmzLY0FcuBqyqcNSq78qlcOtHmNBumRlHCSnXDcuoYGBGPN1F6n8JoGhviDDsIaF/oQrzTzs6Lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.45.0", + "@algolia/requester-browser-xhr": "5.45.0", + "@algolia/requester-fetch": "5.45.0", + "@algolia/requester-node-http": "5.45.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/autocomplete-core": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.17.7.tgz", + "integrity": "sha512-BjiPOW6ks90UKl7TwMv7oNQMnzU+t/wk9mgIDi6b1tXpUek7MW0lbNOUHpvam9pe3lVCf4xPFT+lK7s+e+fs7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-plugin-algolia-insights": "1.17.7", + "@algolia/autocomplete-shared": "1.17.7" + } + }, + "node_modules/@algolia/autocomplete-plugin-algolia-insights": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.17.7.tgz", + "integrity": "sha512-Jca5Ude6yUOuyzjnz57og7Et3aXjbwCSDf/8onLHSQgw1qW3ALl9mrMWaXb5FmPVkV3EtkD2F/+NkT6VHyPu9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-shared": "1.17.7" + }, + "peerDependencies": { + "search-insights": ">= 1 < 3" + } + }, + "node_modules/@algolia/autocomplete-preset-algolia": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.17.7.tgz", + "integrity": "sha512-ggOQ950+nwbWROq2MOCIL71RE0DdQZsceqrg32UqnhDz8FlO9rL8ONHNsI2R1MH0tkgVIDKI/D0sMiUchsFdWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-shared": "1.17.7" + }, + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/autocomplete-shared": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.17.7.tgz", + "integrity": "sha512-o/1Vurr42U/qskRSuhBH+VKxMvkkUVTLU6WZQr+L5lGZZLYWyhdzWjW0iGXY7EkwRTjBqvN2EsR81yCTGV/kmg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/client-abtesting": { + "version": "5.45.0", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.45.0.tgz", + "integrity": "sha512-WTW0VZA8xHMbzuQD5b3f41ovKZ0MNTIXkWfm0F2PU+XGcLxmxX15UqODzF2sWab0vSbi3URM1xLhJx+bXbd1eQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.45.0", + "@algolia/requester-browser-xhr": "5.45.0", + "@algolia/requester-fetch": "5.45.0", + "@algolia/requester-node-http": "5.45.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-analytics": { + "version": "5.45.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.45.0.tgz", + "integrity": "sha512-I3g7VtvG/QJOH3tQO7E7zWTwBfK/nIQXShFLR8RvPgWburZ626JNj332M3wHCYcaAMivN9WJG66S2JNXhm6+Xg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.45.0", + "@algolia/requester-browser-xhr": "5.45.0", + "@algolia/requester-fetch": "5.45.0", + "@algolia/requester-node-http": "5.45.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-common": { + "version": "5.45.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.45.0.tgz", + "integrity": "sha512-/nTqm1tLiPtbUr+8kHKyFiCOfhRfgC+JxLvOCq471gFZZOlsh6VtFRiKI60/zGmHTojFC6B0mD80PB7KeK94og==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-insights": { + "version": "5.45.0", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.45.0.tgz", + "integrity": "sha512-suQTx/1bRL1g/K2hRtbK3ANmbzaZCi13487sxxmqok+alBDKKw0/TI73ZiHjjFXM2NV52inwwcmW4fUR45206Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.45.0", + "@algolia/requester-browser-xhr": "5.45.0", + "@algolia/requester-fetch": "5.45.0", + "@algolia/requester-node-http": "5.45.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-personalization": { + "version": "5.45.0", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.45.0.tgz", + "integrity": "sha512-CId/dbjpzI3eoUhPU6rt/z4GrRsDesqFISEMOwrqWNSrf4FJhiUIzN42Ac+Gzg69uC0RnzRYy60K1y4Na5VSMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.45.0", + "@algolia/requester-browser-xhr": "5.45.0", + "@algolia/requester-fetch": "5.45.0", + "@algolia/requester-node-http": "5.45.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-query-suggestions": { + "version": "5.45.0", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.45.0.tgz", + "integrity": "sha512-tjbBKfA8fjAiFtvl9g/MpIPiD6pf3fj7rirVfh1eMIUi8ybHP4ovDzIaE216vHuRXoePQVCkMd2CokKvYq1CLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.45.0", + "@algolia/requester-browser-xhr": "5.45.0", + "@algolia/requester-fetch": "5.45.0", + "@algolia/requester-node-http": "5.45.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-search": { + "version": "5.45.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.45.0.tgz", + "integrity": "sha512-nxuCid+Nszs4xqwIMDw11pRJPes2c+Th1yup/+LtpjFH8QWXkr3SirNYSD3OXAeM060HgWWPLA8/Fxk+vwxQOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.45.0", + "@algolia/requester-browser-xhr": "5.45.0", + "@algolia/requester-fetch": "5.45.0", + "@algolia/requester-node-http": "5.45.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/ingestion": { + "version": "1.45.0", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.45.0.tgz", + "integrity": "sha512-t+1doBzhkQTeOOjLHMlm4slmXBhvgtEGQhOmNpMPTnIgWOyZyESWdm+XD984qM4Ej1i9FRh8VttOGrdGnAjAng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.45.0", + "@algolia/requester-browser-xhr": "5.45.0", + "@algolia/requester-fetch": "5.45.0", + "@algolia/requester-node-http": "5.45.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/monitoring": { + "version": "1.45.0", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.45.0.tgz", + "integrity": "sha512-IaX3ZX1A/0wlgWZue+1BNWlq5xtJgsRo7uUk/aSiYD7lPbJ7dFuZ+yTLFLKgbl4O0QcyHTj1/mSBj9ryF1Lizg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.45.0", + "@algolia/requester-browser-xhr": "5.45.0", + "@algolia/requester-fetch": "5.45.0", + "@algolia/requester-node-http": "5.45.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/recommend": { + "version": "5.45.0", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.45.0.tgz", + "integrity": "sha512-1jeMLoOhkgezCCPsOqkScwYzAAc1Jr5T2hisZl0s32D94ZV7d1OHozBukgOjf8Dw+6Hgi6j52jlAdUWTtkX9Mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.45.0", + "@algolia/requester-browser-xhr": "5.45.0", + "@algolia/requester-fetch": "5.45.0", + "@algolia/requester-node-http": "5.45.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-browser-xhr": { + "version": "5.45.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.45.0.tgz", + "integrity": "sha512-46FIoUkQ9N7wq4/YkHS5/W9Yjm4Ab+q5kfbahdyMpkBPJ7IBlwuNEGnWUZIQ6JfUZuJVojRujPRHMihX4awUMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.45.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-fetch": { + "version": "5.45.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.45.0.tgz", + "integrity": "sha512-XFTSAtCwy4HdBhSReN2rhSyH/nZOM3q3qe5ERG2FLbYId62heIlJBGVyAPRbltRwNlotlydbvSJ+SQ0ruWC2cw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.45.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-node-http": { + "version": "5.45.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.45.0.tgz", + "integrity": "sha512-8mTg6lHx5i44raCU52APsu0EqMsdm4+7Hch/e4ZsYZw0hzwkuaMFh826ngnkYf9XOl58nHoou63aZ874m8AbpQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.45.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.5" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@docsearch/css": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.8.2.tgz", + "integrity": "sha512-y05ayQFyUmCXze79+56v/4HpycYF3uFqB78pLPrSV5ZKAlDuIAAJNhaRi8tTdRNXh05yxX/TyNnzD6LwSM89vQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@docsearch/js": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/@docsearch/js/-/js-3.8.2.tgz", + "integrity": "sha512-Q5wY66qHn0SwA7Taa0aDbHiJvaFJLOJyHmooQ7y8hlwwQLQ/5WwCcoX0g7ii04Qi2DJlHsd0XXzJ8Ypw9+9YmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@docsearch/react": "3.8.2", + "preact": "^10.0.0" + } + }, + "node_modules/@docsearch/react": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.8.2.tgz", + "integrity": "sha512-xCRrJQlTt8N9GU0DG4ptwHRkfnSnD/YpdeaXe02iKfqs97TkZJv60yE+1eq/tjPcVnTW8dP5qLP7itifFVV5eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-core": "1.17.7", + "@algolia/autocomplete-preset-algolia": "1.17.7", + "@docsearch/css": "3.8.2", + "algoliasearch": "^5.14.2" + }, + "peerDependencies": { + "@types/react": ">= 16.8.0 < 19.0.0", + "react": ">= 16.8.0 < 19.0.0", + "react-dom": ">= 16.8.0 < 19.0.0", + "search-insights": ">= 1 < 3" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "search-insights": { + "optional": true + } + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@iconify-json/simple-icons": { + "version": "1.2.60", + "resolved": "https://registry.npmjs.org/@iconify-json/simple-icons/-/simple-icons-1.2.60.tgz", + "integrity": "sha512-KlwLBKCdMCqfySdkAA+jehdUx6VSjnj6lvzQKus7HjkPSQ6QP58d6xiptkIp0jd/Hw3PW2++nRuGvCvSYaF0Mg==", + "dev": true, + "license": "CC0-1.0", + "dependencies": { + "@iconify/types": "*" + } + }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.3.tgz", + "integrity": "sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.3.tgz", + "integrity": "sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.3.tgz", + "integrity": "sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.3.tgz", + "integrity": "sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.3.tgz", + "integrity": "sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.3.tgz", + "integrity": "sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.3.tgz", + "integrity": "sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.3.tgz", + "integrity": "sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.3.tgz", + "integrity": "sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.3.tgz", + "integrity": "sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.3.tgz", + "integrity": "sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.3.tgz", + "integrity": "sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.3.tgz", + "integrity": "sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.3.tgz", + "integrity": "sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.3.tgz", + "integrity": "sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.3.tgz", + "integrity": "sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.3.tgz", + "integrity": "sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.3.tgz", + "integrity": "sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.3.tgz", + "integrity": "sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.3.tgz", + "integrity": "sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.3.tgz", + "integrity": "sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.3.tgz", + "integrity": "sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@shikijs/core": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-2.5.0.tgz", + "integrity": "sha512-uu/8RExTKtavlpH7XqnVYBrfBkUc20ngXiX9NSrBhOVZYv/7XQRKUyhtkeflY5QsxC0GbJThCerruZfsUaSldg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/engine-javascript": "2.5.0", + "@shikijs/engine-oniguruma": "2.5.0", + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4", + "hast-util-to-html": "^9.0.4" + } + }, + "node_modules/@shikijs/engine-javascript": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-2.5.0.tgz", + "integrity": "sha512-VjnOpnQf8WuCEZtNUdjjwGUbtAVKuZkVQ/5cHy/tojVVRIRtlWMYVjyWhxOmIq05AlSOv72z7hRNRGVBgQOl0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "oniguruma-to-es": "^3.1.0" + } + }, + "node_modules/@shikijs/engine-oniguruma": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-2.5.0.tgz", + "integrity": "sha512-pGd1wRATzbo/uatrCIILlAdFVKdxImWJGQ5rFiB5VZi2ve5xj3Ax9jny8QvkaV93btQEwR/rSz5ERFpC5mKNIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2" + } + }, + "node_modules/@shikijs/langs": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-2.5.0.tgz", + "integrity": "sha512-Qfrrt5OsNH5R+5tJ/3uYBBZv3SuGmnRPejV9IlIbFH3HTGLDlkqgHymAlzklVmKBjAaVmkPkyikAV/sQ1wSL+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "2.5.0" + } + }, + "node_modules/@shikijs/themes": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-2.5.0.tgz", + "integrity": "sha512-wGrk+R8tJnO0VMzmUExHR+QdSaPUl/NKs+a4cQQRWyoc3YFbUzuLEi/KWK1hj+8BfHRKm2jNhhJck1dfstJpiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "2.5.0" + } + }, + "node_modules/@shikijs/transformers": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/transformers/-/transformers-2.5.0.tgz", + "integrity": "sha512-SI494W5X60CaUwgi8u4q4m4s3YAFSxln3tzNjOSYqq54wlVgz0/NbbXEb3mdLbqMBztcmS7bVTaEd2w0qMmfeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/core": "2.5.0", + "@shikijs/types": "2.5.0" + } + }, + "node_modules/@shikijs/types": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-2.5.0.tgz", + "integrity": "sha512-ygl5yhxki9ZLNuNpPitBWvcy9fsSKKaRuO4BAlMyagszQidxcpLAr0qiW/q43DtSIDxO6hEbtYLiFZNXO/hdGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, + "node_modules/@shikijs/vscode-textmate": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", + "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/markdown-it": { + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", + "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/linkify-it": "^5", + "@types/mdurl": "^2" + } + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.21", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz", + "integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "dev": true, + "license": "ISC" + }, + "node_modules/@vitejs/plugin-vue": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz", + "integrity": "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.25", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.25.tgz", + "integrity": "sha512-vay5/oQJdsNHmliWoZfHPoVZZRmnSWhug0BYT34njkYTPqClh3DNWLkZNJBVSjsNMrg0CCrBfoKkjZQPM/QVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@vue/shared": "3.5.25", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-core/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.25", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.25.tgz", + "integrity": "sha512-4We0OAcMZsKgYoGlMjzYvaoErltdFI2/25wqanuTu+S4gismOTRTBPi4IASOjxWdzIwrYSjnqONfKvuqkXzE2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.25", + "@vue/shared": "3.5.25" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.25", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.25.tgz", + "integrity": "sha512-PUgKp2rn8fFsI++lF2sO7gwO2d9Yj57Utr5yEsDf3GNaQcowCLKL7sf+LvVFvtJDXUp/03+dC6f2+LCv5aK1ag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@vue/compiler-core": "3.5.25", + "@vue/compiler-dom": "3.5.25", + "@vue/compiler-ssr": "3.5.25", + "@vue/shared": "3.5.25", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.21", + "postcss": "^8.5.6", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.25", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.25.tgz", + "integrity": "sha512-ritPSKLBcParnsKYi+GNtbdbrIE1mtuFEJ4U1sWeuOMlIziK5GtOL85t5RhsNy4uWIXPgk+OUdpnXiTdzn8o3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.25", + "@vue/shared": "3.5.25" + } + }, + "node_modules/@vue/devtools-api": { + "version": "7.7.9", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.9.tgz", + "integrity": "sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-kit": "^7.7.9" + } + }, + "node_modules/@vue/devtools-kit": { + "version": "7.7.9", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.9.tgz", + "integrity": "sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-shared": "^7.7.9", + "birpc": "^2.3.0", + "hookable": "^5.5.3", + "mitt": "^3.0.1", + "perfect-debounce": "^1.0.0", + "speakingurl": "^14.0.1", + "superjson": "^2.2.2" + } + }, + "node_modules/@vue/devtools-shared": { + "version": "7.7.9", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.9.tgz", + "integrity": "sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "rfdc": "^1.4.1" + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.25", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.25.tgz", + "integrity": "sha512-5xfAypCQepv4Jog1U4zn8cZIcbKKFka3AgWHEFQeK65OW+Ys4XybP6z2kKgws4YB43KGpqp5D/K3go2UPPunLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.25" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.25", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.25.tgz", + "integrity": "sha512-Z751v203YWwYzy460bzsYQISDfPjHTl+6Zzwo/a3CsAf+0ccEjQ8c+0CdX1WsumRTHeywvyUFtW6KvNukT/smA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.25", + "@vue/shared": "3.5.25" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.25", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.25.tgz", + "integrity": "sha512-a4WrkYFbb19i9pjkz38zJBg8wa/rboNERq3+hRRb0dHiJh13c+6kAbgqCPfMaJ2gg4weWD3APZswASOfmKwamA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.25", + "@vue/runtime-core": "3.5.25", + "@vue/shared": "3.5.25", + "csstype": "^3.1.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.25", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.25.tgz", + "integrity": "sha512-UJaXR54vMG61i8XNIzTSf2Q7MOqZHpp8+x3XLGtE3+fL+nQd+k7O5+X3D/uWrnQXOdMw5VPih+Uremcw+u1woQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.25", + "@vue/shared": "3.5.25" + }, + "peerDependencies": { + "vue": "3.5.25" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.25", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.25.tgz", + "integrity": "sha512-AbOPdQQnAnzs58H2FrrDxYj/TJfmeS2jdfEEhgiKINy+bnOANmVizIEgq1r+C5zsbs6l1CCQxtcj71rwNQ4jWg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vueuse/core": { + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-12.8.2.tgz", + "integrity": "sha512-HbvCmZdzAu3VGi/pWYm5Ut+Kd9mn1ZHnn4L5G8kOQTPs/IwIAmJoBrmYk2ckLArgMXZj0AW3n5CAejLUO+PhdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/web-bluetooth": "^0.0.21", + "@vueuse/metadata": "12.8.2", + "@vueuse/shared": "12.8.2", + "vue": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/integrations": { + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/integrations/-/integrations-12.8.2.tgz", + "integrity": "sha512-fbGYivgK5uBTRt7p5F3zy6VrETlV9RtZjBqd1/HxGdjdckBgBM4ugP8LHpjolqTj14TXTxSK1ZfgPbHYyGuH7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vueuse/core": "12.8.2", + "@vueuse/shared": "12.8.2", + "vue": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "async-validator": "^4", + "axios": "^1", + "change-case": "^5", + "drauu": "^0.4", + "focus-trap": "^7", + "fuse.js": "^7", + "idb-keyval": "^6", + "jwt-decode": "^4", + "nprogress": "^0.2", + "qrcode": "^1.5", + "sortablejs": "^1", + "universal-cookie": "^7" + }, + "peerDependenciesMeta": { + "async-validator": { + "optional": true + }, + "axios": { + "optional": true + }, + "change-case": { + "optional": true + }, + "drauu": { + "optional": true + }, + "focus-trap": { + "optional": true + }, + "fuse.js": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "jwt-decode": { + "optional": true + }, + "nprogress": { + "optional": true + }, + "qrcode": { + "optional": true + }, + "sortablejs": { + "optional": true + }, + "universal-cookie": { + "optional": true + } + } + }, + "node_modules/@vueuse/metadata": { + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-12.8.2.tgz", + "integrity": "sha512-rAyLGEuoBJ/Il5AmFHiziCPdQzRt88VxR+Y/A/QhJ1EWtWqPBBAxTAFaSkviwEuOEZNtW8pvkPgoCZQ+HxqW1A==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-12.8.2.tgz", + "integrity": "sha512-dznP38YzxZoNloI0qpEfpkms8knDtaoQ6Y/sfS0L7Yki4zh40LFHEhur0odJC6xTHG5dxWVPiUWBXn+wCG2s5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "vue": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@xmldom/xmldom": { + "version": "0.9.8", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.9.8.tgz", + "integrity": "sha512-p96FSY54r+WJ50FIOsCOjyj/wavs8921hG5+kVMmZgKcvIKxMXHTrjNJvRgWa/zuX3B6t2lijLNFaOyuxUH+2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.6" + } + }, + "node_modules/algoliasearch": { + "version": "5.45.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.45.0.tgz", + "integrity": "sha512-wrj4FGr14heLOYkBKV3Fbq5ZBGuIFeDJkTilYq/G+hH1CSlQBtYvG2X1j67flwv0fUeQJwnWxxRIunSemAZirA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/abtesting": "1.11.0", + "@algolia/client-abtesting": "5.45.0", + "@algolia/client-analytics": "5.45.0", + "@algolia/client-common": "5.45.0", + "@algolia/client-insights": "5.45.0", + "@algolia/client-personalization": "5.45.0", + "@algolia/client-query-suggestions": "5.45.0", + "@algolia/client-search": "5.45.0", + "@algolia/ingestion": "1.45.0", + "@algolia/monitoring": "1.45.0", + "@algolia/recommend": "5.45.0", + "@algolia/requester-browser-xhr": "5.45.0", + "@algolia/requester-fetch": "5.45.0", + "@algolia/requester-node-http": "5.45.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/birpc": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.8.0.tgz", + "integrity": "sha512-Bz2a4qD/5GRhiHSwj30c/8kC8QGj12nNDwz3D4ErQ4Xhy35dsSDvF+RA/tWpjyU0pdGtSDiEk6B5fBGE1qNVhw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true, + "license": "ISC" + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/cheerio": { + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz", + "integrity": "sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cheerio-select": "^1.5.0", + "dom-serializer": "^1.3.2", + "domhandler": "^4.2.0", + "htmlparser2": "^6.1.0", + "parse5": "^6.0.1", + "parse5-htmlparser2-tree-adapter": "^6.0.1", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.6.0.tgz", + "integrity": "sha512-eq0GdBvxVFbqWgmCm7M3XGs1I8oLy/nExUnh6oLqmBditPO9AqQJrkslDpMun/hZ0yyTs8L0m85OHp4ho6Qm9g==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "css-select": "^4.3.0", + "css-what": "^6.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.3.1", + "domutils": "^2.8.0" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/copy-anything": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-4.0.5.tgz", + "integrity": "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-what": "^5.2.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/emoji-regex-xs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex-xs/-/emoji-regex-xs-1.0.0.tgz", + "integrity": "sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==", + "dev": true, + "license": "MIT" + }, + "node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/escape-goat": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-3.0.0.tgz", + "integrity": "sha512-w3PwNZJwRxlp47QGzhuEBldEqVHHhh8/tIPcl6ecf2Bou99cdAt0knihBV0Ecc7CGxYduXVBDheH1K2oADRlvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/esm": { + "version": "3.2.25", + "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", + "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/focus-trap": { + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.6.6.tgz", + "integrity": "sha512-v/Z8bvMCajtx4mEXmOo7QEsIzlIOqRXTIwgUfsFOF9gEsespdbD0AkPIka1bSXZ8Y8oZ+2IVDQZePkTfEHZl7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "tabbable": "^6.3.0" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/hast-util-to-html": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz", + "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hookable": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", + "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/is-what": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-5.5.0.tgz", + "integrity": "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/juice": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/juice/-/juice-8.1.0.tgz", + "integrity": "sha512-FLzurJrx5Iv1e7CfBSZH68dC04EEvXvvVvPYB7Vx1WAuhCp1ZPIMtqxc+WTWxVkpTIC2Ach/GAv0rQbtGf6YMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cheerio": "1.0.0-rc.10", + "commander": "^6.1.0", + "mensch": "^0.3.4", + "slick": "^1.12.2", + "web-resource-inliner": "^6.0.1" + }, + "bin": { + "juice": "bin/juice" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/mark.js": { + "version": "8.11.1", + "resolved": "https://registry.npmjs.org/mark.js/-/mark.js-8.11.1.tgz", + "integrity": "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/markdown-it-mathjax3": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/markdown-it-mathjax3/-/markdown-it-mathjax3-4.3.2.tgz", + "integrity": "sha512-TX3GW5NjmupgFtMJGRauioMbbkGsOXAAt1DZ/rzzYmTHqzkO1rNAdiMD4NiruurToPApn2kYy76x02QN26qr2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "juice": "^8.0.0", + "mathjax-full": "^3.2.0" + } + }, + "node_modules/mathjax-full": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/mathjax-full/-/mathjax-full-3.2.1.tgz", + "integrity": "sha512-aUz9o16MGZdeiIBwZjAfUBTiJb7LRqzZEl1YOZ8zQMGYIyh1/nxRebxKxjDe9L+xcZCr2OHdzoFBMcd6VnLv9Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esm": "^3.2.25", + "mhchemparser": "^4.1.0", + "mj-context-menu": "^0.6.1", + "speech-rule-engine": "^4.0.6" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mensch": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/mensch/-/mensch-0.3.4.tgz", + "integrity": "sha512-IAeFvcOnV9V0Yk+bFhYR07O3yNina9ANIN5MoXBKYJ/RLYPurd2d0yw14MDhpr9/momp0WofT1bPUh3hkzdi/g==", + "dev": true, + "license": "MIT" + }, + "node_modules/mhchemparser": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/mhchemparser/-/mhchemparser-4.2.1.tgz", + "integrity": "sha512-kYmyrCirqJf3zZ9t/0wGgRZ4/ZJw//VwaRVGA75C4nhE60vtnIzhl9J9ndkX/h6hxSN7pjg/cE0VxbnNM+bnDQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/minisearch": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/minisearch/-/minisearch-7.2.0.tgz", + "integrity": "sha512-dqT2XBYUOZOiC5t2HRnwADjhNS2cecp9u+TJRiJ1Qp/f5qjkeT5APcGPjHw+bz89Ms8Jp+cG4AlE+QZ/QnDglg==", + "dev": true, + "license": "MIT" + }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "dev": true, + "license": "MIT" + }, + "node_modules/mj-context-menu": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/mj-context-menu/-/mj-context-menu-0.6.1.tgz", + "integrity": "sha512-7NO5s6n10TIV96d4g2uDpG7ZDpIhMh0QNfGdJw/W47JswFcosz457wqz/b5sAKvl12sxINGFCn80NZHKwxQEXA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/oniguruma-to-es": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-3.1.1.tgz", + "integrity": "sha512-bUH8SDvPkH3ho3dvwJwfonjlQ4R80vjyvrU8YpxuROddv55vAEJrTuCuCVUhhsHbtlD9tGGbaNApGQckXhS8iQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex-xs": "^1.0.0", + "regex": "^6.0.1", + "regex-recursion": "^6.0.2" + } + }, + "node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true, + "license": "MIT" + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse5": "^6.0.1" + } + }, + "node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/preact": { + "version": "10.27.2", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.27.2.tgz", + "integrity": "sha512-5SYSgFKSyhCbk6SrXyMpqjb5+MQBgfvEKE/OC+PujcY34sOpqtr+0AZQtPYx5IA6VxynQ7rUPCtKzyovpj9Bpg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, + "node_modules/property-information": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/regex/-/regex-6.0.1.tgz", + "integrity": "sha512-uorlqlzAKjKQZ5P+kTJr3eeJGSVroLKoHmquUj4zHWuR+hEyNqlXsSKlYYF5F4NI6nl7tWCs0apKJ0lmfsXAPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-recursion": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz", + "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-utilities": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz", + "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", + "dev": true, + "license": "MIT" + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/rollup": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.3.tgz", + "integrity": "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.53.3", + "@rollup/rollup-android-arm64": "4.53.3", + "@rollup/rollup-darwin-arm64": "4.53.3", + "@rollup/rollup-darwin-x64": "4.53.3", + "@rollup/rollup-freebsd-arm64": "4.53.3", + "@rollup/rollup-freebsd-x64": "4.53.3", + "@rollup/rollup-linux-arm-gnueabihf": "4.53.3", + "@rollup/rollup-linux-arm-musleabihf": "4.53.3", + "@rollup/rollup-linux-arm64-gnu": "4.53.3", + "@rollup/rollup-linux-arm64-musl": "4.53.3", + "@rollup/rollup-linux-loong64-gnu": "4.53.3", + "@rollup/rollup-linux-ppc64-gnu": "4.53.3", + "@rollup/rollup-linux-riscv64-gnu": "4.53.3", + "@rollup/rollup-linux-riscv64-musl": "4.53.3", + "@rollup/rollup-linux-s390x-gnu": "4.53.3", + "@rollup/rollup-linux-x64-gnu": "4.53.3", + "@rollup/rollup-linux-x64-musl": "4.53.3", + "@rollup/rollup-openharmony-arm64": "4.53.3", + "@rollup/rollup-win32-arm64-msvc": "4.53.3", + "@rollup/rollup-win32-ia32-msvc": "4.53.3", + "@rollup/rollup-win32-x64-gnu": "4.53.3", + "@rollup/rollup-win32-x64-msvc": "4.53.3", + "fsevents": "~2.3.2" + } + }, + "node_modules/search-insights": { + "version": "2.17.3", + "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.3.tgz", + "integrity": "sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/shiki": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-2.5.0.tgz", + "integrity": "sha512-mI//trrsaiCIPsja5CNfsyNOqgAZUb6VpJA+340toL42UpzQlXpwRV9nch69X6gaUxrr9kaOOa6e3y3uAkGFxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/core": "2.5.0", + "@shikijs/engine-javascript": "2.5.0", + "@shikijs/engine-oniguruma": "2.5.0", + "@shikijs/langs": "2.5.0", + "@shikijs/themes": "2.5.0", + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, + "node_modules/slick": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/slick/-/slick-1.12.2.tgz", + "integrity": "sha512-4qdtOGcBjral6YIBCWJ0ljFSKNLz9KkhbWtuGvUyRowl1kxfuE1x/Z/aJcaiilpb3do9bl5K7/1h9XC5wWpY/A==", + "dev": true, + "license": "MIT (http://mootools.net/license.txt)", + "engines": { + "node": "*" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/speakingurl": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", + "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/speech-rule-engine": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/speech-rule-engine/-/speech-rule-engine-4.1.2.tgz", + "integrity": "sha512-S6ji+flMEga+1QU79NDbwZ8Ivf0S/MpupQQiIC0rTpU/ZTKgcajijJJb1OcByBQDjrXCN1/DJtGz4ZJeBMPGJw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@xmldom/xmldom": "0.9.8", + "commander": "13.1.0", + "wicked-good-xpath": "1.3.0" + }, + "bin": { + "sre": "bin/sre" + } + }, + "node_modules/speech-rule-engine/node_modules/commander": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "dev": true, + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/superjson": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.6.tgz", + "integrity": "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "copy-anything": "^4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tabbable": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.3.0.tgz", + "integrity": "sha512-EIHvdY5bPLuWForiR/AN2Bxngzpuwn1is4asboytXtpTgsArc+WmSJKVLlhdh71u7jFcryDqB2A8lQvj78MkyQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/unist-util-is": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/valid-data-url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/valid-data-url/-/valid-data-url-3.0.1.tgz", + "integrity": "sha512-jOWVmzVceKlVVdwjNSenT4PbGghU0SBIizAev8ofZVgivk/TVHXSbNL8LP6M3spZvkR9/QolkyJavGSX5Cs0UA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vite": { + "version": "5.4.21", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vitepress": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/vitepress/-/vitepress-1.6.4.tgz", + "integrity": "sha512-+2ym1/+0VVrbhNyRoFFesVvBvHAVMZMK0rw60E3X/5349M1GuVdKeazuksqopEdvkKwKGs21Q729jX81/bkBJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@docsearch/css": "3.8.2", + "@docsearch/js": "3.8.2", + "@iconify-json/simple-icons": "^1.2.21", + "@shikijs/core": "^2.1.0", + "@shikijs/transformers": "^2.1.0", + "@shikijs/types": "^2.1.0", + "@types/markdown-it": "^14.1.2", + "@vitejs/plugin-vue": "^5.2.1", + "@vue/devtools-api": "^7.7.0", + "@vue/shared": "^3.5.13", + "@vueuse/core": "^12.4.0", + "@vueuse/integrations": "^12.4.0", + "focus-trap": "^7.6.4", + "mark.js": "8.11.1", + "minisearch": "^7.1.1", + "shiki": "^2.1.0", + "vite": "^5.4.14", + "vue": "^3.5.13" + }, + "bin": { + "vitepress": "bin/vitepress.js" + }, + "peerDependencies": { + "markdown-it-mathjax3": "^4", + "postcss": "^8" + }, + "peerDependenciesMeta": { + "markdown-it-mathjax3": { + "optional": true + }, + "postcss": { + "optional": true + } + } + }, + "node_modules/vue": { + "version": "3.5.25", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.25.tgz", + "integrity": "sha512-YLVdgv2K13WJ6n+kD5owehKtEXwdwXuj2TTyJMsO7pSeKw2bfRNZGjhB7YzrpbMYj5b5QsUebHpOqR3R3ziy/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.25", + "@vue/compiler-sfc": "3.5.25", + "@vue/runtime-dom": "3.5.25", + "@vue/server-renderer": "3.5.25", + "@vue/shared": "3.5.25" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/web-resource-inliner": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/web-resource-inliner/-/web-resource-inliner-6.0.1.tgz", + "integrity": "sha512-kfqDxt5dTB1JhqsCUQVFDj0rmY+4HLwGQIsLPbyrsN9y9WV/1oFDSx3BQ4GfCv9X+jVeQ7rouTqwK53rA/7t8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.1", + "escape-goat": "^3.0.0", + "htmlparser2": "^5.0.0", + "mime": "^2.4.6", + "node-fetch": "^2.6.0", + "valid-data-url": "^3.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/web-resource-inliner/node_modules/domhandler": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz", + "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.0.1" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/web-resource-inliner/node_modules/htmlparser2": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-5.0.1.tgz", + "integrity": "sha512-vKZZra6CSe9qsJzh0BjBGXo8dvzNsq/oGvsjfRdOrrryfeD9UOBEEQdeoqCRmKZchF5h2zOBMQ6YuQ0uRUmdbQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^3.3.0", + "domutils": "^2.4.2", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/fb55/htmlparser2?sponsor=1" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/wicked-good-xpath": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/wicked-good-xpath/-/wicked-good-xpath-1.3.0.tgz", + "integrity": "sha512-Gd9+TUn5nXdwj/hFsPVx5cuHHiF5Bwuc30jZ4+ronF1qHK5O7HD0sgmXWSEgwKquT3ClLoKPVbO6qGwVwLzvAw==", + "dev": true, + "license": "MIT" + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..cef6f37 --- /dev/null +++ b/package.json @@ -0,0 +1,18 @@ +{ + "name": "learn-ai", + "version": "1.0.0", + "description": "面向软件工程专业毕业生的中文人工智能入门学习教程网站。", + "type": "module", + "scripts": { + "docs:dev": "vitepress dev docs", + "docs:build": "vitepress build docs", + "docs:preview": "vitepress preview docs" + }, + "keywords": ["ai", "machine-learning", "deep-learning", "tutorial", "chinese"], + "author": "", + "license": "MIT", + "devDependencies": { + "markdown-it-mathjax3": "^4.3.2", + "vitepress": "^1.6.4" + } +}