Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
__pycache__/
*.pyc
output/
102 changes: 100 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,100 @@
# Program-Management-System
用于座舱项目管理风险汇报
# ProjectAI 自动项目管控工具

ProjectAI 是面向智能座舱项目管理团队的 AI 自动项目管控工具样例,实现了数据采集、风险识别、日报生成与通知提醒的最小可行产品(MVP)。

## 功能概览

- **信息抓取**:从示例飞书文档、表格、群消息数据中提取任务与事件。
- **风险识别**:通过规则 + AI 推理思路(此处以规则示例实现)识别延期、阻塞、进度滞后等风险。
- **日报生成**:根据模板自动生成日报文本并保存到本地文件。
- **通知提醒**:对高风险任务生成待发送的飞书提醒内容。

## 目录结构

```
├── config/ # 示例配置
├── data/ # 示例飞书导出数据
├── output/ # 日报输出目录
├── src/project_ai/ # 核心源码
│ ├── data_sources/ # 数据抓取与解析
│ ├── models/ # 数据模型与风险模型
│ ├── services/ # 风险识别、报告、通知等服务
│ └── templates/ # 日报模板
```

## 快速开始

1. 创建虚拟环境并安装依赖(本示例使用 Python 标准库,无需额外依赖)。
2. 执行以下命令运行完整流程:

```bash
python run.py run --config config/sample_config.json
```

3. 运行结束后,在 `output/daily_report.txt` 中查看生成的日报,同时命令行会输出需要发送的高风险提醒。

## 配置说明

`config/sample_config.json` 包含以下配置项:

- `feishu`:指定示例数据文件路径,可替换为真实的 Feishu API 数据抓取逻辑。
- `report.output_path`:日报输出路径。
- `report.template_path`:日报模板,可根据团队格式自定义。
- `notifications`:通知开关、接收人列表与高风险提醒阈值。

## 接入真实飞书云文档

要使用企业自建应用(例如用户提供的 `APP ID: cli_a87f247f8b33d00c`、`APP Secret: HCSvCW70fv9hh6M9VkxTMdOhMxeE8gQn`、`Tenant: t-g104aka8DBCSH47JL6L6XSSUP7Y7N3WJZIAXNMHE`)访问真实的飞书云文档内容,请按照以下步骤操作:

1. 安装网络依赖:

```bash
pip install requests
```

2. 在配置中启用 API 模式,例如复制一份 `config/sample_config.json`,并将 `feishu.mode` 设置为 `"api"`,同时在 `feishu.api` 中填写凭据与需要同步的文档 ID:

```json
{
"feishu": {
"mode": "api",
"api": {
"app_id": "cli_a87f247f8b33d00c",
"app_secret": "HCSvCW70fv9hh6M9VkxTMdOhMxeE8gQn",
"tenant_key": "t-g104aka8DBCSH47JL6L6XSSUP7Y7N3WJZIAXNMHE",
"document_ids": ["doccnXXXXXXXXXXXXXX"]
}
}
}
```

> 为保障安全,生产环境推荐通过环境变量或密钥服务注入上述敏感配置。

3. 执行命令:

```bash
python run.py run --config config/your_api_config.json
```

`FeishuAPIClient` 会自动调用云文档的 `raw_content` 与 `content` 接口,解析其中的待办(`- [ ]` 或 `TODO`)条目并生成任务,同时同步文档元数据更新时间。

4. 如需同步多维表格、群聊消息,可在 `feishu.api.bitable`、`feishu.api.chat_ids` 中继续填充配置,客户端会自动调用相关接口。

有关鉴权流程、字段映射与分页策略的更多说明,请参阅 [docs/feishu_api_integration.md](docs/feishu_api_integration.md)。

## 后续扩展建议

- 接入真实的 Feishu API,实现定时同步项目数据。
- 增加 NLP 模型解析非结构化群聊/文档内容,提取更多任务语义。
- 结合历史数据和机器学习模型,优化风险识别准确率。
- 构建 Web 看板展示进度、风险趋势,并加入甘特图等可视化能力。

## 许可证

本示例项目用于演示 AI 自动项目管控的基础能力,可根据团队需要自由扩展与修改。

## 飞书 API 集成设计

- 当前仓库默认使用本地 JSON 示例数据(`mode=local_files`)。
- 若需接入真实飞书接口,请参考 [docs/feishu_api_integration.md](docs/feishu_api_integration.md),其中包含鉴权、数据抓取、配置结构与迁移步骤的完整设计。
- API 模式需要额外安装 `requests` 等网络依赖,并在配置中提供企业自建应用的凭据。
25 changes: 25 additions & 0 deletions config/sample_config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"feishu": {
"documents": [
"data/document_tasks.json"
],
"sheets": [
"data/sheet_tasks.json"
],
"messages": [
"data/messages.json"
],
"mode": "local_files"
},
"report": {
"output_path": "output/daily_report.txt",
"template_path": "src/project_ai/templates/daily_report_template.txt"
},
"notifications": {
"enabled": true,
"recipients": [
"project.manager@feishu"
],
"high_risk_threshold": 3
}
}
24 changes: 24 additions & 0 deletions data/document_tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"tasks": [
{
"id": "DOC-101",
"title": "语音交互需求评审",
"owner": "张伟",
"due_date": "2024-05-10",
"status": "completed",
"progress": 100,
"description": "完成语音交互模块的需求评审",
"blockers": null
},
{
"id": "DOC-102",
"title": "驾驶舱 UI 设计验收",
"owner": "李娜",
"due_date": "2024-05-14",
"status": "in progress",
"progress": 45,
"description": "与设计团队确认交互细节",
"blockers": null
}
]
}
12 changes: 12 additions & 0 deletions data/messages.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"events": [
{
"timestamp": "2024-05-11 09:30",
"summary": "产品经理在群内确认语音交互需求已冻结。"
},
{
"timestamp": "2024-05-11 15:00",
"summary": "传感器团队预计 5 月 13 日提供新固件。"
}
]
}
24 changes: 24 additions & 0 deletions data/sheet_tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"tasks": [
{
"id": "SHEET-201",
"title": "智能导航算法联调",
"owner": "王强",
"due_date": "2024-05-12",
"status": "blocked",
"progress": 30,
"description": "等待传感器团队提供最新固件",
"blockers": "传感器固件未发布"
},
{
"id": "SHEET-202",
"title": "驾驶行为模型验证",
"owner": "陈晨",
"due_date": "2024-05-16",
"status": "not started",
"progress": 10,
"description": "搭建仿真环境并验证模型数据",
"blockers": null
}
]
}
150 changes: 150 additions & 0 deletions docs/feishu_api_integration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
# 飞书 API 集成设计方案

本方案阐述如何将当前依赖本地 JSON 示例数据的 ProjectAI 项目接入真实的飞书开放平台接口,实现项目数据的自动抓取、风险分析、日报生成与通知提醒的闭环。

## 设计目标

1. **统一数据装载接口**:保留现有的 `FeishuClient` 以支持本地调试,同时新增基于飞书开放平台的 `FeishuAPIClient`,二者实现相同的 `load_project_state()` 接口,便于在配置中切换。
2. **覆盖核心数据源**:支持从多维表格(Bitable)、文档(Docs)、群聊(IM)读取任务与事件信息。
3. **安全合规**:按照飞书平台要求安全存储凭据,管理访问令牌,并记录关键操作日志。
4. **可扩展性**:为后续扩展(例如甘特图、看板、更多数据源)预留结构。

## 系统架构调整

```
┌────────────────────┐
│ run.py / CLI │
└─────────┬──────────┘
┌─────────▼──────────┐
│ IngestionService │ 根据配置选择数据客户端(本地 / API)
└─────────┬──────────┘
┌───────▼───────────────────────────────────────┐
│ Data Sources │
│ • FeishuClient ← 本地 JSON 示例数据 │
│ • FeishuAPIClient ← 飞书开放平台接口 │
└───────┬───────────────────────────────────────┘
│ ProjectState
┌─────────▼──────────┐
│ Risk / Report / ...│
└────────────────────┘
```

`FeishuAPIClient` 负责:

- 统一鉴权(Tenant Access Token 与 User Access Token 管理)。
- 调用 Docs、Bitable、IM 等接口并抽取数据。
- 数据清洗、字段映射、增量同步与缓存控制。

## 关键模块设计

### 1. 配置结构

在 `config` 中新增 `mode` 与 `api` 子配置,示例:

```json
{
"feishu": {
"mode": "api",
"api": {
"app_id": "cli_xxx",
"app_secret": "xxx",
"tenant_key": "xxx",
"base_url": "https://open.feishu.cn/open-apis",
"document_ids": ["doccnxxxxxxxx"],
"bitable": [
{
"app_token": "bascnxxx",
"table_id": "tblxxx",
"view_id": "vewxxx"
}
],
"chat_ids": ["oc_xxx"],
"sync_window_days": 7
}
}
}
```

### 2. 认证与令牌管理

- 使用**企业自建应用**凭据 (`app_id`, `app_secret`) 通过 `/auth/v3/tenant_access_token/internal` 获取租户令牌。
- 令牌需缓存至内存或可选的 Redis/本地文件,并在过期前自动刷新(默认有效期 2 小时)。
- 如需访问用户维度接口(例如读取私有文档),需集成 OAuth2.0 用户授权流程并持久化 `user_access_token`。
- 在 `FeishuAPIClient` 中实现 `_get_tenant_access_token()` 与 `_ensure_token()`,统一管理请求头。

### 3. 数据抓取

| 数据类型 | API | 解析要点 |
|----------|-----|----------|
| 文档任务 | [Docs Blocks API](https://open.feishu.cn/document/server-docs/docs/docs-docs) | 通过 `/docx/v1/documents/{document_id}/blocks` 遍历段落,使用标记符(例如 `TODO` 列表、表格)提取任务字段。 |
| 多维表格 | [Bitable API](https://open.feishu.cn/document/server-docs/docs/bitable-v1/overview) | `/bitable/v1/apps/{app_token}/tables/{table_id}/records`;字段映射到 `Task`(负责人、截止日期、进度、状态等)。 |
| 群聊消息 | [IM Message API](https://open.feishu.cn/document/server-docs/im-v1/message/list) | 支持按群 ID + 时间窗口分页查询;解析文本、富文本中的关键事件,写入 `ProjectEvent`。 |

实现步骤:

1. 在 `FeishuAPIClient.load_project_state()` 中:
- 调用 `self._fetch_docs_tasks()`、`self._fetch_bitable_tasks()`、`self._fetch_chat_events()`。
- 将结果合并到 `ProjectState`。
2. 针对不同数据源,实现可插拔的解析器:
- `DocTaskParser`:识别段落、清单、表格格式。
- `BitableTaskParser`:根据字段配置映射。
- `ChatEventParser`:基于关键词或正则提取事件摘要。
3. 考虑增量同步,使用 `sync_window_days` 控制查询时间范围,并记录上次同步时间戳。

#### 云文档 API 权限与端点明细

当前可以开放的飞书云文档接口包括:

| 能力 | 接口 | 作用 | 所需权限 Scope |
|------|------|------|----------------|
| 获取文档基本信息 | `GET /docx/v1/documents/{document_id}` | 获取文档标题、拥有者、`revision_id`、最后更新时间等元信息,可用于判断文档是否更新、定位负责人。 | `docx:document:read` |
| 获取文档结构化内容 | `GET /docx/v1/documents/{document_id}/content` | 返回完整的块结构(段落、清单、表格等),便于按层级解析任务列表、关键节点。 | `docx:document:read` |
| 获取文档块列表(分页) | `GET /docx/v1/documents/{document_id}/blocks` | 对于大文档分批获取块列表,可结合 `page_size`/`page_token` 做增量加载,避免一次性下载过大内容。 | `docx:document:read` |
| 获取指定块详情 | `GET /docx/v1/documents/{document_id}/blocks/{block_id}` | 在需要解析表格、待办清单等复杂块时进一步展开子节点,提取任务字段。 | `docx:document:read` |
| 获取文档纯文本 | `GET /docx/v1/documents/{document_id}/raw_content` | 当结构化解析失败时的兜底方案,将全文转为纯文本再用正则/关键词识别任务。 | `docx:document:read` |

> **实现建议**
>
> 1. `FeishuAPIClient` 在同步文档时,先调用“获取文档基本信息”保存 `revision_id`,若与上次同步一致可跳过解析。
> 2. 默认使用 “结构化内容” 接口一次性获取文档树;当文档体量较大或需要定期增量更新时,切换至“块列表 + 指定块详情”组合,基于 `page_token` 做分页。
> 3. 解析过程中建议保留块的 `block_type` 与 `text`/`elements` 信息,方便映射到 `Task` 字段(如负责人、截止日期、状态标签)。
> 4. 如果需要读取协作者或评论,需额外开通 `docx:comment:read` 等权限,此处按当前可开放的接口规划。

### 4. 错误处理与重试

- 封装统一的 `_request()` 方法:
- 注入鉴权头、幂等 ID(`X-Request-ID`)。
- 对 429/5xx 状态码进行指数退避重试。
- 记录请求与响应摘要,便于审计。
- 对解析失败的记录写入告警日志,同时继续处理其他数据,避免单条数据阻塞流程。

### 5. 安全与合规

- 所有敏感信息通过环境变量或密钥管理服务传入,避免硬编码在仓库中。
- 如果部署在服务器,需要限制日志中出现的个人信息;对导出的任务/消息内容进行脱敏处理。
- 结合企业内部安全规范,评估权限最小化策略(仅授予必要的 API 权限)。

### 6. 测试策略

1. **单元测试**:为 `FeishuAPIClient` 的解析函数编写 Mock 响应,确保字段映射准确。
2. **集成测试**:使用飞书提供的沙箱或测试租户进行端到端验证,确认鉴权、分页、重试逻辑正确。
3. **回归测试**:保留原有本地 JSON 数据模式,确保 `mode=local_files` 时行为不变。
4. **监控验证**:对接后在生产环境添加成功率、延迟、错误码等监控指标。

### 7. 迁移步骤

1. **准备环境**:创建飞书企业自建应用,配置回调与权限,获取 `app_id`/`app_secret`。
2. **实现 API 客户端**:按照本文设计补全 `FeishuAPIClient`,并接入解析器(当前实现已对接云文档 `raw_content` 与 `content` 接口,可直接解析待办事项为任务数据)。
3. **本地验证**:在测试租户中配置 `config`,运行 `python run.py run --config ...` 检查输出。
4. **部署密钥管理**:将凭据注入运行环境,添加日志与监控。
5. **灰度发布**:小范围启用 API 模式,观察日报与提醒准确性,再逐步覆盖所有项目。

### 8. 后续扩展

- 支持事件回调(Webhook)触发增量同步,减少轮询成本。
- 引入缓存层(Redis)保存原始响应,支持调试回放。
- 为 IM 消息推送实现真正的机器人 Webhook 调用,实现自动提醒发送。

通过以上设计,即可在保持现有代码结构的前提下,无缝切换到真实的飞书 API,实现项目数据的自动化获取与处理。
19 changes: 19 additions & 0 deletions run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from __future__ import annotations

import sys
from pathlib import Path


def main() -> None:
project_root = Path(__file__).parent
src_path = project_root / "src"
if str(src_path) not in sys.path:
sys.path.insert(0, str(src_path))

from project_ai.cli import main as cli_main # noqa: WPS433 - runtime import for path setup

cli_main()


if __name__ == "__main__":
main()
5 changes: 5 additions & 0 deletions src/project_ai/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"""ProjectAI - AI 驱动的项目风险识别与日报生成工具。"""

from .cli import main

__all__ = ["main"]
Loading