Major Changes: - Add StreamingService with OpenAI Compatible format - Upgrade Chat component V2 with Ant Design X integration - Implement AIA module with 12 intelligent agents - Update API routes to unified /api/v1 prefix - Update system documentation Backend (~1300 lines): - common/streaming: OpenAI Compatible adapter - modules/aia: 12 agents, conversation service, streaming integration - Update route versions (RVW, PKB to v1) Frontend (~3500 lines): - modules/aia: AgentHub + ChatWorkspace (100% prototype restoration) - shared/Chat: AIStreamChat, ThinkingBlock, useAIStream Hook - Update API endpoints to v1 Documentation: - AIA module status guide - Universal capabilities catalog - System overview updates - All module documentation sync Tested: Stream response verified, authentication working Status: AIA V2.0 core completed (85%)
2062 lines
67 KiB
Markdown
2062 lines
67 KiB
Markdown
# 宸ュ叿C - 绉戠爺鏁版嵁缂栬緫鍣?MVP寮€鍙戣<E98D99>鍒?
|
||
|
||
> **鏂囨。鐗堟湰锛?* V1.0 (鍔″疄蹇<E79684>€熼獙璇佺増)
|
||
> **鍒涘缓鏃ユ湡锛?* 2025-12-06
|
||
> **璁″垝鍛ㄦ湡锛?* 3鍛<33>紙15涓<35>伐浣滄棩锛?
|
||
> **鏍稿績绛栫暐锛?* 鐢ㄦ渶灏忔垚鏈<E59E9A>獙璇佹牳蹇冨亣璁撅紝蹇<E7B49D>€熷け璐ヤ紭浜庡畬缇庤<E7BC87>鍒?
|
||
> **鐘舵€侊細** 寰呭惎鍔?
|
||
|
||
---
|
||
|
||
## 鈿狅笍 寮€鍙戝墠蹇呰<E8B987>锛氫弗鏍奸伒瀹堢幇鏈夋灦鏋勪笌瑙勮寖
|
||
|
||
### 馃敶 涓嶈<E6B693>閲嶅<E996B2>閫犺疆瀛愶紒澶嶇敤骞冲彴鑳藉姏
|
||
|
||
**鏈<>」鐩<E3808D>凡鏈夊畬鏁寸殑3灞傛灦鏋勪綋绯诲拰骞冲彴鍩虹<E98DA9>璁炬柦锛屾墍鏈変唬鐮佸繀椤诲<E6A4A4>鐢ㄧ幇鏈夎兘鍔涳細**
|
||
|
||
#### 骞冲彴鍩虹<E98DA9>灞傦紙鉁?宸插畬鎴愶紝鐩存帴浣跨敤锛?
|
||
|
||
| 鏈嶅姟 | 瀵煎叆鏂瑰紡 | 鐢ㄩ€?| 鏂囨。 |
|
||
|------|---------|------|------|
|
||
| **瀛樺偍鏈嶅姟** | `import { storage } from '@/common/storage'` | 鏂囦欢涓婁紶涓嬭浇 | 鉁?蹇呴』浣跨敤 |
|
||
| **鏃ュ織绯荤粺** | `import { logger } from '@/common/logging'` | 鏍囧噯鍖栨棩蹇?| 鉁?蹇呴』浣跨敤 |
|
||
| **缂撳瓨鏈嶅姟** | `import { cache } from '@/common/cache'` | 鍒嗗竷寮忕紦瀛?| 鉁?蹇呴』浣跨敤 |
|
||
| **寮傛<E5AFAE>浠诲姟** | `import { jobQueue } from '@/common/jobs'` | 闀挎椂闂翠换鍔?| 鉁?蹇呴』浣跨敤 |
|
||
| **鏁版嵁搴?* | `import { prisma } from '@/config/database'` | 鏁版嵁搴撴搷浣?| 鉁?蹇呴』浣跨敤 |
|
||
| **LLM鑳藉姏** | `import { LLMFactory } from '@/common/llm'` | LLM璋冪敤 | 鉁?蹇呴』浣跨敤 |
|
||
|
||
#### 浜戝師鐢熷紑鍙戣<E98D99>鑼冿紙鉁?寮哄埗鎵ц<E98EB5>锛?
|
||
|
||
**璇︾粏鏂囨。**锛歚docs/04-寮€鍙戣<E98D99>鑼?08-浜戝師鐢熷紑鍙戣<E98D99>鑼?md`
|
||
|
||
**鏍稿績瑕佹眰锛?*
|
||
- 鉁?**鏂囦欢瀛樺偍**锛氫娇鐢╜storage.upload()`锛屼笉瑕佺敤`fs.writeFile()`
|
||
- 鉁?**Session绠$悊**锛氬瓨鏁版嵁搴擄紝涓嶈<E6B693>鐢╜Map<sessionId, data>`
|
||
- 鉁?**鏃ュ織杈撳嚭**锛氫娇鐢╜logger.info()`锛屼笉瑕佺敤`console.log()`
|
||
- 鉁?**鏁版嵁搴撹繛鎺?*锛氫娇鐢ㄥ叏灞€`prisma`瀹炰緥锛屼笉瑕乣new PrismaClient()`
|
||
- 鉁?**LLM璋冪敤**锛氫娇鐢╜LLMFactory.getLLM()`锛屼笉瑕佽嚜宸遍泦鎴?
|
||
- 鉂?**绂佹<E7BB82>鏈<EFBFBD>湴鏂囦欢瀛樺偍**锛欵xcel鐩存帴浠庡唴瀛樿В鏋?
|
||
- 鉂?**绂佹<E7BB82>鍐呭瓨缂撳瓨Map**锛氱敤鏁版嵁搴撴垨cache鏈嶅姟
|
||
- 鉂?**绂佹<E7BB82>纭<EFBFBD>紪鐮侀厤缃?*锛氫娇鐢ㄧ幆澧冨彉閲?
|
||
|
||
#### 浠g爜鏂囦欢澶圭粨鏋勶紙鉁?鍙傝€僼ool-b锛?
|
||
|
||
**鍚庣<E98D9A>**锛?
|
||
```
|
||
backend/src/modules/dc/tool-c/ 鈫?宸插瓨鍦?
|
||
鈹溾攢鈹€ services/ 鈫?涓氬姟閫昏緫
|
||
鈹溾攢鈹€ controllers/ 鈫?HTTP鎺у埗鍣?
|
||
鈹溾攢鈹€ routes/ 鈫?璺<>敱瀹氫箟
|
||
鈹斺攢鈹€ utils/ 鈫?宸ュ叿鍑芥暟
|
||
```
|
||
|
||
**鍓嶇<E98D93>**锛?
|
||
```
|
||
frontend-v2/src/modules/dc/pages/tool-c/ 鈫?宸插瓨鍦?
|
||
```
|
||
|
||
#### 甯歌<E794AF>閿欒<E996BF>绀轰緥锛堚潓 涓ョ<E6B693>锛?
|
||
|
||
```typescript
|
||
// 鉂?閿欒<E996BF>1锛氳嚜宸卞疄鐜癝ession绠$悊
|
||
const sessions = new Map<string, any>(); // 杩濆弽瑙勮寖锛?
|
||
|
||
// 鉂?閿欒<E996BF>2锛氭湰鍦版枃浠跺瓨鍌?
|
||
fs.writeFileSync('./uploads/file.xlsx', buffer); // 杩濆弽瑙勮寖锛?
|
||
|
||
// 鉂?閿欒<E996BF>3锛氫笉鐢╨ogger
|
||
console.log('User uploaded file'); // 杩濆弽瑙勮寖锛?
|
||
|
||
// 鉂?閿欒<E996BF>4锛氭柊寤篜risma瀹炰緥
|
||
const prisma = new PrismaClient(); // 杩濆弽瑙勮寖锛?
|
||
|
||
// 鉂?閿欒<E996BF>5锛氳嚜宸遍泦鎴怢LM
|
||
import Anthropic from '@anthropic-ai/sdk'; // 杩濆弽瑙勮寖锛?
|
||
```
|
||
|
||
**姝g‘绀轰緥锛堚渽 蹇呴』锛?*锛氬弬鑰冩湰鏂囨。Day 1-5鐨勪唬鐮佺ず渚?
|
||
|
||
---
|
||
|
||
## 馃搵 鐩<>綍
|
||
|
||
- [寮€鍙戝墠蹇呰<E8B987>](#寮€鍙戝墠蹇呰<EFBFBD>涓ユ牸閬靛畧鐜版湁鏋舵瀯涓庤<EFBFBD>鑼?
|
||
- [涓€銆丮VP鏍稿績鐩<EFBFBD>爣](#涓€mvp鏍稿績鐩<E7B8BE>爣)
|
||
- [浜屻€佹妧鏈<EFBFBD>灦鏋勬柟妗堬紙鍔″疄鐗堬級](#浜屾妧鏈<E5A6A7>灦鏋勬柟妗堝姟瀹炵増)
|
||
- [涓夈€佸姛鑳戒紭鍏堢骇鐭╅樀](#涓夊姛鑳戒紭鍏堢骇鐭╅樀)
|
||
- [鍥涖€?鍛ㄨ<E98D9B>缁嗗紑鍙戣<E98D99>鍒抅(#鍥?鍛ㄨ<E98D9B>缁嗗紑鍙戣<E98D99>鍒?
|
||
- [浜斻€侀<E282AC>闄╁簲瀵圭瓥鐣<E793A5>(#浜旈<EFBFBD>闄╁簲瀵圭瓥鐣?
|
||
- [鍏<>€侀獙鏀舵爣鍑哴(#鍏<EFBFBD>獙鏀舵爣鍑?
|
||
- [涓冦€佸揩閫熷け璐ユ満鍒禲(#涓冨揩閫熷け璐ユ満鍒?
|
||
|
||
---
|
||
|
||
## 涓€銆丮VP鏍稿績鐩<E7B8BE>爣
|
||
|
||
### 1.1 鏍稿績鍋囪<E98D8B>楠岃瘉
|
||
|
||
**鎴戜滑闇€瑕侀獙璇佺殑3涓<33>牳蹇冨亣璁撅細**
|
||
|
||
| 鍋囪<E98D8B> | 楠岃瘉鏂瑰紡 | 鎴愬姛鏍囧噯 | 澶辫触鍚庢灉 |
|
||
|------|---------|---------|---------|
|
||
| **H1: AI鑳界敓鎴愰珮璐ㄩ噺Pandas浠g爜骞舵垚鍔熸墽琛?* | 15涓<35>湡瀹炲満鏅<E6BA80>祴璇?| 鎬讳綋鎴愬姛鐜?> 80% | MVP澶辫触锛屾敼鐢ㄤ唬鐮佹ā鏉垮簱 |
|
||
| **H2: Python浠g爜鎵ц<E98EB5>鐜<EFBFBD><E9909C>绋冲畾鍙<E795BE>潬** | 澶嶆潅鍦烘櫙娴嬭瘯 | 楂樼骇鍦烘櫙鎴愬姛鐜?> 60% | 绠€鍖栦负鎵瑰<E98EB5>鐞嗘ā寮?|
|
||
| **H3: 宸﹁〃鏍?鍙矨I鐨勪氦浜掓ā寮忓ソ鐢?* | 鐢ㄦ埛浣撻獙娴嬭瘯 | 鐢ㄦ埛鑳界嫭绔嬪畬鎴愪换鍔?| 閲嶆柊璁捐<E79281>UI浜や簰 |
|
||
| **H4: 鎬ц兘鍙<E58598>帴鍙楋紙鍚玃ython鎵ц<E98EB5>锛?* | 鎬ц兘娴嬭瘯 | 绔<>埌绔?< 20绉?| 浼樺寲Python鎵ц<E98EB5>鎴栨敼鎵瑰<E98EB5>鐞?|
|
||
|
||
**鈿狅笍 鏍稿績浠峰€间富寮狅細**
|
||
- 鉁?**AI鐢熸垚浠g爜 + 鐪熷疄鎵ц<E98EB5> + 琛ㄦ牸鍒锋柊**鏄<>伐鍏稢鐨勫樊寮傚寲浠峰€?
|
||
- 鉁?濡傛灉鍙<E78189>敓鎴愪唬鐮佷笉鎵ц<E98EB5>锛岀敤鎴疯繕涓嶅<E6B693>鐩存帴鐢–hatGPT
|
||
- 鉁?Python鎵ц<E98EB5>鐜<EFBFBD><E9909C>鏄疢VP鐨?*鎶€鏈<E282AC>牳蹇?*锛屼笉鏄<E7AC89>彲閫夐」
|
||
|
||
### 1.2 MVP鍔熻兘鑼冨洿
|
||
|
||
**鉁?MVP蹇呴』鏈夌殑锛圥0锛夛細**
|
||
1. 鏂囦欢涓婁紶锛?0MB闄愬埗锛?
|
||
2. 琛ㄦ牸灞曠ず锛圓G Grid锛?00琛岄<E7909B>瑙堬級
|
||
3. AI瀵硅瘽鐣岄潰锛堝彸渚т晶杈规爮锛?
|
||
4. AI浠g爜鐢熸垚锛圖eepSeek-V3锛?
|
||
5. 浠g爜鎵ц<E98EB5>锛圥ython娌欑<E5A88C>锛?
|
||
6. UI閿佸畾鏈哄埗锛圓I澶勭悊鏃惰〃鏍煎彧璇伙級
|
||
7. AST瀹夊叏妫€鏌?
|
||
8. 琛ㄦ牸鑷<E789B8>姩鍒锋柊
|
||
9. 瀵煎嚭Excel
|
||
|
||
**鉂?MVP鏄庣‘涓嶅仛鐨勶細**
|
||
- 鎵嬪姩缂栬緫鍗曞厓鏍硷紙涓撴敞AI鑳藉姏锛?
|
||
- 鎾ら攢/鍥炴粴锛堣妭鐪佸唴瀛橈級
|
||
- Apache Arrow锛堝厛鐢↗SON锛?
|
||
- Redis浼氳瘽锛堢敤杩涚▼鍐呭瓨锛?
|
||
- 鏍峰紡淇濈暀锛堢洿鎺ヨ<E98EBA>鐩栵級
|
||
- 鎿嶄綔瀹¤<E780B9>鏃ュ織
|
||
- 鍗忓悓缂栬緫
|
||
|
||
### 1.3 MVP浜や粯鐗?
|
||
|
||
**鏈€缁堟紨绀哄満鏅<E6BA80>細**
|
||
```
|
||
鐢ㄦ埛涓婁紶 "lung_cancer_patients.xlsx" (5000琛?脳 20鍒?
|
||
鈫?
|
||
宸︿晶鏄剧ず鏁版嵁琛ㄦ牸锛屽彸渚<EFBFBD>I鍔╂墜鍑嗗<EFBFBD>灏辩华
|
||
鈫?
|
||
鐢ㄦ埛瀵笰I璇达細"鎶婂勾榫勫ぇ浜?0鐨勬偅鑰呮爣璁颁负鑰佸勾缁?
|
||
鈫?
|
||
AI鐢熸垚浠g爜 鈫?灞曠ず棰勬搷浣滃崱鐗?鈫?鐢ㄦ埛纭<E59F9B><E7BAAD> 鈫?鎵ц<E98EB5>鎴愬姛
|
||
鈫?
|
||
琛ㄦ牸鑷<EFBFBD>姩鍒锋柊锛屾柊澧?age_group"鍒?
|
||
鈫?
|
||
鐢ㄦ埛缁х画璇达細"鍒犻櫎鎵€鏈夌己澶辨偅鑰匢D鐨勮<E990A8>"
|
||
鈫?
|
||
AI鎵ц<EFBFBD> 鈫?琛ㄦ牸鍒锋柊锛屾樉绀哄垹闄や簡23琛?
|
||
鈫?
|
||
鐢ㄦ埛鐐瑰嚮"瀵煎嚭"锛屼笅杞藉<E69D9E>鐞嗗悗鐨凟xcel
|
||
```
|
||
|
||
**鎴愬姛鏍囧噯锛?*
|
||
- 鉁?鏁翠釜娴佺▼ < 2鍒嗛挓瀹屾垚
|
||
- 鉁?AI浠g爜涓€娆℃€ф墽琛屾垚鍔?
|
||
- 鉁?鐢ㄦ埛鏃犻渶鐪嬫枃妗e氨鑳芥搷浣?
|
||
|
||
---
|
||
|
||
## 浜屻€佹妧鏈<E5A6A7>灦鏋勬柟妗堬紙鍔″疄鐗堬級
|
||
|
||
### 2.1 鎬讳綋鏋舵瀯锛堢畝鍖栫増锛? 鈿狅笍 閲嶈<E996B2>锛氬<E9949B>鐢ㄥ钩鍙拌兘鍔?
|
||
|
||
```
|
||
鈹屸攢鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹?
|
||
鈹? 鍓嶇<E98D93> (React) 鈹?
|
||
鈹? frontend-v2/src/modules/dc/pages/tool-c/ 鈹?
|
||
鈹? 鈹屸攢鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹? 鈹屸攢鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹? 鈹?
|
||
鈹? 鈹?AG Grid (70%) 鈹? 鈹?AI Chat Sidebar (30%) 鈹? 鈹?
|
||
鈹? 鈹?鈥?灞曠ず100琛屾暟鎹? 鈹? 鈹?鈥?鑷<>劧璇<E58AA7>█杈撳叆 鈹? 鈹?
|
||
鈹? 鈹?鈥?鍙<><E98D99>妯″紡鍒囨崲 鈹? 鈹?鈥?棰勬搷浣滃崱鐗? 鈹? 鈹?
|
||
鈹? 鈹?鈥?閿佸畾閬<E795BE>僵 鈹? 鈹?鈥?娑堟伅鍘嗗彶 鈹? 鈹?
|
||
鈹? 鈹斺攢鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹? 鈹斺攢鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹? 鈹?
|
||
鈹斺攢鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹?
|
||
鈫?REST API (JSON)
|
||
鈹屸攢鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹?
|
||
鈹? Node.js鍚庣<E98D9A> (backend/src/modules/dc/tool-c/) 鈹?
|
||
鈹? 鈥?鏂囦欢涓婁紶锛堝<E9949B>鐢╯torage鏈嶅姟锛夆渽 鈹?
|
||
鈹? 鈥?浼氳瘽绠$悊锛堝瓨鏁版嵁搴擄紝涓嶇敤鍐呭瓨Map锛夆渽 鈹?
|
||
鈹? 鈥?LLM闆嗘垚锛堝<E9949B>鐢↙LMFactory锛夆渽 鈹?
|
||
鈹? 鈥?鏃ュ織璁板綍锛堝<E9949B>鐢╨ogger锛夆渽 鈹?
|
||
鈹? 鈥?寮傛<E5AFAE>浠诲姟锛堝<E9949B>鐢╦obQueue锛夆渽 鈹?
|
||
鈹斺攢鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹?
|
||
鈫?HTTP锛堝<E9949B>闇€Python鎵ц<E98EB5>锛?
|
||
鈹屸攢鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹?
|
||
鈹? Python寰<6E>湇鍔★紙鍙<E7B499>€夛紝鎵╁睍鏂囨。澶勭悊寮曟搸锛? 鈹?
|
||
鈹? 鈥?DataFrame绠$悊锛堝瓨鏁版嵁搴擄紝涓嶇敤鍐呭瓨锛? 鈹?
|
||
鈹? 鈥?exec()浠g爜鎵ц<E98EB5> 鈹?
|
||
鈹? 鈥?AST闈欐€佸畨鍏ㄦ<E98D8F>鏌? 鈹?
|
||
鈹? 鈥?JSON搴忓垪鍖栬繑鍥? 鈹?
|
||
鈹斺攢鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹?
|
||
```
|
||
|
||
**鈿狅笍 浜戝師鐢熸灦鏋勫己鍒惰<E98D92>姹傦細**
|
||
- 鉁?**澶嶇敤storage鏈嶅姟**锛歚import { storage } from '@/common/storage'`
|
||
- 鉁?**澶嶇敤logger鏈嶅姟**锛歚import { logger } from '@/common/logging'`
|
||
- 鉁?**澶嶇敤cache鏈嶅姟**锛歚import { cache } from '@/common/cache'`
|
||
- 鉁?**澶嶇敤LLMFactory**锛歚import { LLMFactory } from '@/common/llm'`
|
||
- 鉁?**澶嶇敤prisma瀹炰緥**锛歚import { prisma } from '@/config/database'`
|
||
- 鉁?**Session瀛樻暟鎹<E69A9F>簱**锛氫笉鐢ㄥ唴瀛楳ap锛堣繚鍙嶈<E98D99>鑼冿級
|
||
- 鉂?**绂佹<E7BB82>鏈<EFBFBD>湴鏂囦欢瀛樺偍**锛欵xcel鐩存帴浠庡唴瀛樿В鏋?
|
||
- 鉂?**绂佹<E7BB82>鏂板缓Prisma瀹炰緥**锛氫娇鐢ㄥ叏灞€瀹炰緥
|
||
|
||
**鍏抽敭鍐崇瓥锛?*
|
||
- 鉁?**涓嶇敤Apache Arrow**锛欽SON澶熷揩锛?00琛?鈮?20KB锛?
|
||
- 鉁?**Session瀛樻暟鎹<E69A9F>簱**锛氱<E9949B>鍚堜簯鍘熺敓瑙勮寖锛屾敮鎸佸<E98EB8>瀹炰緥
|
||
- 鉁?**涓嶅仛鎾ら攢**锛氳妭鐪佸紑鍙戞椂闂达紝鐢ㄦ埛閲嶆柊涓婁紶鍗冲彲
|
||
- 鉁?**涓嶄繚鐣欐牱寮?*锛氱洿鎺ョ敓鎴愭柊Excel
|
||
|
||
### 2.2 鎶€鏈<E282AC>爤閫夊瀷锛堚渽 澶嶇敤鐜版湁鎶€鏈<E282AC>爤锛?
|
||
|
||
#### 鍓嶇<E98D93>锛坒rontend-v2锛?
|
||
```json
|
||
{
|
||
"framework": "React 19 + TypeScript 5 (宸叉湁)",
|
||
"table": "AG Grid Community (鍏嶈垂鐗?",
|
||
"ui": "Ant Design 5 (宸叉湁)",
|
||
"state": "React Query v5 (宸叉湁)",
|
||
"http": "axios (宸叉湁)",
|
||
"routing": "React Router DOM v6 (宸叉湁)"
|
||
}
|
||
```
|
||
|
||
#### Node.js鍚庣<E98D9A>锛坆ackend锛?
|
||
```json
|
||
{
|
||
"framework": "Fastify v4 (宸叉湁)",
|
||
"llm": "鉁?澶嶇敤 LLMFactory (骞冲彴閫氱敤鑳藉姏灞?",
|
||
"storage": "鉁?澶嶇敤 storage鏈嶅姟 (骞冲彴鍩虹<E98DA9>灞?",
|
||
"logging": "鉁?澶嶇敤 logger鏈嶅姟 (骞冲彴鍩虹<E98DA9>灞?",
|
||
"cache": "鉁?澶嶇敤 cache鏈嶅姟 (骞冲彴鍩虹<E98DA9>灞?",
|
||
"database": "鉁?澶嶇敤 prisma鍏ㄥ眬瀹炰緥 (骞冲彴鍩虹<E98DA9>灞?",
|
||
"session": "鉁?PostgreSQL (dc_tool_c_sessions琛?",
|
||
"excel": "xlsx 搴擄紙鍐呭瓨瑙f瀽锛?,
|
||
"validation": "Joi"
|
||
}
|
||
```
|
||
|
||
#### Python寰<6E>湇鍔★紙鈿狅笍 鏍稿績鍔熻兘锛屾墿灞曠幇鏈夋湇鍔★級猸愨瓙猸愨瓙猸?
|
||
**鍐崇瓥**锛氣渽 **绯荤粺宸叉湁Python寰<6E>湇鍔★紙FastAPI锛夛紝闇€鎵╁睍浠g爜鎵ц<E98EB5>鍔熻兘**
|
||
|
||
**馃摝 鐜版湁Python鏈嶅姟锛堝凡瀹屾垚锛夛細**
|
||
- 鉁?**extraction_service**锛欶astAPI + PyMuPDF + Pandas + openpyxl
|
||
- 鉁?**绔<>彛**锛?000锛堝凡杩愯<E69DA9>锛?
|
||
- 鉁?**鍔熻兘**锛歅DF/Docx/Txt鏂囨。鎻愬彇銆佽<E98A86>瑷€妫€娴?
|
||
- 鉁?**闆嗘垚**锛歂ode.js閫氳繃ExtractionClient璋冪敤
|
||
- 鉁?**渚濊禆**锛歅andas銆乷penpyxl銆乧hardet銆乴angdetect锛堝凡瀹夎<E780B9>锛?
|
||
|
||
**馃敡 宸ュ叿C闇€瑕佺殑鏂板姛鑳斤細**
|
||
| 鍔熻兘 | 鐜版湁鏈嶅姟 | 闇€姹?| 鏂规<E98F82> |
|
||
|------|---------|------|------|
|
||
| **Pandas浠g爜鎵ц<E98EB5>** | 鉂?涓嶆敮鎸?| 鉁?鏍稿績 | **鏂板<E98F82>API绔<49>偣** `/api/dc/execute` |
|
||
| **Excel涓婁紶** | 鉂?涓嶆敮鎸?| 鉁?闇€瑕?| 澶嶇敤MultiPart涓婁紶 |
|
||
| **DataFrame绠$悊** | 鉂?涓嶆敮鎸?| 鉁?浼氳瘽 | 鏂板<E98F82>Session绠$悊 |
|
||
| **AST浠g爜妫€鏌?* | 鉂?涓嶆敮鎸?| 鉁?蹇呴』 | 鏂板<E98F82>AST妯″潡 |
|
||
| **Excel瀵煎嚭** | 鉂?涓嶆敮鎸?| 鉁?闇€瑕?| 浣跨敤openpyxl锛堝凡瀹夎<E780B9>锛?|
|
||
|
||
**鈿狅笍 涓嶉渶瑕侀噸澶嶅紑鍙戯細**
|
||
- 鉂?涓嶉渶瑕佹柊寤篜ython椤圭洰
|
||
- 鉂?涓嶉渶瑕侀噸鏂板畨瑁匬andas/openpyxl锛堝凡瀹夎<E780B9>锛?
|
||
- 鉂?涓嶉渶瑕侀噸鏂伴厤缃瓼astAPI锛堝凡杩愯<E69DA9>锛?
|
||
- 鉂?涓嶉渶瑕侀噸鏂板啓Node.js璋冪敤閫昏緫锛圗xtractionClient宸插瓨鍦<E793A8>級
|
||
|
||
**鉁?MVP鎵╁睍鏂规<E98F82>锛?*
|
||
```python
|
||
# extraction_service/services/dc_executor.py锛堟柊澧烇級
|
||
import pandas as pd
|
||
import ast
|
||
from typing import Dict, Any
|
||
|
||
def validate_code(code: str) -> Dict[str, Any]:
|
||
"""AST闈欐€佹<EFBFBD>鏌ワ紙瀹夊叏楠岃瘉锛?""
|
||
try:
|
||
tree = ast.parse(code)
|
||
# 绂佹<E7BB82>import os銆乻ys銆乻ubprocess绛?
|
||
for node in ast.walk(tree):
|
||
if isinstance(node, ast.Import):
|
||
for alias in node.names:
|
||
if alias.name in ['os', 'sys', 'subprocess', 'socket']:
|
||
return {'valid': False, 'error': f'绂佹<EFBFBD>瀵煎叆{alias.name}'}
|
||
return {'valid': True}
|
||
except Exception as e:
|
||
return {'valid': False, 'error': str(e)}
|
||
|
||
def execute_pandas_code(data: list, code: str) -> Dict[str, Any]:
|
||
"""鎵ц<EFBFBD>Pandas浠g爜锛堚瓙鏍稿績鍔熻兘锛?""
|
||
try:
|
||
# 1. 瀹夊叏妫€鏌?
|
||
validation = validate_code(code)
|
||
if not validation['valid']:
|
||
return {'success': False, 'error': validation['error']}
|
||
|
||
# 2. 鍔犺浇鏁版嵁
|
||
df = pd.DataFrame(data)
|
||
|
||
# 3. 鎵ц<E98EB5>浠g爜锛堟敞鍏<E6959E>f鍜宲d锛?
|
||
exec(code, {'df': df, 'pd': pd})
|
||
|
||
# 4. 杩斿洖缁撴灉锛堝墠100琛岋級
|
||
return {
|
||
'success': True,
|
||
'data': df.head(100).to_dict('records'),
|
||
'totalRows': len(df),
|
||
'totalCols': len(df.columns),
|
||
'columns': df.columns.tolist()
|
||
}
|
||
except Exception as e:
|
||
return {'success': False, 'error': str(e)}
|
||
```
|
||
|
||
```python
|
||
# extraction_service/main.py锛堟墿灞曪級
|
||
from services.dc_executor import execute_pandas_code, validate_code
|
||
|
||
@app.post("/api/dc/execute")
|
||
async def execute_code(
|
||
data: List[Dict],
|
||
code: str
|
||
):
|
||
"""宸ュ叿C锛氭墽琛孭andas浠g爜"""
|
||
result = execute_pandas_code(data, code)
|
||
return JSONResponse(result)
|
||
|
||
@app.post("/api/dc/validate")
|
||
async def validate_code_endpoint(code: str):
|
||
"""宸ュ叿C锛欰ST浠g爜妫€鏌?""
|
||
result = validate_code(code)
|
||
return JSONResponse(result)
|
||
```
|
||
|
||
**鉁?Node.js璋冪敤锛堝<E9949B>鐢‥xtractionClient妯″紡锛夛細**
|
||
```typescript
|
||
// backend/src/modules/dc/tool-c/services/PythonExecutorService.ts
|
||
import axios from 'axios';
|
||
|
||
const EXTRACTION_SERVICE_URL = process.env.EXTRACTION_SERVICE_URL || 'http://localhost:8000';
|
||
|
||
export class PythonExecutorService {
|
||
async executeCode(data: any[], code: string) {
|
||
const response = await axios.post(`${EXTRACTION_SERVICE_URL}/api/dc/execute`, {
|
||
data,
|
||
code
|
||
});
|
||
return response.data;
|
||
}
|
||
}
|
||
```
|
||
|
||
### 2.3 鏁版嵁娴佽<E5A8B4>璁?
|
||
|
||
**浼氳瘽鐢熷懡鍛ㄦ湡锛?*
|
||
```python
|
||
# 1. 鐢ㄦ埛涓婁紶鏂囦欢
|
||
POST /api/tool-c/session/init
|
||
{
|
||
file: File,
|
||
userId: string
|
||
}
|
||
|
||
# Node.js: 杞<>彂鍒癙ython
|
||
# Python:
|
||
# - 璇诲彇Excel 鈫?DataFrame
|
||
# - 瀛樺叆鍐呭瓨锛歴essions[sessionId] = df
|
||
# - 杩斿洖锛歴essionId + 鏁版嵁姒傝<E5A792>
|
||
|
||
# 2. 鐢ㄦ埛鍙戦€丄I鎸囦护
|
||
POST /api/tool-c/ai/execute
|
||
{
|
||
sessionId: string,
|
||
prompt: string
|
||
}
|
||
|
||
# Node.js:
|
||
# - 鏋勫缓System Prompt锛堝寘鍚<E5AF98>暟鎹<E69A9F>笂涓嬫枃锛?
|
||
# - 璋冪敤LLM鐢熸垚浠g爜
|
||
# - 杞<>彂浠g爜鍒癙ython
|
||
|
||
# Python:
|
||
# - AST妫€鏌?
|
||
# - exec(code)淇<>敼df
|
||
# - 杩斿洖鍓?00琛孞SON
|
||
|
||
# 3. 鐢ㄦ埛瀵煎嚭
|
||
GET /api/tool-c/session/export/{sessionId}
|
||
|
||
# Python:
|
||
# - df.to_excel(buffer)
|
||
# - 杩斿洖浜岃繘鍒舵祦
|
||
```
|
||
|
||
---
|
||
|
||
## 涓夈€佸姛鑳戒紭鍏堢骇鐭╅樀
|
||
|
||
### 3.1 P0绾э細蹇呴』寮€鍙戯紙鏍稿績闂<E7B8BE>幆锛夆瓙猸愨瓙猸愨瓙
|
||
|
||
| ID | 鍔熻兘 | 鎻忚堪 | 楠岃瘉鐩<E79889>爣 | 宸ユ椂 | 璐熻矗浜?|
|
||
|----|------|------|---------|------|--------|
|
||
| **P0-001** | 鏂囦欢涓婁紶 | 鍓嶇<E98D93>Upload缁勪欢 + 10MB闄愬埗 | 鑳藉惁瑙f瀽Excel | 0.5澶?| 鍓嶇<E98D93> |
|
||
| **P0-002** | Session鍒濆<E98D92>鍖?| 鍚庣<E98D9A>鎺ユ敹鏂囦欢锛孭ython鍔犺浇DataFrame | 涓<>枃鍒楀悕銆丟BK缂栫爜 | 1澶?| 鍚庣<E98D9A> |
|
||
| **P0-003** | 琛ㄦ牸灞曠ず | AG Grid灞曠ず100琛屾暟鎹?| 鍒楃被鍨嬭瘑鍒<E79891>€佺┖鍊奸珮浜?| 1澶?| 鍓嶇<E98D93> |
|
||
| **P0-004** | AI瀵硅瘽UI | 鍙充晶渚ц竟鏍忥紝娑堟伅鍒楄〃 | 鑱婂ぉ浜や簰娴佺晠 | 0.5澶?| 鍓嶇<E98D93> |
|
||
| **P0-005** | System Prompt鏋勫缓 | 鍖呭惈鏁版嵁涓婁笅鏂囩殑Prompt | AI鑳界悊瑙f暟鎹<E69A9F>粨鏋?| 1澶?| 鍚庣<E98D9A> |
|
||
| **P0-006** | AI浠g爜鐢熸垚 | 璋冪敤DeepSeek-V3鐢熸垚Pandas浠g爜 | **鎴愬姛鐜?80%** | 2澶?| 鍚庣<E98D9A> |
|
||
| **P0-007** | AST瀹夊叏妫€鏌?| 鎷︽埅鍗遍櫓浠g爜 | `import os`琚<EFBFBD>嫤鎴?| 1澶?| Python |
|
||
| **P0-008** | 浠g爜鎵ц<E98EB5> | exec()鍦ㄦ矙绠变腑杩愯<E69DA9>浠g爜 | 淇<>敼DataFrame鎴愬姛 | 1澶?| Python |
|
||
| **P0-009** | 棰勬搷浣滃崱鐗?| 灞曠ず浠g爜锛岀敤鎴风‘璁ゅ悗鎵ц<E98EB5> | 鐢ㄦ埛鑳界湅鎳備唬鐮佹剰鍥?| 0.5澶?| 鍓嶇<E98D93> |
|
||
| **P0-010** | 琛ㄦ牸鍒锋柊 | 鎵ц<E98EB5>鍚庤嚜鍔ㄦ媺鍙栨柊鏁版嵁 | 鍓嶇<E98D93>瀹炴椂鏇存柊 | 0.5澶?| 鍓嶇<E98D93> |
|
||
| **P0-011** | UI閿佸畾鏈哄埗 | AI澶勭悊鏃惰〃鏍煎彉鐏?閬<>僵 | 鐗╃悊绂佹<E7BB82>骞跺彂鎿嶄綔 | 0.5澶?| 鍓嶇<E98D93> |
|
||
| **P0-012** | 瀵煎嚭Excel | 涓嬭浇澶勭悊鍚庣殑鏂囦欢 | 鏂囦欢瀹屾暣鎬?| 1澶?| Python |
|
||
|
||
**P0灏忚<E7818F>锛?1.5澶?*
|
||
|
||
### 3.2 P1绾э細蹇呴』楠岃瘉锛屽彲绠€鍖栧疄鐜?猸愨瓙猸愨瓙
|
||
|
||
| ID | 鍔熻兘 | MVP绠€鍖栨柟妗?| 瀹屾暣鐗?| 宸ユ椂 |
|
||
|----|------|------------|--------|------|
|
||
| **P1-001** | 浼氳瘽绠$悊 | 杩涚▼鍐呭瓨Map锛堝崟瀹炰緥锛?| Redis鍒嗗竷寮?| 0.5澶?|
|
||
| **P1-002** | 蹇冭烦淇濇椿 | 鍥哄畾10鍒嗛挓杩囨湡锛屼笉缁<E7AC89>湡 | 鍓嶇<E98D93>蹇冭烦缁<E783A6>湡 | 0.5澶?|
|
||
| **P1-003** | 缂栫爜妫€娴?| chardet鑷<74>姩妫€娴?鍙嬪ソ鎶ラ敊 | 鑷<>姩杞<E5A7A9>崲 | 1澶?|
|
||
| **P1-004** | AI鑷<49>垜淇<E59E9C><E6B787> | 澶辫触鍚庨噸璇?娆?| 澶氭<E6BEB6>閲嶈瘯+瀛︿範 | 1澶?|
|
||
| **P1-005** | 蹇<>嵎妯℃澘 | 3涓<33>父鐢ㄦā鏉匡紙骞撮緞鍒嗙粍绛夛級 | 10+妯℃澘搴?| 0.5澶?|
|
||
|
||
**P1灏忚<E7818F>锛?.5澶?*
|
||
|
||
### 3.3 P2绾э細寤跺悗鎴栦笉鍋?猸愨瓙
|
||
|
||
| 鍔熻兘 | 寤跺悗鍘熷洜 | 浣曟椂鍋?|
|
||
|------|---------|--------|
|
||
| 鎵嬪姩缂栬緫鍗曞厓鏍?| MVP涓撴敞AI | P2闃舵<E99783> |
|
||
| 鎾ら攢/鍥炴粴 | 鑺傜渷鍐呭瓨 | P2闃舵<E99783> |
|
||
| Apache Arrow | JSON澶熺敤 | 鎬ц兘涓嶈揪鏍囨椂 |
|
||
| Redis鍒嗗竷寮?| 鍗曞疄渚嬪<E6B89A>鐢?| 妯<>悜鎵╁睍鏃?|
|
||
| 鏍峰紡淇濈暀 | 澶嶆潅搴﹂珮 | P3闃舵<E99783> |
|
||
| 鎿嶄綔瀹¤<E780B9> | 闈炴牳蹇?| P3闃舵<E99783> |
|
||
| 澶歋heet鏀<74>寔 | 绠€鍖栭€昏緫 | P3闃舵<E99783> |
|
||
|
||
---
|
||
|
||
## 鍥涖€?鍛ㄨ<E98D9B>缁嗗紑鍙戣<E98D99>鍒?
|
||
|
||
### Week 1锛氬熀纭€鏋舵瀯鎼<E780AF>缓锛?澶╋級
|
||
|
||
#### Day 1锛氱幆澧冩惌寤?+ 浠g爜缁撴瀯锛堚殸锔?鍙傝€僼ool-b缁撴瀯 + Python鐜<6E><E9909C>锛?
|
||
|
||
**浠诲姟娓呭崟锛?*
|
||
- [ ] 鍒涘缓椤圭洰鐩<E6B4B0>綍缁撴瀯锛?*鍙傝€僼ool-b**锛?
|
||
```
|
||
backend/src/modules/dc/tool-c/ 鈫?涓荤洰褰?
|
||
鈹溾攢鈹€ services/ 鈫?涓氬姟閫昏緫灞?
|
||
鈹? 鈹溾攢鈹€ SessionService.ts 鈫?Session绠$悊锛堝瓨鏁版嵁搴擄級
|
||
鈹? 鈹溾攢鈹€ AICodeService.ts 鈫?AI浠g爜鐢熸垚
|
||
鈹? 鈹溾攢鈹€ PythonExecutorService.ts 鈫?猸?Python浠g爜鎵ц<E98EB5>锛堟牳蹇冿級
|
||
鈹? 鈹斺攢鈹€ DataProcessService.ts 鈫?鏁版嵁澶勭悊閫昏緫
|
||
鈹溾攢鈹€ controllers/ 鈫?鎺у埗鍣ㄥ眰
|
||
鈹? 鈹斺攢鈹€ ToolCController.ts 鈫?HTTP璇锋眰澶勭悊
|
||
鈹溾攢鈹€ routes/ 鈫?璺<>敱灞?
|
||
鈹? 鈹斺攢鈹€ index.ts 鈫?璺<>敱瀹氫箟
|
||
鈹斺攢鈹€ utils/ 鈫?宸ュ叿鍑芥暟
|
||
鈹溾攢鈹€ codeValidator.ts 鈫?AST浠g爜妫€鏌?
|
||
鈹斺攢鈹€ pythonScripts/ 鈫?猸?Python鎵ц<E98EB5>鑴氭湰
|
||
鈹斺攢鈹€ executor.py 鈫?Pandas浠g爜鎵ц<E98EB5>鍣?
|
||
|
||
frontend-v2/src/modules/dc/pages/tool-c/ 鈫?鍓嶇<E98D93>锛堝凡瀛樺湪锛?
|
||
```
|
||
|
||
- [ ] **猸?鎵╁睍鐜版湁Python鏈嶅姟锛堟牳蹇冨姛鑳斤級**
|
||
```bash
|
||
# 绯荤粺宸叉湁Python寰<6E>湇鍔★紙extraction_service锛夛紝鍙<E7B49D>渶鎵╁睍鍔熻兘
|
||
cd extraction_service
|
||
|
||
# 1. 鍒涘缓DC鎵ц<E98EB5>鍣ㄦā鍧?
|
||
cat > services/dc_executor.py << 'EOF'
|
||
import pandas as pd
|
||
import ast
|
||
from typing import Dict, Any, List
|
||
|
||
def validate_code(code: str) -> Dict[str, Any]:
|
||
"""AST闈欐€佹<E282AC>鏌ワ紙瀹夊叏楠岃瘉锛?""
|
||
try:
|
||
tree = ast.parse(code)
|
||
# 绂佹<E7BB82>鍗遍櫓瀵煎叆
|
||
forbidden_modules = ['os', 'sys', 'subprocess', 'socket', 'shutil', 'requests']
|
||
for node in ast.walk(tree):
|
||
if isinstance(node, ast.Import):
|
||
for alias in node.names:
|
||
if alias.name in forbidden_modules:
|
||
return {'valid': False, 'error': f'绂佹<E7BB82>瀵煎叆{alias.name}妯″潡'}
|
||
elif isinstance(node, ast.ImportFrom):
|
||
if node.module in forbidden_modules:
|
||
return {'valid': False, 'error': f'绂佹<E7BB82>瀵煎叆{node.module}妯″潡'}
|
||
return {'valid': True}
|
||
except Exception as e:
|
||
return {'valid': False, 'error': f'浠g爜璇<E7889C>硶閿欒<E996BF>: {str(e)}'}
|
||
|
||
def execute_pandas_code(data: List[Dict], code: str) -> Dict[str, Any]:
|
||
"""鎵ц<E98EB5>Pandas浠g爜锛堚瓙鏍稿績鍔熻兘锛?""
|
||
try:
|
||
# 1. 瀹夊叏妫€鏌?
|
||
validation = validate_code(code)
|
||
if not validation['valid']:
|
||
return {'success': False, 'error': validation['error']}
|
||
|
||
# 2. 鍔犺浇鏁版嵁鍒癉ataFrame
|
||
df = pd.DataFrame(data)
|
||
|
||
# 3. 鎵ц<E98EB5>浠g爜锛堟敞鍏<E6959E>f鍜宲d锛岄殧绂荤幆澧冿級
|
||
local_env = {'df': df, 'pd': pd}
|
||
exec(code, {'__builtins__': {}}, local_env)
|
||
|
||
# 4. 鑾峰彇鎵ц<E98EB5>鍚庣殑df
|
||
df_result = local_env.get('df', df)
|
||
|
||
# 5. 杩斿洖缁撴灉锛堝墠100琛岋紝閬垮厤鏁版嵁閲忚繃澶э級
|
||
return {
|
||
'success': True,
|
||
'data': df_result.head(100).to_dict('records'),
|
||
'totalRows': len(df_result),
|
||
'totalCols': len(df_result.columns),
|
||
'columns': df_result.columns.tolist()
|
||
}
|
||
except Exception as e:
|
||
return {
|
||
'success': False,
|
||
'error': f'浠g爜鎵ц<E98EB5>澶辫触: {str(e)}'
|
||
}
|
||
EOF
|
||
|
||
# 2. 鎵╁睍main.py锛屾坊鍔燚C绔<43>偣
|
||
# 鍦╩ain.py鏈<79>熬娣诲姞锛?
|
||
cat >> main.py << 'EOF'
|
||
|
||
# ==================== DC宸ュ叿C绔<43>偣 ====================
|
||
from services.dc_executor import execute_pandas_code, validate_code
|
||
from pydantic import BaseModel
|
||
|
||
class ExecuteRequest(BaseModel):
|
||
data: List[Dict]
|
||
code: str
|
||
|
||
class ValidateRequest(BaseModel):
|
||
code: str
|
||
|
||
@app.post("/api/dc/execute")
|
||
async def dc_execute_code(request: ExecuteRequest):
|
||
"""宸ュ叿C锛氭墽琛孭andas浠g爜"""
|
||
logger.info(f"DC Execute: code length={len(request.code)}, data rows={len(request.data)}")
|
||
result = execute_pandas_code(request.data, request.code)
|
||
return JSONResponse(result)
|
||
|
||
@app.post("/api/dc/validate")
|
||
async def dc_validate_code(request: ValidateRequest):
|
||
"""宸ュ叿C锛欰ST浠g爜妫€鏌?""
|
||
logger.info(f"DC Validate: code length={len(request.code)}")
|
||
result = validate_code(request.code)
|
||
return JSONResponse(result)
|
||
EOF
|
||
```
|
||
|
||
- [ ] **Node.js璋冪敤Python鏈嶅姟锛圥ythonExecutorService锛?*
|
||
```typescript
|
||
// backend/src/modules/dc/tool-c/services/PythonExecutorService.ts
|
||
import axios from 'axios';
|
||
import { logger } from '@/common/logging';
|
||
|
||
const EXTRACTION_SERVICE_URL = process.env.EXTRACTION_SERVICE_URL || 'http://localhost:8000';
|
||
|
||
export interface ExecuteResult {
|
||
success: boolean;
|
||
data?: any[];
|
||
totalRows?: number;
|
||
totalCols?: number;
|
||
columns?: string[];
|
||
error?: string;
|
||
}
|
||
|
||
export class PythonExecutorService {
|
||
private baseUrl: string;
|
||
|
||
constructor() {
|
||
this.baseUrl = EXTRACTION_SERVICE_URL;
|
||
}
|
||
|
||
/**
|
||
* 鎵ц<E98EB5>Pandas浠g爜锛堚瓙 鏍稿績鍔熻兘锛?
|
||
* 澶嶇敤鐜版湁Python寰<6E>湇鍔★紝娣诲姞鏂扮<E98F82>鐐?
|
||
*/
|
||
async executeCode(data: any[], code: string): Promise<ExecuteResult> {
|
||
try {
|
||
logger.info('Calling Python executor', {
|
||
dataRows: data.length,
|
||
codeLength: code.length
|
||
});
|
||
|
||
const response = await axios.post<ExecuteResult>(
|
||
`${this.baseUrl}/api/dc/execute`,
|
||
{ data, code },
|
||
{ timeout: 30000 } // 30绉掕秴鏃?
|
||
);
|
||
|
||
logger.info('Python execution success', {
|
||
totalRows: response.data.totalRows
|
||
});
|
||
|
||
return response.data;
|
||
} catch (error) {
|
||
logger.error('Python execution failed', { error });
|
||
|
||
if (axios.isAxiosError(error) && error.response) {
|
||
throw new Error(error.response.data.error || 'Python execution failed');
|
||
}
|
||
|
||
throw new Error('鏃犳硶杩炴帴鍒癙ython鎵ц<E98EB5>鏈嶅姟');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* AST浠g爜妫€鏌ワ紙鎵ц<E98EB5>鍓嶉獙璇侊級
|
||
*/
|
||
async validateCode(code: string): Promise<{ valid: boolean; error?: string }> {
|
||
try {
|
||
const response = await axios.post(
|
||
`${this.baseUrl}/api/dc/validate`,
|
||
{ code },
|
||
{ timeout: 5000 }
|
||
);
|
||
|
||
return response.data;
|
||
} catch (error) {
|
||
logger.error('Code validation failed', { error });
|
||
throw new Error('浠g爜楠岃瘉澶辫触');
|
||
}
|
||
}
|
||
}
|
||
|
||
export const pythonExecutorService = new PythonExecutorService();
|
||
```
|
||
|
||
- [ ] **寮哄埗妫€鏌?*锛氱‘淇濆<E6B787>鐢ㄥ钩鍙版湇鍔?
|
||
```typescript
|
||
// backend/src/modules/dc/tool-c/services/SessionService.ts
|
||
|
||
// 鉁?蹇呴』瀵煎叆杩欎簺骞冲彴鏈嶅姟
|
||
import { storage } from '@/common/storage';
|
||
import { logger } from '@/common/logging';
|
||
import { cache } from '@/common/cache';
|
||
import { prisma } from '@/config/database';
|
||
|
||
// 鉂?绂佹<E7BB82>鑷<EFBFBD>繁瀹炵幇
|
||
// const sessions = new Map() 鈫?杩濆弽瑙勮寖锛?
|
||
```
|
||
|
||
- [ ] 鏁版嵁搴揝chema璁捐<E79281>锛坉c_schema锛?
|
||
```prisma
|
||
// prisma/schema.prisma锛堟坊鍔犲埌dc_schema锛?
|
||
model DcToolCSession {
|
||
id String @id @default(uuid())
|
||
userId String
|
||
sessionId String @unique
|
||
fileName String
|
||
dataSnapshot Json // 瀛樺偍100琛岄<E7909B>瑙堟暟鎹?
|
||
totalRows Int
|
||
totalCols Int
|
||
columns Json // 鍒椾俊鎭?
|
||
expiresAt DateTime // 10鍒嗛挓杩囨湡
|
||
createdAt DateTime @default(now())
|
||
|
||
@@schema("dc_schema")
|
||
@@map("dc_tool_c_sessions")
|
||
}
|
||
```
|
||
|
||
**楠屾敹鏍囧噯锛?*
|
||
- 鉁?鏂囦欢澶圭粨鏋勪笌tool-b涓€鑷?
|
||
- 鉁?瀵煎叆浜嗘墍鏈夊繀椤荤殑骞冲彴鏈嶅姟
|
||
- 鉁?娌℃湁鍐呭瓨Map銆佹病鏈夋湰鍦版枃浠跺瓨鍌?
|
||
|
||
**璐熻矗浜猴細** 鍚庣<E98D9A>寮€鍙?
|
||
|
||
---
|
||
|
||
#### Day 2锛歋ession绠$悊 + 鏁版嵁鍔犺浇锛堚殸锔?瀛樻暟鎹<E69A9F>簱锛屼笉鐢ㄥ唴瀛橈級
|
||
|
||
**浠诲姟娓呭崟锛?*
|
||
- [ ] 瀹炵幇SessionService锛?*瀛樻暟鎹<E69A9F>簱锛岀<E9949B>鍚堜簯鍘熺敓瑙勮寖**锛?
|
||
```typescript
|
||
// backend/src/modules/dc/tool-c/services/SessionService.ts
|
||
import { storage } from '@/common/storage';
|
||
import { logger } from '@/common/logging';
|
||
import { prisma } from '@/config/database';
|
||
import * as xlsx from 'xlsx';
|
||
import chardet from 'chardet';
|
||
|
||
export class SessionService {
|
||
/**
|
||
* 鍒涘缓Session锛堚渽 瀛樻暟鎹<E69A9F>簱锛屼笉鐢ㄥ唴瀛楳ap锛?
|
||
*/
|
||
async createSession(userId: string, fileBuffer: Buffer, fileName: string): Promise<string> {
|
||
// 1. 妫€娴嬬紪鐮?
|
||
const detected = chardet.detect(fileBuffer);
|
||
if (detected.encoding.toLowerCase() !== 'utf-8') {
|
||
throw new Error(`鏂囦欢缂栫爜涓?{detected.encoding}锛岃<E9949B>杞<EFBFBD>崲涓篣TF-8`);
|
||
}
|
||
|
||
// 2. 鍐呭瓨瑙f瀽Excel锛堚渽 浜戝師鐢燂細涓嶈惤鐩橈級
|
||
const workbook = xlsx.read(fileBuffer, { type: 'buffer' });
|
||
const sheet = workbook.Sheets[workbook.SheetNames[0]];
|
||
const data = xlsx.utils.sheet_to_json(sheet);
|
||
|
||
// 3. 鎻愬彇鍒椾俊鎭?
|
||
const columns = Object.keys(data[0] || {}).map(col => ({
|
||
name: col,
|
||
type: typeof data[0][col]
|
||
}));
|
||
|
||
// 4. Session瀛樻暟鎹<E69A9F>簱锛堚渽 绗﹀悎浜戝師鐢熻<E990A2>鑼冿級
|
||
const sessionId = `session_${Date.now()}_${Math.random().toString(36)}`;
|
||
await prisma.dcToolCSession.create({
|
||
data: {
|
||
sessionId,
|
||
userId,
|
||
fileName,
|
||
dataSnapshot: data.slice(0, 100), // 鍙<>瓨鍓?00琛岄<E7909B>瑙?
|
||
totalRows: data.length,
|
||
totalCols: columns.length,
|
||
columns,
|
||
expiresAt: new Date(Date.now() + 10 * 60 * 1000) // 10鍒嗛挓杩囨湡
|
||
}
|
||
});
|
||
|
||
// 5. 瀹屾暣鏁版嵁涓婁紶鍒癘SS锛堚渽 浜戝師鐢燂細鎸佷箙鍖栧瓨鍌<E793A8>級
|
||
const dataKey = `dc/tool-c/${sessionId}/full-data.json`;
|
||
await storage.uploadBuffer(dataKey, Buffer.from(JSON.stringify(data)));
|
||
|
||
logger.info('Session created', { sessionId, totalRows: data.length });
|
||
|
||
return sessionId;
|
||
}
|
||
|
||
/**
|
||
* 鑾峰彇Session锛堜粠鏁版嵁搴撹<E690B4>鍙栵級
|
||
*/
|
||
async getSession(sessionId: string) {
|
||
const session = await prisma.dcToolCSession.findUnique({
|
||
where: { sessionId }
|
||
});
|
||
|
||
if (!session || new Date() > session.expiresAt) {
|
||
throw new Error('Session宸茶繃鏈?);
|
||
}
|
||
|
||
return session;
|
||
}
|
||
}
|
||
```
|
||
|
||
**娴嬭瘯鐢ㄤ緥锛?*
|
||
- [ ] 涓婁紶UTF-8缂栫爜鐨凟xcel锛屾<E9949B>甯歌В鏋?
|
||
- [ ] 涓婁紶GBK缂栫爜鐨凟xcel锛岃<E9949B>鎷︽埅骞舵彁绀?
|
||
- [ ] 涓婁紶涓<E7B4B6>枃鍒楀悕鐨凟xcel锛屾棤涔辩爜
|
||
- [ ] Session瀛樺叆鏁版嵁搴擄紝鍙<E7B49D>煡璇?
|
||
- [ ] 10鍒嗛挓鍚嶴ession鑷<6E>姩杩囨湡
|
||
|
||
**楠屾敹鏍囧噯锛?*
|
||
- 鉁?Session瀛樺偍鍦ㄦ暟鎹<E69A9F>簱锛堜笉鏄<E7AC89>唴瀛楳ap锛?
|
||
- 鉁?瀹屾暣鏁版嵁瀛樺偍鍦∣SS
|
||
- 鉁?绗﹀悎浜戝師鐢熷紑鍙戣<E98D99>鑼?
|
||
|
||
**璐熻矗浜猴細** Node.js鍚庣<E98D9A>
|
||
|
||
---
|
||
|
||
#### Day 3锛歂ode.js BFF + 鏂囦欢涓婁紶
|
||
|
||
**浠诲姟娓呭崟锛?*
|
||
- [ ] 鍒涘缓Fastify璺<79>敱
|
||
```typescript
|
||
// backend/src/modules/dc/tool-c/routes/index.ts
|
||
import { FastifyInstance } from 'fastify';
|
||
|
||
export async function registerToolCRoutes(fastify: FastifyInstance) {
|
||
// 鏂囦欢涓婁紶
|
||
fastify.post('/api/v1/dc/tool-c/session/init', async (req, reply) => {
|
||
const file = await req.file();
|
||
|
||
// 1. 鏂囦欢澶у皬妫€鏌?
|
||
if (file.file.bytesRead > 10 * 1024 * 1024) {
|
||
return reply.code(413).send({
|
||
success: false,
|
||
error: '鏂囦欢杩囧ぇ锛岃<E9949B>鍘嬬缉鍚庨噸璇曪紙闄?0MB锛?
|
||
});
|
||
}
|
||
|
||
// 2. 杞<>彂鍒癙ython鏈嶅姟
|
||
const formData = new FormData();
|
||
formData.append('file', file.file, file.filename);
|
||
|
||
const response = await axios.post('http://localhost:8001/api/python/init', formData);
|
||
|
||
return {
|
||
success: true,
|
||
sessionId: response.data.sessionId,
|
||
data: response.data
|
||
};
|
||
});
|
||
}
|
||
```
|
||
- [ ] 闆嗘垚鍒颁富搴旂敤
|
||
```typescript
|
||
// backend/src/modules/dc/index.ts
|
||
import { registerToolCRoutes } from './tool-c/routes';
|
||
|
||
export async function registerDCRoutes(fastify: FastifyInstance) {
|
||
await registerToolBRoutes(fastify);
|
||
await registerToolCRoutes(fastify); // 鏂板<E98F82>
|
||
}
|
||
```
|
||
|
||
**娴嬭瘯鐢ㄤ緥锛?*
|
||
- [ ] 涓婁紶9MB鏂囦欢锛屾垚鍔?
|
||
- [ ] 涓婁紶11MB鏂囦欢锛岃<E9949B>鎷︽埅
|
||
- [ ] 骞跺彂涓婁紶2涓<32>枃浠讹紝sessionId涓嶅啿绐?
|
||
|
||
**楠屾敹鏍囧噯锛?*
|
||
- 鉁?Node.js鑳芥<E991B3>纭<EFBFBD>浆鍙戞枃浠跺埌Python
|
||
- 鉁?鏂囦欢澶у皬闄愬埗鐢熸晥
|
||
|
||
**璐熻矗浜猴細** Node.js鍚庣<E98D9A>
|
||
|
||
---
|
||
|
||
#### Day 4锛氬墠绔<E5A2A0><E7BB94>鏋舵惌寤?
|
||
|
||
**浠诲姟娓呭崟锛?*
|
||
- [ ] 鍒涘缓Tool C椤甸潰
|
||
```typescript
|
||
// frontend-v2/src/modules/dc/pages/tool-c/index.tsx
|
||
import { AgGridReact } from 'ag-grid-react';
|
||
import { Upload, Spin } from 'antd';
|
||
|
||
export default function ToolCEditor() {
|
||
const [sessionId, setSessionId] = useState<string>();
|
||
const [data, setData] = useState<any[]>([]);
|
||
const [columns, setColumns] = useState<any[]>([]);
|
||
const [isLoading, setIsLoading] = useState(false);
|
||
|
||
const handleUpload = async (file: File) => {
|
||
setIsLoading(true);
|
||
const formData = new FormData();
|
||
formData.append('file', file);
|
||
|
||
const response = await api.post('/api/v1/dc/tool-c/session/init', formData);
|
||
|
||
setSessionId(response.data.sessionId);
|
||
setData(response.data.data.preview);
|
||
setColumns(response.data.data.columns);
|
||
setIsLoading(false);
|
||
};
|
||
|
||
return (
|
||
<div className="h-screen flex">
|
||
{/* 宸︿晶锛氳〃鏍煎尯鍩?*/}
|
||
<div className="flex-1">
|
||
{!sessionId ? (
|
||
<Upload beforeUpload={handleUpload}>
|
||
<Button>涓婁紶Excel鏂囦欢锛堥檺10MB锛?/Button>
|
||
</Upload>
|
||
) : (
|
||
<AgGridReact
|
||
rowData={data}
|
||
columnDefs={columns.map(col => ({
|
||
field: col.name,
|
||
headerName: col.name
|
||
}))}
|
||
/>
|
||
)}
|
||
</div>
|
||
|
||
{/* 鍙充晶锛欰I渚ц竟鏍忥紙鍗犱綅锛?*/}
|
||
<div className="w-96 border-l bg-white">
|
||
<h3>AI鍔╂墜</h3>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
```
|
||
- [ ] 闆嗘垚AG Grid
|
||
```bash
|
||
cd frontend-v2
|
||
npm install ag-grid-react ag-grid-community
|
||
```
|
||
- [ ] 璺<>敱閰嶇疆
|
||
```typescript
|
||
// frontend-v2/src/modules/dc/routes.tsx
|
||
{
|
||
path: 'tool-c',
|
||
element: <ToolCEditor />
|
||
}
|
||
```
|
||
|
||
**娴嬭瘯鐢ㄤ緥锛?*
|
||
- [ ] 涓婁紶鏂囦欢锛岃〃鏍兼<E98F8D>纭<EFBFBD>樉绀?
|
||
- [ ] 涓<>枃鍒楀悕鏄剧ず姝e父
|
||
- [ ] 绌哄€煎崟鍏冩牸鏈夎<E98F88>瑙夋彁绀?
|
||
|
||
**楠屾敹鏍囧噯锛?*
|
||
- 鉁?鐢ㄦ埛鑳界湅鍒板乏鍙冲垎鏍忕晫闈?
|
||
- 鉁?琛ㄦ牸鑳藉睍绀?00琛屾暟鎹?
|
||
|
||
**璐熻矗浜猴細** 鍓嶇<E98D93>寮€鍙?
|
||
|
||
---
|
||
|
||
#### Day 5锛歋ystem Prompt鏋勫缓
|
||
|
||
**浠诲姟娓呭崟锛?*
|
||
- [ ] 鍒涘缓Prompt妯℃澘
|
||
```typescript
|
||
// backend/src/modules/dc/tool-c/prompts/system-prompt.ts
|
||
export function buildSystemPrompt(dataContext: DataContext): string {
|
||
return `# AI鍖荤枟鏁版嵁娓呮礂鍔╂墜 - 绯荤粺瑙掕壊
|
||
|
||
## 褰撳墠鏁版嵁缁撴瀯
|
||
- 鎬昏<E98EAC>鏁帮細${dataContext.totalRows} 琛?
|
||
- 鎬诲垪鏁帮細${dataContext.totalCols} 鍒?
|
||
- 鍒楀悕锛?{dataContext.columns.map(c => c.name).join(', ')}
|
||
|
||
### 鍓?琛屾暟鎹<E69A9F>ず渚?
|
||
${JSON.stringify(dataContext.headData, null, 2)}
|
||
|
||
## 涓ユ牸瑙勫垯
|
||
1. 鍙<>兘浣跨敤pandas鎿嶄綔锛堝凡棰勫<E6A3B0>鍏ヤ负pd锛?
|
||
2. 鍙橀噺鍚嶅繀椤绘槸df锛堜笉瑕佺敤鍏朵粬鍚嶅瓧锛?
|
||
3. 灏卞湴淇<E6B9B4>敼锛歞f['new'] = ... 鎴?df.drop(...)
|
||
4. 涓嶈<E6B693>print()銆乨isplay()绛夎緭鍑?
|
||
5. 绂佹<E7BB82>import os銆乻ys銆乺equests绛?
|
||
|
||
## Few-shot绀轰緥锛堝垎灞傞毦搴︼細鍩虹<E98DA9>鈫掍腑绛夆啋楂樼骇锛?
|
||
|
||
### 馃煝 鍩虹<E98DA9>鍦烘櫙锛堝崟姝ラ<E5A79D>鎿嶄綔锛?
|
||
#### 鍦烘櫙1锛氬勾榫勫垎缁?
|
||
鐢ㄦ埛锛?鎶婂勾榫勫ぇ浜?0鐨勬爣璁颁负鑰佸勾缁?
|
||
浠g爜锛?
|
||
df['age_group'] = df['age'].apply(lambda x: '鑰佸勾缁? if pd.notna(x) and x > 60 else '闈炶€佸勾缁?)
|
||
|
||
#### 鍦烘櫙2锛氬垹闄ょ己澶?
|
||
鐢ㄦ埛锛?鍒犻櫎娌℃湁鎮h€匢D鐨勮<E990A8>"
|
||
浠g爜锛?
|
||
df.dropna(subset=['patient_id'], inplace=True)
|
||
|
||
#### 鍦烘櫙3锛氭€у埆缂栫爜
|
||
鐢ㄦ埛锛?鎶婃€у埆杞<E59F86>负鏁板瓧"
|
||
浠g爜锛?
|
||
df['gender_code'] = df['gender'].map({'鐢?: 1, '濂?: 0})
|
||
|
||
### 馃煛 涓<>瓑鍦烘櫙锛堝<E9949B>姝ラ<E5A79D>鎴栬法鍒楅€昏緫锛?
|
||
#### 鍦烘櫙4锛氳<E9949B>绠桸LR骞跺垎缁?
|
||
鐢ㄦ埛锛?璁$畻涓<E795BB>€х矑缁嗚優娣嬪反缁嗚優姣斿€糔LR锛屽苟鎸?.5鍒嗕负楂樹綆涓ょ粍"
|
||
浠g爜锛?
|
||
df['NLR'] = df.apply(lambda row: row['neutrophil'] / row['lymphocyte'] if pd.notna(row['neutrophil']) and pd.notna(row['lymphocyte']) and row['lymphocyte'] > 0 else None, axis=1)
|
||
df['NLR_group'] = df['NLR'].apply(lambda x: 'High' if pd.notna(x) and x > 2.5 else 'Low')
|
||
|
||
#### 鍦烘櫙5锛氬瓧绗︿覆鎷嗗垎锛堣<E9949B>鍘嬶級
|
||
鐢ㄦ埛锛?鎶婅<E98EB6>鍘嬪垪鐨?120/80'鏍煎紡鎷嗗垎鎴愭敹缂╁帇鍜岃垝寮犲帇锛屽苟鍒ゆ柇鏄<E69F87>惁楂樿<E6A582>鍘?
|
||
浠g爜锛?
|
||
df[['systolic_bp', 'diastolic_bp']] = df['blood_pressure'].str.split('/', expand=True)
|
||
df['systolic_bp'] = pd.to_numeric(df['systolic_bp'], errors='coerce')
|
||
df['diastolic_bp'] = pd.to_numeric(df['diastolic_bp'], errors='coerce')
|
||
df['is_hypertension'] = ((df['systolic_bp'] > 140) | (df['diastolic_bp'] > 90)).astype(int)
|
||
|
||
#### 鍦烘櫙6锛氭椂闂村樊璁$畻锛堥€昏緫楠岃瘉锛?
|
||
鐢ㄦ埛锛?璁$畻浣忛櫌澶╂暟锛屽<E9949B>鏋滃嚭闄㈡棩鏈熸棭浜庡叆闄㈡棩鏈熷垯鏍囪<E98F8D>涓哄紓甯?
|
||
浠g爜锛?
|
||
df['admission_date'] = pd.to_datetime(df['admission_date'], errors='coerce')
|
||
df['discharge_date'] = pd.to_datetime(df['discharge_date'], errors='coerce')
|
||
df['hospital_days'] = (df['discharge_date'] - df['admission_date']).dt.days
|
||
df['date_error'] = df['hospital_days'] < 0
|
||
df.loc[df['date_error'], 'hospital_days'] = None
|
||
|
||
### 馃敶 楂樼骇鍦烘櫙锛堝垎缁勮仛鍚堛€佹椂闂村簭鍒椼€佸尰瀛﹁<E7809B>鍒欙級
|
||
#### 鍦烘櫙7锛氱敓瀛樻椂闂磋<E99782>绠楋紙澶嶆潅鏉′欢閫昏緫锛?
|
||
鐢ㄦ埛锛?鐢熸垚鐢熷瓨鐘舵€佸拰鐢熷瓨鏃堕棿锛屽<E9949B>鏋滄<E98F8B>浜℃棩鏈熷瓨鍦ㄥ垯鐘舵€佷负1锛屾椂闂翠负姝讳骸鏃ユ湡鍑忚瘖鏂<E79896>棩鏈燂紝鍚﹀垯鐘舵€佷负0锛屾椂闂翠负闅忚<E99785>鎴<EFBFBD><E98EB4>鏃ユ湡鍑忚瘖鏂<E79896>棩鏈?
|
||
浠g爜锛?
|
||
df['diagnosis_date'] = pd.to_datetime(df['diagnosis_date'], errors='coerce')
|
||
df['death_date'] = pd.to_datetime(df['death_date'], errors='coerce')
|
||
df['followup_end_date'] = pd.to_datetime(df['followup_end_date'], errors='coerce')
|
||
df['vital_status'] = df['death_date'].notna().astype(int)
|
||
df['survival_days'] = df.apply(lambda row: (row['death_date'] - row['diagnosis_date']).days if pd.notna(row['death_date']) else (row['followup_end_date'] - row['diagnosis_date']).days, axis=1)
|
||
df['survival_months'] = (df['survival_days'] / 30.44).round(1)
|
||
|
||
#### 鍦烘櫙8锛氬垎缁勮仛鍚堬紙棣栨湯璁板綍锛?
|
||
鐢ㄦ埛锛?瀵规瘡涓<E798A1>偅鑰呮壘鍑虹<E98D91>涓€娆″寲鐤楁棩鏈熷拰鏈€鍚庝竴娆″寲鐤楁棩鏈燂紝璁$畻鎸佺画鏃堕棿"
|
||
浠g爜锛?
|
||
df['chemo_date'] = pd.to_datetime(df['chemo_date'], errors='coerce')
|
||
patient_chemo = df.groupby('patient_id')['chemo_date'].agg(['min', 'max']).reset_index()
|
||
patient_chemo.columns = ['patient_id', 'first_chemo', 'last_chemo']
|
||
patient_chemo['chemo_duration_days'] = (patient_chemo['last_chemo'] - patient_chemo['first_chemo']).dt.days
|
||
df = df.merge(patient_chemo[['patient_id', 'first_chemo', 'last_chemo', 'chemo_duration_days']], on='patient_id', how='left')
|
||
|
||
#### 鍦烘櫙9锛氭椂闂村簭鍒楀彉鍖栫巼
|
||
鐢ㄦ埛锛?鎸夋偅鑰匢D鍒嗙粍锛岃<E9949B>绠楁瘡娆¢殢璁跨浉姣斾笂娆$殑鑲跨槫澶у皬鍙樺寲鐜?
|
||
浠g爜锛?
|
||
df = df.sort_values(['patient_id', 'followup_date'])
|
||
df['prev_tumor_size'] = df.groupby('patient_id')['tumor_size'].shift(1)
|
||
df['tumor_change_rate'] = ((df['tumor_size'] - df['prev_tumor_size']) / df['prev_tumor_size'] * 100).round(2)
|
||
df['tumor_change_rate'] = df['tumor_change_rate'].fillna(0)
|
||
|
||
#### 鍦烘櫙10锛氬尰瀛﹁<E7809B>鍒欏紩鎿庯紙鑲濆姛鑳藉垎绾э級
|
||
鐢ㄦ埛锛?鏍规嵁ALT銆丄ST銆丄LP銆乀BIL鍒ゆ柇鑲濆姛鑳藉垎绾?
|
||
浠g爜锛?
|
||
def classify_liver_function(row):
|
||
abnormal_count = 0
|
||
if pd.notna(row.get('ALT')) and row['ALT'] > 40: abnormal_count += 1
|
||
if pd.notna(row.get('AST')) and row['AST'] > 40: abnormal_count += 1
|
||
if pd.notna(row.get('ALP')) and row['ALP'] > 125: abnormal_count += 1
|
||
if pd.notna(row.get('TBIL')) and row['TBIL'] > 20: abnormal_count += 1
|
||
if abnormal_count == 0: return '姝e父'
|
||
elif abnormal_count == 1: return '杞诲害寮傚父'
|
||
elif abnormal_count == 2: return '涓<>害寮傚父'
|
||
else: return '閲嶅害寮傚父'
|
||
df['liver_function_grade'] = df.apply(classify_liver_function, axis=1)
|
||
|
||
鐜板湪锛岃<EFBFBD>鍑嗗<EFBFBD>濂芥帴鏀剁敤鎴风殑鎸囦护銆傝<EFBFBD>浣忥細浠g爜瑕佸畨鍏ㄣ€佸彲闈犮€佹槗鎳傦紝鑳藉<EFBFBD>鐞嗕粠鍩虹<EFBFBD>鍒伴珮绾х殑澶嶆潅鍖荤枟鍦烘櫙銆?
|
||
`;
|
||
}
|
||
```
|
||
- [ ] 闆嗘垚LLMFactory锛堚渽 澶嶇敤骞冲彴閫氱敤鑳藉姏灞傦級
|
||
```typescript
|
||
// backend/src/modules/dc/tool-c/services/AICodeService.ts
|
||
import { LLMFactory } from '@/common/llm'; // 鉁?澶嶇敤骞冲彴LLM鑳藉姏
|
||
import { logger } from '@/common/logging'; // 鉁?澶嶇敤鏃ュ織
|
||
|
||
export class AICodeService {
|
||
/**
|
||
* 鐢熸垚Pandas浠g爜锛堚渽 澶嶇敤LLMFactory锛?
|
||
*/
|
||
async generateCode(prompt: string, dataContext: DataContext): Promise<string> {
|
||
logger.info('Generating Pandas code', { prompt, dataContext });
|
||
|
||
// 鉁?澶嶇敤骞冲彴LLM鏈嶅姟
|
||
const llm = LLMFactory.getLLM('deepseek-v3');
|
||
|
||
const systemPrompt = buildSystemPrompt(dataContext);
|
||
|
||
const response = await llm.chat([
|
||
{ role: 'system', content: systemPrompt },
|
||
{ role: 'user', content: prompt }
|
||
]);
|
||
|
||
// 鎻愬彇绾<E5BD87>唬鐮侊紙鍘婚櫎Markdown鏍煎紡锛?
|
||
const code = this.extractCode(response.content);
|
||
|
||
logger.info('Code generated successfully', { codeLength: code.length });
|
||
|
||
return code;
|
||
}
|
||
|
||
/**
|
||
* AI鑷<49>垜淇<E59E9C><E6B787>锛堝け璐ュ悗閲嶈瘯1娆★級
|
||
*/
|
||
async fixCode(originalCode: string, errorMsg: string, dataContext: DataContext): Promise<string> {
|
||
logger.warn('Code execution failed, attempting self-repair', { errorMsg });
|
||
|
||
const llm = LLMFactory.getLLM('deepseek-v3');
|
||
|
||
const fixPrompt = `浠ヤ笅浠g爜鎵ц<EFBFBD>澶辫触锛岃<EFBFBD>淇<EFBFBD><EFBFBD>锛?
|
||
|
||
閿欒<EFBFBD>淇℃伅锛?
|
||
${errorMsg}
|
||
|
||
鍘熷<EFBFBD>浠g爜锛?
|
||
${originalCode}
|
||
|
||
鏁版嵁缁撴瀯锛?
|
||
${JSON.stringify(dataContext)}
|
||
|
||
璇风敓鎴愪慨澶嶅悗鐨勪唬鐮侊紙涓嶈<EFBFBD>鏈塎arkdown鏍煎紡锛夛細`;
|
||
|
||
const response = await llm.chat([{ role: 'user', content: fixPrompt }]);
|
||
|
||
return this.extractCode(response.content);
|
||
}
|
||
|
||
private extractCode(text: string): string {
|
||
// 鍘婚櫎```python```鎴朻``鏍囪<E98F8D>
|
||
const match = text.match(/```(?:python)?\n([\s\S]*?)\n```/);
|
||
return match ? match[1] : text;
|
||
}
|
||
}
|
||
```
|
||
|
||
**娴嬭瘯鐢ㄤ緥锛?*
|
||
- [ ] 杈撳叆"骞撮緞鍒嗙粍"锛岀敓鎴愭<E98EB4>纭<EFBFBD>唬鐮?
|
||
- [ ] 杈撳叆"鍒犻櫎绌鸿<E7BB8C>"锛岀敓鎴愭<E98EB4>纭<EFBFBD>唬鐮?
|
||
- [ ] 妫€鏌ヤ唬鐮佷腑鏄<E88591>惁鍖呭惈鍗遍櫓璇<E6AB93>彞
|
||
|
||
**楠屾敹鏍囧噯锛?*
|
||
- 鉁?AI鑳界敓鎴愬彲鎵ц<E98EB5>鐨凱andas浠g爜
|
||
- 鉁?浠g爜绗﹀悎瑙勮寖锛堟棤print銆佹棤import锛?
|
||
|
||
**璐熻矗浜猴細** Node.js鍚庣<E98D9A>
|
||
|
||
---
|
||
|
||
### Week 2锛氭牳蹇冨姛鑳藉紑鍙戯紙5澶╋級
|
||
|
||
#### Day 6-7锛欰I浠g爜鐢熸垚 + AST妫€鏌?
|
||
|
||
**Day 6浠诲姟锛?*
|
||
- [ ] 瀹炵幇AST闈欐€佹<E282AC>鏌?
|
||
```python
|
||
# python-service/code_validator.py
|
||
import ast
|
||
|
||
DANGEROUS_IMPORTS = {'os', 'sys', 'subprocess', 'requests', 'urllib'}
|
||
DANGEROUS_BUILTINS = {'eval', 'exec', 'compile', 'open', '__import__'}
|
||
|
||
def validate_code_safety(code: str) -> Tuple[bool, str]:
|
||
try:
|
||
tree = ast.parse(code)
|
||
|
||
for node in ast.walk(tree):
|
||
# 妫€鏌<E282AC>mport
|
||
if isinstance(node, ast.Import):
|
||
for alias in node.names:
|
||
if alias.name in DANGEROUS_IMPORTS:
|
||
return False, f"绂佹<E7BB82>瀵煎叆锛歿alias.name}"
|
||
|
||
# 妫€鏌ュ嚱鏁拌皟鐢?
|
||
if isinstance(node, ast.Call):
|
||
if isinstance(node.func, ast.Name):
|
||
if node.func.id in DANGEROUS_BUILTINS:
|
||
return False, f"绂佹<E7BB82>浣跨敤锛歿node.func.id}"
|
||
|
||
return True, "楠岃瘉閫氳繃"
|
||
except SyntaxError as e:
|
||
return False, f"璇<>硶閿欒<E996BF>锛歿str(e)}"
|
||
```
|
||
|
||
**Day 7浠诲姟锛?*
|
||
- [ ] 瀹炵幇AI浠g爜鐢熸垚API
|
||
```typescript
|
||
// Node.js
|
||
fastify.post('/api/v1/dc/tool-c/ai/generate', async (req, reply) => {
|
||
const { sessionId, prompt } = req.body;
|
||
|
||
// 1. 鑾峰彇鏁版嵁涓婁笅鏂?
|
||
const context = await pythonService.getDataContext(sessionId);
|
||
|
||
// 2. 璋冪敤AI鐢熸垚浠g爜
|
||
const code = await aiService.generateCode(prompt, context);
|
||
|
||
return {
|
||
success: true,
|
||
code,
|
||
summary: `灏嗘墽琛屼互涓嬫搷浣滐細${extractSummary(code)}`
|
||
};
|
||
});
|
||
```
|
||
|
||
**娴嬭瘯鍦烘櫙锛?5涓<35>湡瀹炲尰鐤楁暟鎹<E69A9F>竻娲楀満鏅<E6BA80>級锛?*
|
||
|
||
**馃煝 鍩虹<E98DA9>鍦烘櫙锛?涓<>級- 鍗曟<E98D97>楠ゆ搷浣滐細**
|
||
1. [ ] "鎶婂勾榫勫ぇ浜?0鐨勬爣璁颁负鑰佸勾缁? - 绠€鍗曟潯浠跺垽鏂?
|
||
2. [ ] "鍒犻櫎鎵€鏈夋偅鑰匢D涓虹┖鐨勮<E990A8>" - 鏁版嵁瀹屾暣鎬ф竻娲?
|
||
3. [ ] "鎶婃€у埆杞<E59F86>负鏁板瓧锛岀敺1濂?" - 鍒嗙被鍙橀噺缂栫爜
|
||
4. [ ] "璁$畻BMI = 浣撻噸 / (韬<>珮/100)^2" - 绠€鍗曞叕寮忚<E5AFAE>绠?
|
||
5. [ ] "鍒犻櫎缂哄け鐜囪秴杩?0%鐨勫垪" - 鍒楃骇鏁版嵁璐ㄩ噺鎺у埗
|
||
|
||
**馃煛 涓<>瓑鍦烘櫙锛?涓<>級- 澶氭<E6BEB6>楠ゆ垨璺ㄥ垪閫昏緫锛?*
|
||
6. [ ] "鎶婅瘖鏂<E79896>棩鏈熷拰鍑洪櫌鏃ユ湡璁$畻澶╂暟宸<E69A9F>紝濡傛灉鍑洪櫌鏃ユ湡鏃╀簬璇婃柇鏃ユ湡鍒欐爣璁颁负寮傚父" - 閫昏緫楠岃瘉
|
||
7. [ ] "鏍规嵁鐧界粏鑳炪€佷腑鎬х矑缁嗚優銆佹穻宸寸粏鑳炰笁涓<E7AC81>寚鏍囷紝璁$畻NLR锛堜腑鎬х矑缁嗚優/娣嬪反缁嗚優锛夛紝骞舵寜2.5鍒嗕负楂樹綆涓ょ粍" - 澶氭<E6BEB6>楠よ<E6A5A0>绠?
|
||
8. [ ] "浠庣梾鐞嗘姤鍛婂垪涓<E59EAA>彁鍙朤NM鍒嗘湡锛岀敓鎴愭柊鍒楋紝濡傛灉娌℃湁鎻愬彇鍒板垯鏍囪<E98F8D>涓?鏈<>垎鏈?" - 鏂囨湰鎻愬彇锛堝彲鐢ㄦ<E990A2>鍒欙級
|
||
9. [ ] "鎶婅<E98EB6>鍘嬪垪涓<E59EAA>殑'120/80'鏍煎紡鎷嗗垎鎴愭敹缂╁帇鍜岃垝寮犲帇涓ゅ垪锛屽苟鍒ゆ柇鏄<E69F87>惁楂樿<E6A582>鍘嬶紙鏀剁缉鍘?140 or 鑸掑紶鍘?90锛? - 瀛楃<E7809B>涓插<E6B693>鐞?閫昏緫鍒ゆ柇
|
||
10. [ ] "鍒犻櫎閲嶅<E996B2>鐨勬偅鑰匢D锛屼繚鐣欐渶鏂扮殑涓€鏉¤<E98F89>褰曪紙鏍规嵁灏辫瘖鏃ユ湡锛? - 鍘婚噸+鎺掑簭
|
||
|
||
**馃敶 楂樼骇鍦烘櫙锛?涓<>級- 澶嶆潅鍒嗙粍銆佹椂闂村簭鍒椼€佸尰瀛﹁<E7809B>鍒欙細**
|
||
11. [ ] "瀵逛簬姣忎釜鎮h€咃紝鎵惧嚭绗<E59AAD>竴娆″寲鐤楁棩鏈熷拰鏈€鍚庝竴娆″寲鐤楁棩鏈燂紝璁$畻鍖栫枟鎸佺画鏃堕棿" - 鍒嗙粍鑱氬悎
|
||
12. [ ] "鐢熸垚鐢熷瓨鐘舵€佸彉閲忥細濡傛灉姝讳骸鏃ユ湡瀛樺湪鍒欎负1锛屽惁鍒欎负0锛涚敓鎴愮敓瀛樻椂闂达細濡傛灉姝讳骸鍒欎负锛堟<E9949B>浜℃棩鏈?璇婃柇鏃ユ湡锛夛紝鍚﹀垯涓猴紙闅忚<E99785>鎴<EFBFBD><E98EB4>鏃ユ湡-璇婃柇鏃ユ湡锛? - 澶嶆潅鏉′欢閫昏緫
|
||
13. [ ] "鏍规嵁澶氫釜瀹為獙瀹ゆ寚鏍囷紙ALT銆丄ST銆丄LP銆乀BIL锛夊垽鏂<E59EBD>倽鍔熻兘鍒嗙骇锛堟<E9949B>甯搞€佽交搴﹀紓甯搞€佷腑搴﹀紓甯搞€侀噸搴﹀紓甯革級" - 鍖诲<E98D96>瑙勫垯寮曟搸
|
||
14. [ ] "鎸夋偅鑰匢D鍒嗙粍锛屽<E9949B>姣忎釜鎮h€呯殑澶氭<E6BEB6>闅忚<E99785>璁板綍锛岃<E9949B>绠楃浉閭讳袱娆′箣闂寸殑鎸囨爣鍙樺寲鐜囷紙濡傝偪鐦ゅぇ灏忓彉鍖栫巼锛? - 鏃堕棿搴忓垪鍒嗘瀽
|
||
15. [ ] "鏍规嵁鍏ラ櫌鏃堕棿锛岃<E9949B>绠楁偅鑰呯殑瀛h妭鍙橀噺锛堟槬澶忕<E6BEB6>鍐<EFBFBD>級锛岀劧鍚庣粺璁′笉鍚屽<E98D9A>鑺傜殑鍙戠梾浜烘暟" - 鏃堕棿鐗瑰緛鎻愬彇+缁熻<E7BC81>鍒嗘瀽
|
||
|
||
**楠屾敹鏍囧噯锛堝垎灞傝<E7819E>姹傦級锛?*
|
||
- 鉁?**鍩虹<E98DA9>鍦烘櫙鎴愬姛鐜?> 90%**锛?/5鎴?/5鎴愬姛锛?
|
||
- 鉁?**涓<>瓑鍦烘櫙鎴愬姛鐜?> 80%**锛?/5鎴愬姛锛?
|
||
- 鉁?**楂樼骇鍦烘櫙鎴愬姛鐜?> 60%**锛?/5鎴愬姛锛?
|
||
- 鉁?**鎬讳綋鎴愬姛鐜?> 80%**锛?2/15鍦烘櫙鎴愬姛锛?
|
||
- 鉁?AST鑳芥嫤鎴猔import os`绛夊嵄闄╀唬鐮?
|
||
- 鉂?濡傛灉鎬讳綋鎴愬姛鐜?< 60%锛?/15澶辫触锛夛紝**MVP澶辫触锛岄渶瑕丳ivot鍒版ā鏉垮簱妯″紡**
|
||
|
||
**璐熻矗浜猴細** Node.js鍚庣<E98D9A> + Python寮€鍙?
|
||
|
||
---
|
||
|
||
#### Day 8锛氫唬鐮佹墽琛?+ 琛ㄦ牸鍒锋柊
|
||
|
||
**浠诲姟娓呭崟锛?*
|
||
- [ ] 瀹炵幇浠g爜鎵ц<E98EB5>API
|
||
```python
|
||
# Python
|
||
@app.post("/api/python/execute")
|
||
async def execute_code(request: ExecuteRequest):
|
||
# 1. 鑾峰彇Session
|
||
df = session_manager.get(request.sessionId)
|
||
|
||
# 2. AST妫€鏌?
|
||
is_safe, error_msg = validate_code_safety(request.code)
|
||
if not is_safe:
|
||
return {"success": False, "error": error_msg}
|
||
|
||
# 3. 鎵ц<E98EB5>浠g爜
|
||
try:
|
||
exec(request.code, {'df': df, 'pd': pd, 'np': np})
|
||
|
||
# 4. 杩斿洖棰勮<E6A3B0>鏁版嵁
|
||
preview = df.head(100).to_dict('records')
|
||
|
||
return {
|
||
"success": True,
|
||
"preview": preview,
|
||
"stats": {
|
||
"totalRows": len(df),
|
||
"totalCols": len(df.columns)
|
||
}
|
||
}
|
||
except Exception as e:
|
||
return {
|
||
"success": False,
|
||
"error": str(e),
|
||
"traceback": traceback.format_exc()
|
||
}
|
||
```
|
||
- [ ] 鍓嶇<E98D93>鎵ц<E98EB5>娴佺▼
|
||
```typescript
|
||
async function executeAICode(code: string) {
|
||
// 1. 灞曠ず棰勬搷浣滃崱鐗?
|
||
const confirmed = await showActionCard(code);
|
||
if (!confirmed) return;
|
||
|
||
// 2. 閿佸畾琛ㄦ牸
|
||
setIsLocked(true);
|
||
|
||
try {
|
||
// 3. 鎵ц<E98EB5>浠g爜
|
||
const response = await api.post('/api/v1/dc/tool-c/ai/execute', {
|
||
sessionId,
|
||
code
|
||
});
|
||
|
||
if (response.data.success) {
|
||
// 4. 鍒锋柊琛ㄦ牸
|
||
setData(response.data.preview);
|
||
message.success('鎵ц<E98EB5>鎴愬姛锛?);
|
||
} else {
|
||
message.error(`鎵ц<EFBFBD>澶辫触锛?{response.data.error}`);
|
||
}
|
||
} finally {
|
||
// 5. 瑙i攣琛ㄦ牸
|
||
setIsLocked(false);
|
||
}
|
||
}
|
||
```
|
||
|
||
**娴嬭瘯鐢ㄤ緥锛?*
|
||
- [ ] 鎵ц<E98EB5>鎴愬姛锛岃〃鏍兼<E98F8D>纭<EFBFBD>埛鏂?
|
||
- [ ] 鎵ц<E98EB5>澶辫触锛屾樉绀洪敊璇<E6958A>俊鎭?
|
||
- [ ] 鎵ц<E98EB5>鏈熼棿锛岃〃鏍煎<E98F8D>浜庨攣瀹氱姸鎬?
|
||
|
||
**楠屾敹鏍囧噯锛?*
|
||
- 鉁?浠g爜鑳芥<E991B3>纭<EFBFBD>慨鏀笵ataFrame
|
||
- 鉁?鍓嶇<E98D93>鑳藉疄鏃剁湅鍒板彉鍖?
|
||
|
||
**璐熻矗浜猴細** Python寮€鍙?+ 鍓嶇<E98D93>
|
||
|
||
---
|
||
|
||
#### Day 9锛歎I閿佸畾 + 棰勬搷浣滃崱鐗?
|
||
|
||
**浠诲姟娓呭崟锛?*
|
||
- [ ] 瀹炵幇AI瀵硅瘽UI
|
||
```typescript
|
||
function AIChatPanel({ sessionId }: Props) {
|
||
const [messages, setMessages] = useState<Message[]>([]);
|
||
const [input, setInput] = useState('');
|
||
const [isProcessing, setIsProcessing] = useState(false);
|
||
|
||
const handleSend = async () => {
|
||
if (!input.trim()) return;
|
||
|
||
// 1. 娣诲姞鐢ㄦ埛娑堟伅
|
||
setMessages(prev => [...prev, {
|
||
role: 'user',
|
||
content: input
|
||
}]);
|
||
|
||
setIsProcessing(true);
|
||
|
||
// 2. 璋冪敤AI鐢熸垚浠g爜
|
||
const response = await api.post('/api/v1/dc/tool-c/ai/generate', {
|
||
sessionId,
|
||
prompt: input
|
||
});
|
||
|
||
// 3. 娣诲姞AI娑堟伅锛堝寘鍚<E5AF98>唬鐮侊級
|
||
setMessages(prev => [...prev, {
|
||
role: 'assistant',
|
||
content: response.data.summary,
|
||
code: response.data.code
|
||
}]);
|
||
|
||
setIsProcessing(false);
|
||
setInput('');
|
||
};
|
||
|
||
return (
|
||
<div className="flex flex-col h-full">
|
||
{/* 娑堟伅鍒楄〃 */}
|
||
<div className="flex-1 overflow-y-auto p-4">
|
||
{messages.map((msg, idx) => (
|
||
<MessageBubble key={idx} message={msg} />
|
||
))}
|
||
</div>
|
||
|
||
{/* 杈撳叆妗?*/}
|
||
<div className="p-4 border-t">
|
||
<Input.TextArea
|
||
value={input}
|
||
onChange={e => setInput(e.target.value)}
|
||
placeholder="杈撳叆鎸囦护锛屼緥濡傦細鎶婂勾榫勫ぇ浜?0鐨勬爣璁颁负鑰佸勾缁?
|
||
disabled={isProcessing}
|
||
/>
|
||
<Button onClick={handleSend} disabled={isProcessing}>
|
||
鍙戦€?
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
```
|
||
- [ ] 瀹炵幇棰勬搷浣滃崱鐗?
|
||
```typescript
|
||
function ActionCard({ code, onConfirm, onCancel }: Props) {
|
||
return (
|
||
<Card className="mt-2 bg-slate-900 text-white">
|
||
<div className="mb-2 text-xs text-slate-400">
|
||
AI鐢熸垚鐨勪唬鐮?- 璇风‘璁ゅ悗鎵ц<E98EB5>
|
||
</div>
|
||
<pre className="text-sm font-mono text-blue-300">
|
||
{code}
|
||
</pre>
|
||
<div className="mt-3 flex gap-2">
|
||
<Button type="primary" onClick={onConfirm}>
|
||
杩愯<E69DA9>浠g爜
|
||
</Button>
|
||
<Button onClick={onCancel}>
|
||
鍙栨秷
|
||
</Button>
|
||
</div>
|
||
</Card>
|
||
);
|
||
}
|
||
```
|
||
- [ ] 瀹炵幇UI閿佸畾
|
||
```typescript
|
||
<AgGridReact
|
||
rowData={data}
|
||
suppressClickEdit={isLocked}
|
||
readOnlyEdit={isLocked}
|
||
/>
|
||
|
||
{isLocked && (
|
||
<div className="absolute inset-0 bg-black/20 flex items-center justify-center">
|
||
<Spin tip="AI姝e湪澶勭悊涓<E6828A>紝璇风◢鍊?.." />
|
||
</div>
|
||
)}
|
||
```
|
||
|
||
**楠屾敹鏍囧噯锛?*
|
||
- 鉁?鐢ㄦ埛鑳藉彂閫佹秷鎭?
|
||
- 鉁?AI杩斿洖浠g爜鏃跺睍绀洪<E7BB80>鎿嶄綔鍗$墖
|
||
- 鉁?鎵ц<E98EB5>鏈熼棿琛ㄦ牸閿佸畾
|
||
|
||
**璐熻矗浜猴細** 鍓嶇<E98D93>
|
||
|
||
---
|
||
|
||
#### Day 10锛氬<E9949B>鍑?+ 绔<>埌绔<E59F8C>祴璇?
|
||
|
||
**浠诲姟娓呭崟锛?*
|
||
- [ ] 瀹炵幇瀵煎嚭API
|
||
```python
|
||
@app.get("/api/python/export/{session_id}")
|
||
async def export_excel(session_id: str):
|
||
df = session_manager.get(session_id)
|
||
|
||
# 鐢熸垚Excel
|
||
output = io.BytesIO()
|
||
df.to_excel(output, index=False, engine='openpyxl')
|
||
output.seek(0)
|
||
|
||
return StreamingResponse(
|
||
output,
|
||
media_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||
headers={
|
||
'Content-Disposition': f'attachment; filename=cleaned_data_{session_id}.xlsx'
|
||
}
|
||
)
|
||
```
|
||
- [ ] 鍓嶇<E98D93>瀵煎嚭鎸夐挳
|
||
```typescript
|
||
const handleExport = async () => {
|
||
const response = await api.get(`/api/v1/dc/tool-c/session/export/${sessionId}`, {
|
||
responseType: 'blob'
|
||
});
|
||
|
||
const url = window.URL.createObjectURL(response.data);
|
||
const a = document.createElement('a');
|
||
a.href = url;
|
||
a.download = 'cleaned_data.xlsx';
|
||
a.click();
|
||
};
|
||
```
|
||
- [ ] **绔<>埌绔<E59F8C>祴璇曪紙瀹屾暣娴佺▼锛?*
|
||
```
|
||
1. 涓婁紶 test_data.xlsx (5000琛?脳 20鍒?
|
||
2. AI鎸囦护锛?鎶婂勾榫勫ぇ浜?0鐨勬爣璁颁负鑰佸勾缁?
|
||
3. 纭<><E7BAAD> 鈫?鎵ц<E98EB5> 鈫?琛ㄦ牸鍒锋柊锛堥獙璇佹柊澧炲垪锛?
|
||
4. AI鎸囦护锛?鍒犻櫎鎮h€匢D涓虹┖鐨勮<E990A8>"
|
||
5. 纭<><E7BAAD> 鈫?鎵ц<E98EB5> 鈫?琛ㄦ牸鍒锋柊锛堥獙璇佽<E79287>鏁板噺灏戯級
|
||
6. 鐐瑰嚮"瀵煎嚭" 鈫?涓嬭浇鏂囦欢
|
||
7. 鎵撳紑涓嬭浇鐨勬枃浠讹紝楠岃瘉鏁版嵁姝g‘
|
||
```
|
||
|
||
**楠屾敹鏍囧噯锛?*
|
||
- 鉁?鏁翠釜娴佺▼ < 2鍒嗛挓
|
||
- 鉁?瀵煎嚭鐨凟xcel鏁版嵁姝g‘
|
||
- 鉁?AI浠g爜鎵ц<E98EB5>鎴愬姛
|
||
|
||
**璐熻矗浜猴細** 鍏ㄥ憳
|
||
|
||
---
|
||
|
||
### Week 3锛氫紭鍖栦笌娴嬭瘯锛?澶╋級
|
||
|
||
#### Day 11-12锛氶敊璇<E6958A><E79287>鐞?+ AI鑷<49>垜淇<E59E9C><E6B787>
|
||
|
||
**浠诲姟娓呭崟锛?*
|
||
- [ ] 瀹炵幇AI鑷<49>垜淇<E59E9C><E6B787>
|
||
```typescript
|
||
async function executeWithRetry(code: string): Promise<ExecuteResult> {
|
||
// 绗<>竴娆℃墽琛?
|
||
let result = await pythonService.execute(sessionId, code);
|
||
|
||
if (!result.success) {
|
||
// 澶辫触锛岃<E9949B>AI淇<49><E6B787>
|
||
const fixedCode = await aiService.fixCode(code, result.error);
|
||
|
||
// 閲嶈瘯1娆?
|
||
result = await pythonService.execute(sessionId, fixedCode);
|
||
|
||
if (!result.success) {
|
||
// 褰诲簳澶辫触
|
||
return {
|
||
success: false,
|
||
error: '浠g爜鎵ц<E98EB5>澶辫触锛岃<E9949B>灏濊瘯鏇磋<E98F87>缁嗗湴鎻忚堪鎮ㄧ殑闇€姹?,
|
||
originalError: result.error
|
||
};
|
||
}
|
||
}
|
||
|
||
return result;
|
||
}
|
||
```
|
||
- [ ] 浼樺寲閿欒<E996BF>鎻愮ず
|
||
```typescript
|
||
function showErrorDetail(error: string) {
|
||
const errorMap = {
|
||
"KeyError: 'age'": "鍒楀悕'age'涓嶅瓨鍦<E793A8>紝璇锋<E79287>鏌ュ垪鍚嶆槸鍚︽<E98D9A>纭?,
|
||
"ValueError": "鏁版嵁绫诲瀷涓嶅尮閰嶏紝璇锋<E79287>鏌ユ暟鎹<E69A9F>牸寮?,
|
||
"MemoryError": "鏁版嵁閲忚繃澶э紝璇峰噺灏戞暟鎹<E69A9F><E98EB9>鏁?
|
||
};
|
||
|
||
const friendlyMsg = errorMap[error] || error;
|
||
|
||
Modal.error({
|
||
title: '鎵ц<E98EB5>澶辫触',
|
||
content: friendlyMsg
|
||
});
|
||
}
|
||
```
|
||
|
||
**娴嬭瘯鍦烘櫙锛堣竟鐣屾儏鍐碉級锛?*
|
||
- [ ] 鍒楀悕涓嶅瓨鍦<E793A8>細`df['nonexistent']`
|
||
- [ ] 璇<>硶閿欒<E996BF>锛歚df[df['age'] > 60 and df['age'] < 80]`
|
||
- [ ] 鏁版嵁绫诲瀷閿欒<E996BF>锛歚df['age'] + '瀛楃<E7809B>涓?`
|
||
- [ ] 鍐呭瓨婧㈠嚭锛氬<E9949B>鐞嗚秴澶ф暟鎹?
|
||
|
||
**楠屾敹鏍囧噯锛?*
|
||
- 鉁?甯歌<E794AF>閿欒<E996BF>鑳借嚜鎴戜慨澶?
|
||
- 鉁?鏃犳硶淇<E7A1B6><E6B787>鏃舵湁鍙嬪ソ鎻愮ず
|
||
|
||
**璐熻矗浜猴細** Node.js鍚庣<E98D9A>
|
||
|
||
---
|
||
|
||
#### Day 13锛氬揩鎹锋ā鏉?+ 缂栫爜妫€娴?
|
||
|
||
**浠诲姟娓呭崟锛?*
|
||
- [ ] 瀹炵幇蹇<E5B987>嵎妯℃澘
|
||
```typescript
|
||
const QUICK_TEMPLATES = {
|
||
'骞撮緞鍒嗙粍': {
|
||
label: '骞撮緞鍒嗙粍锛?0宀佸垎鐣岋級',
|
||
code: `df['age_group'] = pd.cut(df['age'], bins=[0,60,150], labels=['闈炶€佸勾','鑰佸勾'])`
|
||
},
|
||
'鍒犻櫎绌鸿<E7BB8C>': {
|
||
label: '鍒犻櫎绌鸿<E7BB8C>',
|
||
code: `df.dropna(how='all', inplace=True)`
|
||
},
|
||
'鎬у埆缂栫爜': {
|
||
label: '鎬у埆缂栫爜锛堢敺1濂?锛?,
|
||
code: `df['gender_code'] = df['gender'].map({'鐢?:1, '濂?:0})`
|
||
}
|
||
};
|
||
|
||
function QuickActions() {
|
||
return (
|
||
<div className="p-4 border-t">
|
||
<div className="text-xs text-slate-500 mb-2">蹇<>嵎鎿嶄綔</div>
|
||
{Object.entries(QUICK_TEMPLATES).map(([key, template]) => (
|
||
<Button
|
||
key={key}
|
||
size="small"
|
||
onClick={() => executeTemplate(template.code)}
|
||
>
|
||
{template.label}
|
||
</Button>
|
||
))}
|
||
</div>
|
||
);
|
||
}
|
||
```
|
||
- [ ] 瀹炵幇缂栫爜妫€娴?
|
||
```python
|
||
import chardet
|
||
|
||
def detect_encoding(file_bytes: bytes) -> str:
|
||
result = chardet.detect(file_bytes)
|
||
encoding = result['encoding']
|
||
confidence = result['confidence']
|
||
|
||
if confidence < 0.8:
|
||
raise ValueError(f"鏃犳硶纭<E7A1B6>畾鏂囦欢缂栫爜锛堢疆淇″害{confidence:.0%}锛?)
|
||
|
||
return encoding
|
||
|
||
@app.post("/api/python/init")
|
||
async def init_session(file: UploadFile):
|
||
content = await file.read()
|
||
|
||
# 妫€娴嬬紪鐮?
|
||
encoding = detect_encoding(content)
|
||
|
||
if encoding.lower() not in ['utf-8', 'utf-8-sig']:
|
||
return {
|
||
"success": False,
|
||
"error": f"鏂囦欢缂栫爜涓簕encoding}锛岃<E9949B>杞<EFBFBD>崲涓篣TF-8鍚庨噸鏂颁笂浼?,
|
||
"suggestion": "鍦‥xcel涓<6C>彟瀛樹负CSV UTF-8鏍煎紡"
|
||
}
|
||
|
||
# 姝e父鍔犺浇
|
||
# ...
|
||
```
|
||
|
||
**楠屾敹鏍囧噯锛?*
|
||
- 鉁?蹇<>嵎妯℃澘涓€閿<E282AC>墽琛?
|
||
- 鉁?GBK鏂囦欢琚<E6ACA2>弸濂芥嫤鎴?
|
||
|
||
**璐熻矗浜猴細** 鍓嶇<E98D93> + Python寮€鍙?
|
||
|
||
---
|
||
|
||
#### Day 14锛氭€ц兘娴嬭瘯 + 鍘嬪姏娴嬭瘯
|
||
|
||
**娴嬭瘯鍦烘櫙锛?*
|
||
- [ ] **鎬ц兘娴嬭瘯**
|
||
```
|
||
娴嬭瘯鏁版嵁锛?000琛?脳 20鍒楋紙绾?MB锛?
|
||
|
||
鍦烘櫙1锛氫笂浼犳枃浠?
|
||
- 鐩<>爣锛? 5绉?
|
||
- 瀹炴祴锛歘___绉?
|
||
|
||
鍦烘櫙2锛欰I鐢熸垚浠g爜
|
||
- 鐩<>爣锛? 5绉?
|
||
- 瀹炴祴锛歘___绉?
|
||
|
||
鍦烘櫙3锛氫唬鐮佹墽琛?鍒锋柊
|
||
- 鐩<>爣锛? 3绉?
|
||
- 瀹炴祴锛歘___绉?
|
||
|
||
鍦烘櫙4锛氬<E9949B>鍑篍xcel
|
||
- 鐩<>爣锛? 3绉?
|
||
- 瀹炴祴锛歘___绉?
|
||
|
||
鎬昏<E98EAC>锛? 16绉?
|
||
```
|
||
- [ ] **鍘嬪姏娴嬭瘯**
|
||
```
|
||
鍦烘櫙1锛氬苟鍙戠敤鎴?
|
||
- 5涓<35>敤鎴峰悓鏃朵笂浼犳枃浠?
|
||
- 楠岃瘉锛歋ession闅旂<E99785>锛屼簰涓嶅奖鍝?
|
||
|
||
鍦烘櫙2锛氬ぇ鏁版嵁閲?
|
||
- 涓婁紶50000琛?脳 50鍒楋紙绾?0MB锛?
|
||
- 楠岃瘉锛氫笉宕╂簝锛屽搷搴旀椂闂村彲鎺ュ彈
|
||
|
||
鍦烘櫙3锛氳繛缁<E7B99B>搷浣?
|
||
- 杩炵画鎵ц<E98EB5>10娆<30>I鎸囦护
|
||
- 楠岃瘉锛氬唴瀛樹笉娉勬紡
|
||
```
|
||
|
||
**鎬ц兘浼樺寲锛堝<E9949B>鏋滀笉杈炬爣锛夛細**
|
||
- [ ] 鍓嶇<E98D93>锛欰G Grid铏氭嫙婊氬姩閰嶇疆
|
||
- [ ] 鍚庣<E98D9A>锛欴ataFrame鎿嶄綔鏀逛负鎯版€ц<E282AC>绠?
|
||
- [ ] Python锛氫娇鐢≒olars鏇夸唬Pandas锛堝<E9949B>鏋滈渶瑕侊級
|
||
|
||
**楠屾敹鏍囧噯锛?*
|
||
- 鉁?鍗曟<E98D97>鎿嶄綔 < 16绉?
|
||
- 鉁?5涓<35>苟鍙戠敤鎴锋<E98EB4>甯稿伐浣?
|
||
- 鉁?鏃犲唴瀛樻硠婕?
|
||
|
||
**璐熻矗浜猴細** 鍏ㄥ憳
|
||
|
||
---
|
||
|
||
#### Day 15锛氭枃妗?+ 婕旂ず鍑嗗<E98D91>
|
||
|
||
**浠诲姟娓呭崟锛?*
|
||
- [ ] 缂栧啓鐢ㄦ埛鏂囨。
|
||
```markdown
|
||
# 宸ュ叿C浣跨敤鎸囧崡
|
||
|
||
## 蹇<>€熷紑濮?
|
||
1. 鐐瑰嚮"涓婁紶鏂囦欢"锛岄€夋嫨Excel锛堥檺10MB锛?
|
||
2. 绛夊緟3-5绉掞紝琛ㄦ牸鍔犺浇瀹屾垚
|
||
3. 鍦ㄥ彸渚<E5BDB8>I鍔╂墜杈撳叆鎸囦护锛屼緥濡傦細"鎶婂勾榫勫ぇ浜?0鐨勬爣璁颁负鑰佸勾缁?
|
||
4. 鐐瑰嚮"杩愯<E69DA9>浠g爜"纭<><E7BAAD>
|
||
5. 鏌ョ湅琛ㄦ牸鑷<E789B8>姩鍒锋柊
|
||
6. 瀹屾垚鎵€鏈夋搷浣滃悗锛岀偣鍑?瀵煎嚭"涓嬭浇缁撴灉
|
||
|
||
## 甯歌<E794AF>闂<EFBFBD><E99782>
|
||
Q: 鏂囦欢涓婁紶澶辫触锛屾彁绀烘枃浠惰繃澶э紵
|
||
A: 璇峰皢Excel鏂囦欢鍘嬬缉鍒?0MB浠ュ唴锛屾垨鍒犻櫎涓嶉渶瑕佺殑鍒椼€?
|
||
|
||
Q: 鍒楀悕鏄剧ず涔辩爜锛?
|
||
A: 璇峰湪Excel涓<6C>彟瀛樹负"CSV UTF-8"鏍煎紡鍚庨噸鏂颁笂浼犮€?
|
||
```
|
||
- [ ] 鍑嗗<E98D91>婕旂ず鏁版嵁
|
||
```
|
||
鍒涘缓 demo_data.xlsx锛?
|
||
- 100琛屾偅鑰呮暟鎹?
|
||
- 鍖呭惈锛歱atient_id, name, age, gender, admission_date, bmi
|
||
- 鏁呮剰鍒堕€犱竴浜涢棶棰橈細绌哄€笺€佸紓甯稿€笺€侀渶瑕佹竻娲楃殑鏁版嵁
|
||
```
|
||
- [ ] 鍑嗗<E98D91>婕旂ず鑴氭湰
|
||
```
|
||
婕旂ず娴佺▼锛?鍒嗛挓锛夛細
|
||
1. 涓婁紶demo_data.xlsx
|
||
2. AI鎸囦护锛?鎶婂勾榫勫ぇ浜?0鐨勬爣璁颁负鑰佸勾缁?
|
||
3. AI鎸囦护锛?鍒犻櫎鎮h€匢D涓虹┖鐨勮<E990A8>"
|
||
4. AI鎸囦护锛?鎶婃€у埆杞<E59F86>负鏁板瓧锛岀敺1濂?"
|
||
5. 瀵煎嚭缁撴灉
|
||
6. 灞曠ず瀵煎嚭鐨凟xcel鏂囦欢
|
||
```
|
||
|
||
**楠屾敹鏍囧噯锛?*
|
||
- 鉁?鏂囨。娓呮櫚鏄撴噦
|
||
- 鉁?婕旂ず娴佺晠鏃犲崱椤?
|
||
- 鉁?婕旂ず鏁版嵁鑳戒綋鐜版牳蹇冨姛鑳?
|
||
|
||
**璐熻矗浜猴細** 鍏ㄥ憳
|
||
|
||
---
|
||
|
||
## 浜斻€侀<E282AC>闄╁簲瀵圭瓥鐣?
|
||
|
||
### 5.1 椋庨櫓娓呭崟涓庡簲瀵?
|
||
|
||
| 椋庨櫓 | 姒傜巼 | 褰卞搷 | 搴斿<E690B4>绛栫暐 | 闄嶇骇鏂规<E98F82> |
|
||
|------|------|------|---------|---------|
|
||
| **AI浠g爜璐ㄩ噺浣庯紙鎴愬姛鐜?60%锛?* | 涓?| 鑷村懡 | 1. 浼樺寲Prompt宸ョ▼<br>2. 澧炲姞Few-shot绀轰緥<br>3. 瀹炵幇鑷<E5B987>垜淇<E59E9C><E6B787> | **Pivot锛氭敼鐢ㄤ唬鐮佹ā鏉垮簱** |
|
||
| **Apache Arrow闆嗘垚鍥伴毦** | 楂?| 楂?| 1. MVP涓嶇敤Arrow<br>2. 鐩存帴鐢↗SON | **宸查檷绾э細MVP鐢↗SON** |
|
||
| **Redis鍐呭瓨鎴愭湰楂?* | 涓?| 涓?| 1. MVP鐢ㄨ繘绋嬪唴瀛?br>2. 婵€杩涚殑Session杩囨湡 | **宸查檷绾э細鐢∕ap缂撳瓨** |
|
||
| **Python鍐呭瓨娉勬紡** | 涓?| 楂?| 1. 涓嶅仛鍘嗗彶蹇<E5BDB6>収<br>2. 瀹氭湡閲嶅惎杩涚▼ | **SAE鑷<45>姩閲嶅惎** |
|
||
| **涓<>枃Excel涔辩爜** | 楂?| 涓?| 1. chardet鑷<74>姩妫€娴?br>2. 鍙嬪ソ鎶ラ敊鎻愮ず | **鏂囨。璇存槑杞琔TF-8** |
|
||
| **SAE鍐峰惎鍔ㄦ參** | 楂?| 涓?| 1. 鏈€灏忓疄渚嬫暟=1<br>2. 寮傛<E5AFAE>鍒濆<E98D92>鍖?| **Loading浼樺寲** |
|
||
| **鍓嶇<E98D93>AG Grid鎬ц兘宸?* | 浣?| 涓?| 1. 鍙<>睍绀?00琛?br>2. 铏氭嫙婊氬姩 | **宸蹭紭鍖?* |
|
||
|
||
### 5.2 蹇<>€熷け璐ヨЕ鍙戝櫒
|
||
|
||
**绔嬪嵆鍋滄<E98D8B>寮€鍙戠殑鏉′欢锛?*
|
||
|
||
1. **Day 7缁撴潫锛孉I浠g爜鎴愬姛鐜?< 60%**
|
||
- 鍐崇瓥锛氭斁寮傾I Code Interpreter璺<72>嚎
|
||
- Pivot锛氭敼涓?浠g爜妯℃澘搴?+ 鍙傛暟鍖栭厤缃?
|
||
|
||
2. **Day 10缁撴潫锛岀<E9949B>鍒扮<E98D92>鏃堕棿 > 30绉?*
|
||
- 鍐崇瓥锛氭€ц兘鏃犳硶鎺ュ彈
|
||
- Pivot锛氭敼涓烘壒澶勭悊妯″紡锛堜笂浼?鈫?鍚庡彴澶勭悊 鈫?涓嬭浇锛?
|
||
|
||
3. **Day 14缁撴潫锛?涓<>敤鎴锋祴璇曪紝閮芥棤娉曠嫭绔嬪畬鎴愪换鍔?*
|
||
- 鍐崇瓥锛氫氦浜掕<E6B59C>璁″け璐?
|
||
- Pivot锛氶噸鏂拌<E98F82>璁<EFBFBD>I锛屽<E9949B>鍔犳柊鎵嬪紩瀵?
|
||
|
||
---
|
||
|
||
## 鍏<>€侀獙鏀舵爣鍑?
|
||
|
||
### 6.1 鍔熻兘楠屾敹娓呭崟
|
||
|
||
| 缂栧彿 | 楠屾敹椤?| 楠屾敹鏍囧噯 | 楠屾敹鏂瑰紡 |
|
||
|------|--------|---------|---------|
|
||
| **F-001** | 鏂囦欢涓婁紶 | 鑳戒笂浼?0MB浠ュ唴鐨凟xcel | 鎵嬪姩娴嬭瘯 |
|
||
| **F-002** | 缂栫爜妫€娴?| GBK鏂囦欢琚<E6ACA2>弸濂芥嫤鎴?| 鎵嬪姩娴嬭瘯 |
|
||
| **F-003** | 琛ㄦ牸灞曠ず | 100琛屾暟鎹<E69A9F><E98EB9>纭<EFBFBD>樉绀猴紝涓<E7B49D>枃鏃犱贡鐮?| 鎵嬪姩娴嬭瘯 |
|
||
| **F-004** | AI瀵硅瘽 | 鑳藉彂閫佹秷鎭<E7A7B7>紝鎺ユ敹鍥炲<E98DA5> | 鎵嬪姩娴嬭瘯 |
|
||
| **F-005** | 浠g爜鐢熸垚 | **10涓<30>満鏅<E6BA80>紝8涓<38>垚鍔燂紙80%锛?* | 鑷<>姩鍖栨祴璇?|
|
||
| **F-006** | AST妫€鏌?| 鎷︽埅`import os`绛夊嵄闄╀唬鐮?| 鍗曞厓娴嬭瘯 |
|
||
| **F-007** | 浠g爜鎵ц<E98EB5> | 鑳芥<E991B3>纭<EFBFBD>慨鏀笵ataFrame | 闆嗘垚娴嬭瘯 |
|
||
| **F-008** | 琛ㄦ牸鍒锋柊 | 鎵ц<E98EB5>鍚庤嚜鍔ㄦ洿鏂?| 鎵嬪姩娴嬭瘯 |
|
||
| **F-009** | UI閿佸畾 | AI澶勭悊鏃惰〃鏍煎彧璇?閬<>僵 | 鎵嬪姩娴嬭瘯 |
|
||
| **F-010** | 瀵煎嚭Excel | 涓嬭浇鐨勬枃浠舵暟鎹<E69A9F><E98EB9>纭?| 鎵嬪姩娴嬭瘯 |
|
||
|
||
### 6.2 鎬ц兘楠屾敹鏍囧噯
|
||
|
||
| 鎸囨爣 | 鐩<>爣鍊?| 楠屾敹鏂瑰紡 |
|
||
|------|--------|---------|
|
||
| 鏂囦欢涓婁紶鍒拌〃鏍兼樉绀?| < 5绉?| 鎬ц兘娴嬭瘯 |
|
||
| AI鐢熸垚浠g爜 | < 5绉?| 鎬ц兘娴嬭瘯 |
|
||
| 浠g爜鎵ц<E98EB5>+鍒锋柊 | < 3绉?| 鎬ц兘娴嬭瘯 |
|
||
| 瀵煎嚭Excel | < 3绉?| 鎬ц兘娴嬭瘯 |
|
||
| **绔<>埌绔<E59F8C>€绘椂闂?* | **< 16绉?* | 鎬ц兘娴嬭瘯 |
|
||
| 骞跺彂鐢ㄦ埛鏁?| 鈮?5浜?| 鍘嬪姏娴嬭瘯 |
|
||
| 鍐呭瓨鍗犵敤 | < 2GB锛?鐢ㄦ埛锛?| 鍘嬪姏娴嬭瘯 |
|
||
|
||
### 6.3 瀹夊叏楠屾敹鏍囧噯
|
||
|
||
| 鎸囨爣 | 楠屾敹鏍囧噯 | 楠屾敹鏂瑰紡 |
|
||
|------|---------|---------|
|
||
| 浠g爜娌欑<E5A88C> | 鎷︽埅鎵€鏈夊嵄闄╀唬鐮?| 娓楅€忔祴璇?|
|
||
| Session闅旂<E99785> | 鐢ㄦ埛A鐪嬩笉鍒扮敤鎴稡鏁版嵁 | 骞跺彂娴嬭瘯 |
|
||
| Session杩囨湡 | 10鍒嗛挓鍚庤嚜鍔ㄦ竻鐞?| 鏃堕棿娴嬭瘯 |
|
||
|
||
---
|
||
|
||
## 涓冦€佸揩閫熷け璐ユ満鍒?
|
||
|
||
### 7.1 鍏抽敭妫€鏌ョ偣
|
||
|
||
```
|
||
Checkpoint 1 (Day 5缁撴潫)锛?
|
||
鈹溾攢 System Prompt鑳藉惁璁〢I鐞嗚В鏁版嵁锛?
|
||
鈹溾攢 AI鑳界敓鎴怭andas浠g爜鍚楋紵
|
||
鈹斺攢 鍐崇瓥锛氱户缁?or 璋冩暣Prompt绛栫暐
|
||
|
||
Checkpoint 2 (Day 7缁撴潫)锛?
|
||
鈹溾攢 AI浠g爜鎴愬姛鐜?鈮?80%锛?
|
||
鈹溾攢 濡傛灉 < 60%锛氱珛鍗冲仠姝<E4BBA0>紝鏀圭敤妯℃澘搴?
|
||
鈹斺攢 濡傛灉 60-80%锛氱户缁<E688B7>紭鍖朠rompt
|
||
|
||
Checkpoint 3 (Day 10缁撴潫)锛?
|
||
鈹溾攢 绔<>埌绔<E59F8C>祦绋嬭兘璺戦€氾紵
|
||
鈹溾攢 鎬ц兘 < 16绉掞紵
|
||
鈹斺攢 鍐崇瓥锛氱户缁?or 鎬ц兘浼樺寲
|
||
|
||
Checkpoint 4 (Day 14缁撴潫)锛?
|
||
鈹溾攢 鐢ㄦ埛娴嬭瘯閫氳繃锛?
|
||
鈹溾攢 鏃犻噸澶<E599B8>ug锛?
|
||
鈹斺攢 鍐崇瓥锛氬彂甯?or 淇<><E6B787>Bug
|
||
```
|
||
|
||
### 7.2 Pivot鍐崇瓥鏍?
|
||
|
||
```
|
||
濡傛灉 AI浠g爜鎴愬姛鐜?< 60%锛?
|
||
鈹溾攢 Pivot 1锛氭敼鐢?浠g爜妯℃澘搴?+ 鍙傛暟鍖栭厤缃?
|
||
鈹? 鈹斺攢 鐢ㄦ埛閫夋嫨妯℃澘 鈫?濉<>啓鍙傛暟 鈫?鐢熸垚浠g爜
|
||
鈹?
|
||
鈹溾攢 Pivot 2锛欰I鍙樻垚"杈呭姪寤鸿<E5AFA4>"瑙掕壊
|
||
鈹? 鈹斺攢 鐢ㄦ埛鎵嬪姩鍐欎唬鐮侊紝AI鎻愪緵寤鸿<E5AFA4>
|
||
鈹?
|
||
鈹斺攢 Pivot 3锛氱畝鍖栦负"鎵瑰<E98EB5>鐞嗘ā寮?
|
||
鈹斺攢 涓婁紶 鈫?閫夋嫨棰勮<E6A3B0>鎿嶄綔 鈫?鍚庡彴澶勭悊 鈫?涓嬭浇
|
||
|
||
濡傛灉 鎬ц兘鏃犳硶鎺ュ彈锛? 30绉掞級锛?
|
||
鈹溾攢 鏂规<E98F82>1锛氬紩鍏<E7B4A9>pache Arrow
|
||
鈹溾攢 鏂规<E98F82>2锛氫娇鐢≒olars鏇夸唬Pandas
|
||
鈹斺攢 鏂规<E98F82>3锛氭敼涓烘壒澶勭悊+寮傛<E5AFAE>閫氱煡
|
||
|
||
濡傛灉 鐢ㄦ埛鏃犳硶鐙<E7A1B6>珛瀹屾垚浠诲姟锛?
|
||
鈹溾攢 鏂规<E98F82>1锛氬<E9949B>鍔犱氦浜掑紡鏂版墜寮曞<E5AFAE>
|
||
鈹溾攢 鏂规<E98F82>2锛氭彁渚涚ず渚嬫暟鎹<E69A9F>泦
|
||
鈹斺攢 鏂规<E98F82>3锛氱畝鍖朥I锛屽噺灏戦€夐」
|
||
```
|
||
|
||
---
|
||
|
||
## 鍏<>€侀檮褰?
|
||
|
||
### 8.1 娴嬭瘯鏁版嵁鍑嗗<E98D91>
|
||
|
||
**鍒涘缓鏍囧噯娴嬭瘯鏁版嵁闆嗭細**
|
||
```python
|
||
# create_test_data.py
|
||
import pandas as pd
|
||
import numpy as np
|
||
|
||
# 鐢熸垚5000琛屾祴璇曟暟鎹?
|
||
data = {
|
||
'patient_id': [f'P{i:04d}' for i in range(1, 5001)],
|
||
'name': [f'鎮h€厈i}' for i in range(1, 5001)],
|
||
'age': np.random.randint(18, 90, 5000),
|
||
'gender': np.random.choice(['鐢?, '濂?], 5000),
|
||
'admission_date': pd.date_range('2023-01-01', periods=5000, freq='H'),
|
||
'weight': np.random.uniform(45, 95, 5000).round(1),
|
||
'height': np.random.uniform(150, 190, 5000).round(0),
|
||
'diagnosis': np.random.choice(['鑲虹檶', '绯栧翱鐥?, '楂樿<E6A582>鍘?], 5000)
|
||
}
|
||
|
||
df = pd.DataFrame(data)
|
||
|
||
# 鏁呮剰鍒堕€犻棶棰?
|
||
df.loc[np.random.choice(5000, 100, replace=False), 'age'] = None # 100涓<30>己澶?
|
||
df.loc[np.random.choice(5000, 10, replace=False), 'age'] = 150 # 10涓<30>紓甯稿€?
|
||
df.loc[np.random.choice(5000, 50, replace=False), 'patient_id'] = None # 50涓<30>┖ID
|
||
|
||
df.to_excel('test_data.xlsx', index=False)
|
||
```
|
||
|
||
### 8.2 10涓<30>吀鍨嬪満鏅<E6BA80>祴璇曠敤渚?
|
||
|
||
```python
|
||
# test_ai_scenarios.py
|
||
test_cases = [
|
||
{
|
||
"id": "TC-001",
|
||
"prompt": "鎶婂勾榫勫ぇ浜?0鐨勬偅鑰呮爣璁颁负鑰佸勾缁?,
|
||
"expected_code": "df['age_group'] = df['age'].apply(lambda x: '鑰佸勾缁? if pd.notna(x) and x > 60 else '闈炶€佸勾缁?)",
|
||
"verify": lambda df: 'age_group' in df.columns
|
||
},
|
||
{
|
||
"id": "TC-002",
|
||
"prompt": "鍒犻櫎鎵€鏈夋偅鑰匢D涓虹┖鐨勮<E990A8>",
|
||
"expected_code": "df.dropna(subset=['patient_id'], inplace=True)",
|
||
"verify": lambda df: df['patient_id'].isnull().sum() == 0
|
||
},
|
||
# ... 鍏朵綑8涓<38>満鏅?
|
||
]
|
||
```
|
||
|
||
### 8.3 鐜<><E9909C>閰嶇疆娓呭崟
|
||
|
||
**Node.js渚濊禆锛?*
|
||
```json
|
||
{
|
||
"dependencies": {
|
||
"fastify": "^4.0.0",
|
||
"axios": "^1.6.0",
|
||
"joi": "^17.11.0",
|
||
"@fastify/multipart": "^8.0.0"
|
||
}
|
||
}
|
||
```
|
||
|
||
**Python渚濊禆锛?*
|
||
```txt
|
||
fastapi==0.115.0
|
||
uvicorn==0.30.0
|
||
pandas==2.2.0
|
||
openpyxl==3.1.0
|
||
chardet==5.2.0
|
||
python-multipart==0.0.9
|
||
```
|
||
|
||
---
|
||
|
||
## 涔濄€侀」鐩<E3808D><E990A9>鐞?
|
||
|
||
### 9.1 鍥㈤槦閰嶇疆
|
||
|
||
| 瑙掕壊 | 浜烘暟 | 鑱岃矗 |
|
||
|------|------|------|
|
||
| 鍓嶇<E98D93>寮€鍙?| 1浜?| React + AG Grid + UI |
|
||
| Node.js鍚庣<E98D9A> | 1浜?| BFF + LLM闆嗘垚 + Prompt宸ョ▼ |
|
||
| Python寮€鍙?| 1浜?| FastAPI + DataFrame + AST妫€鏌?|
|
||
| **鎬昏<E98EAC>** | **3浜?* | **3鍛<33>紙15澶╋級** |
|
||
|
||
### 9.2 娌熼€氭満鍒?
|
||
|
||
- **姣忔棩绔欎細**锛?5鍒嗛挓锛屽悓姝ヨ繘搴﹀拰闂<E68BB0><E99782>
|
||
- **鍏抽敭妫€鏌ョ偣**锛欴ay 5銆?銆?0銆?4
|
||
- **闂<><E99782>鍗囩骇**锛氶樆濉為棶棰?灏忔椂鍐呭崌绾?
|
||
- **鏂囨。鏇存柊**锛氭瘡鏃ユ洿鏂板紑鍙戣<E98D99>褰?
|
||
|
||
### 9.3 浠g爜绠$悊
|
||
|
||
**鍒嗘敮绛栫暐锛?*
|
||
```
|
||
main (绋冲畾鐗?
|
||
鈹斺攢鈹€ develop (寮€鍙戠増)
|
||
鈹溾攢鈹€ feature/tool-c-frontend
|
||
鈹溾攢鈹€ feature/tool-c-backend
|
||
鈹斺攢鈹€ feature/tool-c-python
|
||
```
|
||
|
||
**鎻愪氦瑙勮寖锛?*
|
||
```
|
||
feat: 鏂板<E98F82>AI浠g爜鐢熸垚鍔熻兘
|
||
fix: 淇<><E6B787>琛ㄦ牸鍒锋柊Bug
|
||
test: 澧炲姞AST妫€鏌ユ祴璇曠敤渚?
|
||
docs: 鏇存柊寮€鍙戞枃妗?
|
||
```
|
||
|
||
---
|
||
|
||
## 鍗併€佹€荤粨
|
||
|
||
### 鏍稿績鎴愬姛瑕佺礌
|
||
1. 鉁?**AI浠g爜璐ㄩ噺**锛氭垚鍔熺巼 > 80%锛堟牳蹇冨亣璁撅級
|
||
2. 鉁?**鎬ц兘鍙<E58598>帴鍙?*锛氱<E9949B>鍒扮<E98D92> < 16绉?
|
||
3. 鉁?**浜や簰绠€鍗?*锛氱敤鎴锋棤闇€鏂囨。灏辫兘鐢?
|
||
|
||
### 椋庨櫓鎺у埗
|
||
1. 鉁?**蹇<>€熷け璐?*锛?澶╅獙璇丄I鑳藉姏锛屼笉琛岀珛鍗砅ivot
|
||
2. 鉁?**鍔″疄鎶€鏈?*锛欽SON涓嶇敤Arrow锛屽唴瀛樹笉鐢≧edis
|
||
3. 鉁?**闄嶇骇鏂规<E98F82>**锛氬噯澶囧ソ妯℃澘搴撱€佹壒澶勭悊绛塒lan B
|
||
|
||
### 鏃堕棿鑺傜偣
|
||
- **Week 1**锛氬熀纭€鏋舵瀯锛?澶╋級
|
||
- **Week 2**锛氭牳蹇冨姛鑳斤紙5澶╋級
|
||
- **Week 3**锛氫紭鍖栨祴璇曪紙5澶╋級
|
||
- **鎬昏<E98EAC>**锛?5涓<35>伐浣滄棩
|
||
|
||
---
|
||
|
||
## 馃摑 鏂囨。淇<E38082><E6B787>璁板綍
|
||
|
||
### V1.3锛?025-12-06锛? 鍙戠幇鐜版湁Python鏈嶅姟 猸?閲嶅ぇ鍙戠幇
|
||
|
||
**淇<><E6B787>鍐呭<E98D90>**锛氭<E9949B>鏌ョ郴缁熷彂鐜板凡鏈塒ython寰<6E>湇鍔★紝涓嶉渶瑕侀噸澶嶅紑鍙戯細
|
||
|
||
#### 淇<><E6B787>1锛氬<E9949B>鐢ㄧ幇鏈塒ython鏈嶅姟锛屼笉閲嶅<E996B2>閫犺疆 猸愨瓙猸愨瓙猸?
|
||
- **閲嶅ぇ鍙戠幇**锛氱郴缁熷凡鏈?`extraction_service/`锛團astAPI + Pandas + openpyxl锛?
|
||
- **鐜版湁鍔熻兘**锛?
|
||
- 鉁?PDF/Docx/Txt鏂囨。鎻愬彇锛圥yMuPDF + Mammoth锛?
|
||
- 鉁?Pandas銆乷penpyxl銆乧hardet銆乴angdetect宸插畨瑁?
|
||
- 鉁?FastAPI妗嗘灦宸茶繍琛岋紙绔<E7B499>彛8000锛?
|
||
- 鉁?Node.js宸叉湁ExtractionClient闆嗘垚
|
||
- **鏂板<E98F82>鏂规<E98F82>**锛?
|
||
- 鉁?鎵╁睍鐜版湁鏈嶅姟锛屾坊鍔?`/api/dc/execute` 绔<>偣
|
||
- 鉁?鏂板<E98F82> `dc_executor.py` 妯″潡锛圓ST妫€鏌?+ 浠g爜鎵ц<E98EB5>锛?
|
||
- 鉁?澶嶇敤ExtractionClient妯″紡璋冪敤
|
||
- **閬垮厤閲嶅<E996B2>**锛?
|
||
- 鉂?涓嶉渶瑕佹柊寤篜ython椤圭洰
|
||
- 鉂?涓嶉渶瑕侀噸鏂板畨瑁呬緷璧?
|
||
- 鉂?涓嶉渶瑕侀噸鏂板啓HTTP璋冪敤閫昏緫
|
||
|
||
---
|
||
|
||
### V1.2锛?025-12-06锛? Python鎵ц<E98EB5>鐜<EFBFBD><E9909C> + 澶嶆潅鍦烘櫙 鈿狅笍 鏍稿績鍔熻兘
|
||
|
||
**淇<><E6B787>鍐呭<E98D90>**锛氭牴鎹<E789B4>敤鎴峰弽棣堬紝鏄庣‘Python浠g爜鎵ц<E98EB5>鏄<EFBFBD>牳蹇冨姛鑳斤細
|
||
|
||
#### 淇<><E6B787>1锛歅ython鎵ц<E98EB5>鏄<EFBFBD>牳蹇冿紝涓嶆槸鍙<E6A7B8>€?猸愨瓙猸愨瓙猸?
|
||
- **鍘熼敊璇?*锛氳<E9949B>"MVP闃舵<E99783>鍙<EFBFBD>兘涓嶉渶瑕丳ython寰<6E>湇鍔?
|
||
- **宸蹭慨姝?*锛?*Python浠g爜鎵ц<E98EB5>鏄<EFBFBD>伐鍏稢鐨勬牳蹇冧环鍊硷紝蹇呴』瀹炵幇**
|
||
- **鏂板<E98F82>鍐呭<E98D90>**锛?
|
||
- Day 1澧炲姞Python鐜<6E><E9909C>鎼<EFBFBD>缓
|
||
- 鏂板<E98F82>PythonExecutorService锛圢ode.js 鈫?Python閫氫俊锛?
|
||
- 鏂板<E98F82>executor.py锛圥andas浠g爜鎵ц<E98EB5>鍣<EFBFBD>級
|
||
- 鎶€鏈<E282AC>柟妗堬細Node.js child_process璋冪敤Python鑴氭湰
|
||
|
||
#### 淇<><E6B787>2锛氭祴璇曞満鏅<E6BA80>粠绠€鍗曞埌澶嶆潅 鉁?
|
||
- **鍘熼棶棰?*锛?0涓<30>祴璇曞満鏅<E6BA80>繃浜庣畝鍗?
|
||
- **宸蹭慨姝?*锛?5涓<35>湡瀹炲尰鐤楁暟鎹<E69A9F>竻娲楀満鏅?
|
||
- 馃煝 鍩虹<E98DA9>鍦烘櫙5涓<35>細鍗曟<E98D97>楠ゆ搷浣?
|
||
- 馃煛 涓<>瓑鍦烘櫙5涓<35>細澶氭<E6BEB6>楠ゃ€佽法鍒楅€昏緫
|
||
- 馃敶 楂樼骇鍦烘櫙5涓<35>細鍒嗙粍鑱氬悎銆佹椂闂村簭鍒椼€佸尰瀛﹁<E7809B>鍒?
|
||
- **鏂板<E98F82>鍦烘櫙**锛?
|
||
- 澶嶆潅鏉′欢閫昏緫锛堢敓瀛樻椂闂磋<E99782>绠楋級
|
||
- 鍖诲<E98D96>瑙勫垯寮曟搸锛堣倽鍔熻兘鍒嗙骇锛?
|
||
- 鏃堕棿搴忓垪鍒嗘瀽锛堟寚鏍囧彉鍖栫巼锛?
|
||
- 鏂囨湰鎻愬彇锛圱NM鍒嗘湡锛?
|
||
- 瀛楃<E7809B>涓插<E6B693>鐞嗭紙琛€鍘嬫媶鍒嗭級
|
||
|
||
#### 淇<><E6B787>3锛氶獙鏀舵爣鍑嗗垎灞?鉁?
|
||
- **鍘熸爣鍑?*锛氭€讳綋鎴愬姛鐜?> 80%
|
||
- **鏂版爣鍑?*锛?
|
||
- 鍩虹<E98DA9>鍦烘櫙鎴愬姛鐜?> 90%
|
||
- 涓<>瓑鍦烘櫙鎴愬姛鐜?> 80%
|
||
- 楂樼骇鍦烘櫙鎴愬姛鐜?> 60%
|
||
- 鎬讳綋鎴愬姛鐜?> 80%锛?2/15鍦烘櫙锛?
|
||
|
||
#### 淇<><E6B787>4锛氭牳蹇冨亣璁鹃獙璇?鉁?
|
||
- **鏂板<E98F82>H2**锛歅ython浠g爜鎵ц<E98EB5>鐜<EFBFBD><E9909C>绋冲畾鍙<E795BE>潬
|
||
- **淇<>敼H1**锛氫粠"鐢熸垚浠g爜"鏀逛负"鐢熸垚浠g爜骞舵垚鍔熸墽琛?
|
||
- **寮鸿皟**锛欰I鐢熸垚浠g爜 + 鐪熷疄鎵ц<E98EB5> + 琛ㄦ牸鍒锋柊鏄<E69F8A>樊寮傚寲浠峰€?
|
||
|
||
---
|
||
|
||
### V1.1锛?025-12-06锛? 鏋舵瀯鍚堣<E98D9A>鎬т慨姝?鈿狅笍 閲嶈<E996B2>
|
||
|
||
**淇<><E6B787>鍐呭<E98D90>**锛氭牴鎹<E789B4>敤鎴蜂弗鑲冩彁閱掞紝淇<E7B49D><E6B787>浠ヤ笅杩濆弽瑙勮寖鐨勯棶棰橈細
|
||
|
||
#### 淇<><E6B787>1锛氬己鍒跺<E98D92>鐢ㄥ钩鍙拌兘鍔?鉁?
|
||
- **鍘熼敊璇?*锛氬缓璁<E7BC93>嚜宸卞疄鐜癝ession绠$悊銆佸瓨鍌ㄣ€佹棩蹇?
|
||
- **宸蹭慨姝?*锛氬己鍒朵娇鐢╜storage`, `logger`, `cache`, `prisma`, `LLMFactory`
|
||
- **褰卞搷绔犺妭**锛氭墍鏈塂ay 1-15鐨勪唬鐮佺ず渚?
|
||
|
||
#### 淇<><E6B787>2锛歋ession瀛樺偍鏂瑰紡 鉁?
|
||
- **鍘熼敊璇?*锛氬缓璁<E7BC93>敤`Map<sessionId, data>`鍐呭瓨缂撳瓨
|
||
- **宸蹭慨姝?*锛歋ession瀛樻暟鎹<E69A9F>簱锛坄dc_tool_c_sessions`琛<>級
|
||
- **鍘熷洜**锛氳繚鍙嶄簯鍘熺敓瑙勮寖绗?鏉★紙绂佹<E7BB82>鍐呭瓨缂撳瓨锛?
|
||
|
||
#### 淇<><E6B787>3锛氭枃浠跺す缁撴瀯 鉁?
|
||
- **鍘熼敊璇?*锛氬缓璁<E7BC93>垱寤篳python-service/`銆乣node-service/`瀛愭枃浠跺す
|
||
- **宸蹭慨姝?*锛氶伒寰猼ool-b缁撴瀯锛坄services/`, `controllers/`, `routes/`锛?
|
||
- **鍙傝€?*锛歚backend/src/modules/dc/tool-b/`
|
||
|
||
#### 淇<><E6B787>4锛氭妧鏈<E5A6A7>爤璇存槑 鉁?
|
||
- **鍘熼敊璇?*锛氭湭寮鸿皟澶嶇敤鐜版湁鑳藉姏
|
||
- **宸蹭慨姝?*锛氭槑纭<E6A791>爣娉?宸叉湁"銆?澶嶇敤骞冲彴鑳藉姏"
|
||
- **鏂板<E98F82>**锛氫簯鍘熺敓寮€鍙戣<E98D99>鑼冩<E991BC>鏌ユ竻鍗?
|
||
|
||
#### 淇<><E6B787>5锛氫唬鐮佺ず渚?鉁?
|
||
- **鍘熼敊璇?*锛欴ay 1-5鐨勪唬鐮佺ず渚嬫湭浣撶幇骞冲彴鏈嶅姟
|
||
- **宸蹭慨姝?*锛氭墍鏈変唬鐮佺ず渚嬮兘浣跨敤`import { storage } from '@/common/storage'`绛?
|
||
- **鏂板<E98F82>**锛氬父瑙侀敊璇<E6958A>ず渚嬶紙鉂?涓ョ<E6B693>锛?
|
||
|
||
#### 鏂板<E98F82>绔犺妭 鉁?
|
||
- **寮€鍙戝墠蹇呰<E8B987>**锛氬己璋冧笉瑕侀噸澶嶉€犺疆瀛?
|
||
- **浜戝師鐢熻<E990A2>鑼冨己鍒惰<E98D92>姹?*锛氬垪鍑?鏉℃牳蹇冭<E8B987>鑼?
|
||
- **甯歌<E794AF>閿欒<E996BF>绀轰緥**锛氬睍绀?涓<>弗绂佺殑閿欒<E996BF>鍐欐硶
|
||
|
||
---
|
||
|
||
**鏂囨。鐘舵€侊細** 鉁?宸插畬鎴愶紙V1.1 鏋舵瀯鍚堣<E98D9A>鎬т慨姝g増锛?
|
||
**涓嬩竴姝ワ細** 鍥㈤槦Review 鈫?涓ユ牸鎸夎<E98EB8>鑼冨紑鍙?
|
||
**璐熻矗浜猴細** 椤圭洰缁忕悊
|
||
**鍒涘缓鏃ユ湡锛?* 2025-12-06
|
||
**淇<><E6B787>鏃ユ湡锛?* 2025-12-06锛堟灦鏋勫悎瑙勬€т慨姝o級
|
||
|
||
**鈿狅笍 閲嶈<E996B2>鎻愰啋**锛?
|
||
1. 寮€鍙戝墠蹇呴』闃呰<E99783>锛歚docs/04-寮€鍙戣<E98D99>鑼?08-浜戝師鐢熷紑鍙戣<E98D99>鑼?md`
|
||
2. 鍙傝€冪幇鏈夊疄鐜帮細`backend/src/modules/dc/tool-b/`
|
||
3. 绂佹<E7BB82>杩濆弽瑙勮寖锛氬唴瀛樼紦瀛樸€佹湰鍦版枃浠跺瓨鍌ㄣ€侀噸澶嶅疄鐜板钩鍙拌兘鍔?
|
||
|