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%)
17 KiB
撌亙<EFBFBD>C Day 2 撘<><E69298>穃<EFBFBD><E7A983>鞉<EFBFBD>餌<EFBFBD>
<EFBFBD>交<EFBFBD>: 2025-12-06
**撘<><E69298>𤑳𤌍<F0A491B3>?: Session蝞∠<E89D9E> + <20>唳旿憭<E697BF><E686AD>
**撘<><E69298>𤑳𠶖<F0A491B3>?: <20>?<3F>券<EFBFBD>摰峕<E691B0>
<EFBFBD><EFBFBD> 摰峕<E691B0><E5B395><EFBFBD><EFBFBD>璁<EFBFBD><E79281>
| 隞餃𦛚蝐餃<EFBFBD> | 摰峕<EFBFBD>隞餃𦛚<EFBFBD>? | <EFBFBD>颱遙<EFBFBD>⊥㺭 | 摰峕<EFBFBD><EFBFBD>? |
|---|---|---|---|
| <EFBFBD>唳旿摨廍chema | 1 | 1 | 100% |
| *<EFBFBD>滚𦛚撅<EFBFBD><EFBFBD><EFBFBD>? | 2 | 2 | 100% |
| *<EFBFBD>批<EFBFBD><EFBFBD>典<EFBFBD><EFBFBD>? | 1 | 1 | 100% |
| 頝舐眏<EFBFBD>滨蔭 | 1 | 1 | 100% |
| API瘚贝<EFBFBD> | 7 | 7 | 100% |
| <EFBFBD>餉恣 | 12 | 12 | 100% <20>? |
<EFBFBD>?撌脣<E6928C><E884A3>𣂷遙<F0A382B7>⊥<EFBFBD><E28AA5>?
1. <20>唳旿摨廍chema霈曇恣銝𤾸<E98A9D>撱?
隞餃𦛚1.1: 霈曇恣Prisma璅∪<E79285> <20>?
- <EFBFBD><EFBFBD>辣:
backend/prisma/schema.prisma - <EFBFBD>啣<EFBFBD>璅∪<EFBFBD>:
DcToolCSession - **摮埈挾<E59F88>?*: 12銝?
- id, userId, fileName, fileKey
- totalRows, totalCols, columns, encoding, fileSize
- createdAt, updatedAt, expiresAt
<EFBFBD>喲睸霈曇恣<EFBFBD>喟<EFBFBD>:
- <EFBFBD>?蝚血<E89D9A>鈭穃<E988AD><E7A983>蠘<EFBFBD><E8A098><EFBFBD><EFBFBD>DB<44>芸<EFBFBD><E88AB8><EFBFBD>㺭<EFBFBD>殷<EFBFBD>銝滚<E98A9D>憭扳㺭<E689B3>?
- <EFBFBD>?<3F>𣳇膄鈭<E88684>reviewData摮埈挾嚗<E68CBE><E59A97>OSS摰墧𧒄霂餃<E99C82>嚗?
- <EFBFBD>?瘛餃<E7989B>expiresAt<41>舀<EFBFBD>10<31><30><EFBFBD>餈<EFBFBD><E9A488>
- <EFBFBD>?雿輻鍂JSONB摮睃<E691AE>columns<6E>啁<EFBFBD>
隞餃𦛚1.2: <20>𥕦遣<F0A595A6>唳旿摨栞” <20>?
- <EFBFBD>孵<EFBFBD>: Node.js<6A>𡁏𧋦<F0A1818F>湔𦻖<E6B994>扯<EFBFBD>SQL嚗<4C><E59A97><EFBFBD>㥍risma db push<73>脩<EFBFBD>嚗?
- <EFBFBD>𡁏𧋦:
backend/scripts/create-tool-c-table.mjs(139銵? - 蝏𤘪<EFBFBD>:
- <EFBFBD>?銵典<E98AB5>撱箸<E692B1><E7AEB8>?
- <EFBFBD>?3銝芰揣撘訫<E69298>撱箸<E692B1><E7AEB8>?
- <EFBFBD>?銵冽釣<E586BD>𦠜溶<F0A6A09C>䭾<EFBFBD><E4ADBE>?
- <EFBFBD>?Prisma Client<6E>齿鰵<E9BDBF><E9B0B5><EFBFBD>
**<2A>𥕦遣<F0A595A6><E981A3>揣撘?*:
dc_tool_c_sessions_pkey- 銝駁睸蝝W<E89D9D>idx_dc_tool_c_sessions_user_id- <20>冽<EFBFBD><E586BD>亥砭蝝W<E89D9D>idx_dc_tool_c_sessions_expires_at- 餈<><E9A488>皜<EFBFBD><E79A9C>蝝W<E89D9D>
2. <20>滚𦛚撅<F0A69B9A><E69285><EFBFBD>?
隞餃𦛚2.1: SessionService摰䂿緵 <20>?
- <EFBFBD><EFBFBD>辣:
backend/src/modules/dc/tool-c/services/SessionService.ts(383銵? - <EFBFBD>蠘<EFBFBD>:
-
<EFBFBD>?
createSession()- <20>𥕦遣隡朞<E99AA1>- <EFBFBD><EFBFBD>辣憭批<EFBFBD>撉諹<EFBFBD>嚗?10MB嚗?
- Excel<EFBFBD><EFBFBD><EFBFBD>閫<EFBFBD><EFBFBD>嚗<EFBFBD>妟<EFBFBD>賜<EFBFBD>嚗?
- 銝𠹺<EFBFBD><EFBFBD>記SS嚗īlatform storage<67>滚𦛚嚗?
- 靽嘥<EFBFBD><EFBFBD><EFBFBD>㺭<EFBFBD>桀<EFBFBD>DB
- 餈𥪜<EFBFBD>Session靽⊥<EFBFBD>
-
<EFBFBD>?
getSession()- <20>瑕<EFBFBD>隡朞<E99AA1>- 隞𥟠B<EFBFBD>亥砭Session
- 璉<EFBFBD><EFBFBD>交糓<EFBFBD>西<EFBFBD><EFBFBD>?
- 餈𥪜<EFBFBD><EFBFBD><EFBFBD>㺭<EFBFBD>?
-
<EFBFBD>?
getPreviewData()- <20>瑕<EFBFBD>憸<EFBFBD><E686B8><EFBFBD>唳旿- 隞窻SS銝贝蝸<EFBFBD><EFBFBD>辣<EFBFBD>啣<EFBFBD>摮?
- <EFBFBD><EFBFBD><EFBFBD>閫<EFBFBD><EFBFBD>Excel
- 餈𥪜<EFBFBD><EFBFBD>?00銵?
-
<EFBFBD>?
getFullData()- <20>瑕<EFBFBD>摰峕㟲<E5B395>唳旿- 隞窻SS銝贝蝸摰峕㟲<EFBFBD><EFBFBD>辣
- <EFBFBD><EFBFBD><EFBFBD>閫<EFBFBD><EFBFBD>
- 餈𥪜<EFBFBD><EFBFBD><EFBFBD><EFBFBD>㗇㺭<EFBFBD>?
-
<EFBFBD>?
deleteSession()- <20>𣳇膄隡朞<E99AA1>- <EFBFBD>𣳇膄OSS<EFBFBD><EFBFBD>辣
- <EFBFBD>𣳇膄DB霈啣<EFBFBD>
- <EFBFBD>躰秤摰寥<EFBFBD>嚗㇉SS<EFBFBD>𣳇膄憭梯揖銝滚蔣<EFBFBD>䄂B嚗?
-
<EFBFBD>?
updateHeartbeat()- <20>湔鰵敹<E9B0B5>歲- 撱園鵭expiresAt 10<31><30><EFBFBD>
- <EFBFBD>湔鰵updatedAt<EFBFBD>園𡢿<EFBFBD>?
-
<EFBFBD>?
cleanExpiredSessions()- 皜<><E79A9C>餈<EFBFBD><E9A488>隡朞<E99AA1>- <EFBFBD>亥砭餈<EFBFBD><EFBFBD>Session
- <EFBFBD>寥<EFBFBD><EFBFBD>𣳇膄
- 餈𥪜<EFBFBD>皜<EFBFBD><EFBFBD><EFBFBD>圈<EFBFBD>
-
隞<EFBFBD><EFBFBD>蝷箔<EFBFBD>:
async createSession(userId: string, fileName: string, fileBuffer: Buffer) {
// 1. 撉諹<E69289><E8ABB9><EFBFBD>辣憭批<E686AD>
if (fileBuffer.length > 10 * 1024 * 1024) {
throw new Error('<27><>辣憭批<E686AD>頞<EFBFBD><E9A09E>10MB');
}
// 2. <20><><EFBFBD>閫<EFBFBD><E996AB>Excel嚗<6C>妟<EFBFBD>賜<EFBFBD>嚗?
const workbook = xlsx.read(fileBuffer, { type: 'buffer' });
const data = xlsx.utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]]);
// 3. 銝𠹺<E98A9D><F0A0B9BA>記SS
const fileKey = `dc/tool-c/sessions/${userId}/${Date.now()}-${fileName}`;
await storage.upload(fileKey, fileBuffer);
// 4. 靽嘥<E99DBD><E598A5>蚤B嚗<42>蘨摮睃<E691AE><E79D83>唳旿嚗?
const session = await prisma.dcToolCSession.create({
data: { userId, fileName, fileKey, totalRows, totalCols, columns, ... }
});
return session;
}
隞餃𦛚2.2: DataProcessService摰䂿緵 <20>?
- <EFBFBD><EFBFBD>辣:
backend/src/modules/dc/tool-c/services/DataProcessService.ts(303銵? - <EFBFBD>蠘<EFBFBD>:
-
<EFBFBD>?
parseExcel()- 閫<><E996AB>Excel<65><6C>辣- <EFBFBD><EFBFBD><EFBFBD>霂餃<EFBFBD>嚗<EFBFBD>妟<EFBFBD>賜<EFBFBD>嚗?
- 頧祆揢銝撇SON<EFBFBD>澆<EFBFBD>
- <EFBFBD>𣂼<EFBFBD>銵峕㺭<EFBFBD><EFBFBD><EFBFBD><EFBFBD>啜<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
-
<EFBFBD>?
validateFile()- 撉諹<E69289><E8ABB9><EFBFBD>辣- <EFBFBD><EFBFBD>辣憭批<EFBFBD>璉<EFBFBD><EFBFBD>伐<EFBFBD><10MB嚗?
- <EFBFBD><EFBFBD>辣<EFBFBD>澆<EFBFBD>璉<EFBFBD><EFBFBD>伐<EFBFBD>.xlsx, .xls, .csv嚗?
- <EFBFBD><EFBFBD>捆摰峕㟲<EFBFBD>扳<EFBFBD><EFBFBD>?
- 餈𥪜<EFBFBD><EFBFBD>见末<EFBFBD>躰秤靽⊥<EFBFBD>
-
<EFBFBD>?
inferColumnTypes()- <20>冽鱏<E586BD>㛖掩<E39B96>页<EFBFBD><E9A1B5>舫<EFBFBD>㚁<EFBFBD>- <EFBFBD>硋<EFBFBD>10銵峕甅<EFBFBD>?
- <EFBFBD>冽鱏蝐餃<EFBFBD>嚗䭰umber, string, date, boolean, mixed
- 餈𥪜<EFBFBD>蝐餃<EFBFBD>靽⊥<EFBFBD>
-
<EFBFBD>?
formatFileSize()- <20>澆<EFBFBD><E6BE86>𡝗<EFBFBD>隞嗅之撠?- <EFBFBD>芸𢆡頧祆揢<EFBFBD>蓥<EFBFBD>嚗㇂, KB, MB嚗?
-
<EFBFBD>?
generateFileSummary()- <20><><EFBFBD><EFBFBD><EFBFBD>辣<EFBFBD>䁅<EFBFBD>- <EFBFBD><EFBFBD>鉄<EFBFBD><EFBFBD><EFBFBD>匧<EFBFBD>靽⊥<EFBFBD>
- <EFBFBD>?銵峕甅<E5B395>祆㺭<E7A586>?
-
隞<EFBFBD><EFBFBD>蝷箔<EFBFBD>:
parseExcel(buffer: Buffer): ParsedExcelData {
// <20><><EFBFBD>閫<EFBFBD><E996AB>嚗<EFBFBD>妟<EFBFBD>賜<EFBFBD>嚗?
const workbook = xlsx.read(buffer, { type: 'buffer' });
const sheet = workbook.Sheets[workbook.SheetNames[0]];
const data = xlsx.utils.sheet_to_json(sheet);
return {
data,
columns: Object.keys(data[0] || {}),
totalRows: data.length,
totalCols: Object.keys(data[0] || {}).length,
};
}
validateFile(buffer: Buffer, fileName: string): ValidationResult {
// 1. <20><>辣憭批<E686AD>
if (buffer.length > 10 * 1024 * 1024) {
return { valid: false, error: '<27><>辣頞<E8BEA3><E9A09E>10MB' };
}
// 2. <20><>辣<EFBFBD>澆<EFBFBD>
const ext = fileName.substring(fileName.lastIndexOf('.'));
if (!['.xlsx', '.xls', '.csv'].includes(ext)) {
return { valid: false, error: '銝齿𣈲<E9BDBF><F0A388B2><EFBFBD><EFBFBD>澆<EFBFBD>' };
}
// 3. <20><>捆摰峕㟲<E5B395>?
try {
this.parseExcel(buffer);
} catch (error) {
return { valid: false, error: '<27><>辣<EFBFBD>䭾<EFBFBD>閫<EFBFBD><E996AB>' };
}
return { valid: true };
}
3. <20>批<EFBFBD><E689B9>典<EFBFBD>撘<EFBFBD><E69298>?
隞餃𦛚3.1: SessionController摰䂿緵 <20>?
-
<EFBFBD><EFBFBD>辣:
backend/src/modules/dc/tool-c/controllers/SessionController.ts(300銵? -
<EFBFBD>蠘<EFBFBD>: 6銝服PI蝡舐<E89DA1>
-
<EFBFBD>?
upload()- POST /sessions/upload- <EFBFBD>交𤣰multipart/form-data<74><61>辣銝𠹺<E98A9D>
- 靚<EFBFBD>鍂SessionService.createSession()
- 餈𥪜<EFBFBD>201 + Session靽⊥<E99DBD>
-
<EFBFBD>?
getSession()- GET /sessions/:id- <EFBFBD>瑕<EFBFBD>Session<EFBFBD><EFBFBD>㺭<EFBFBD>?
- 璉<EFBFBD><EFBFBD>亥<EFBFBD><EFBFBD>?
- 餈𥪜<EFBFBD>200 + Session靽⊥<E99DBD>
-
<EFBFBD>?
getPreviewData()- GET /sessions/:id/preview- <EFBFBD>瑕<EFBFBD><EFBFBD>?00銵峕㺭<E5B395>?
- 隞窻SS摰墧𧒄霂餃<EFBFBD>
- 餈𥪜<EFBFBD>200 + 憸<><E686B8><EFBFBD>唳旿
-
<EFBFBD>?
getFullData()- GET /sessions/:id/full- <EFBFBD>瑕<EFBFBD>摰峕㟲<EFBFBD>唳旿
- 隞窻SS銝贝蝸
- 餈𥪜<EFBFBD>200 + 摰峕㟲<E5B395>唳旿
-
<EFBFBD>?
deleteSession()- DELETE /sessions/:id- <EFBFBD>𣳇膄OSS<EFBFBD><EFBFBD>辣
- <EFBFBD>𣳇膄DB霈啣<EFBFBD>
- 餈𥪜<EFBFBD>200 + <20>𣂼<EFBFBD>靽⊥<E99DBD>
-
<EFBFBD>?
updateHeartbeat()- POST /sessions/:id/heartbeat- 撱園鵭餈<EFBFBD><EFBFBD><EFBFBD>園𡢿
- 餈𥪜<EFBFBD>200 + <20>啗<EFBFBD><E59597><EFBFBD>𧒄<EFBFBD>?
-
<EFBFBD>躰秤憭<EFBFBD><EFBFBD>:
- Session銝滚<EFBFBD><EFBFBD>?<3F>?404
- Session餈<EFBFBD><EFBFBD> <20>?404
- <EFBFBD>滚𦛚<EFBFBD>券<EFBFBD>霂?<3F>?500
- <EFBFBD><EFBFBD>㺭<EFBFBD>躰秤 <20>?400
隞餃𦛚3.2: 頝舐眏<E88890>滨蔭<E6BBA8>湔鰵 <20>?
- <EFBFBD><EFBFBD>辣:
backend/src/modules/dc/tool-c/routes/index.ts(62銵? - <EFBFBD>啣<EFBFBD>頝舐眏: 6銝杵ession蝞∠<E89D9E>頝舐眏
- 頝舐眏<EFBFBD>滨<EFBFBD>:
/api/v1/dc/tool-c
4. API瘚贝<E7989A>撉峕𤣰
瘚贝<EFBFBD><EFBFBD>唳旿
// 8銵?x 7<>堒龫<E5A092>埈㺭<E59F88>?
[
{ patient_id: 'P001', name: '撘牐<E69298>', age: 25, gender: '<27>?, diagnosis: '<EFBFBD>笔<EFBFBD>', sbp: 120, dbp: 80 },
{ patient_id: 'P002', name: '<EFBFBD>𤾸<EFBFBD>', age: 65, gender: '憟?, diagnosis: '擃䁅<EFBFBD><EFBFBD>?, sbp: 150, dbp: 95 },
// ... <20>?<3F>∟扇敶?
]
瘚贝<EFBFBD>蝏𤘪<EFBFBD>嚗?/7 <20>朞<EFBFBD>嚗争<E59A97>
瘚贝<EFBFBD>1: 銝𠹺<E98A9D><F0A0B9BA><EFBFBD>辣<EFBFBD>𥕦遣Session <20>?
- 霂瑟<EFBFBD>嚗䥪OST /sessions/upload嚗éultipart嚗?
- <EFBFBD>滚<EFBFBD>嚗?01 Created
- Session ID:
e7abe493-009d-4f97-8342-7a00c09c39fc - <EFBFBD>唳旿撉諹<EFBFBD>嚗尠<EFBFBD> 8銵?x 7<>?摰<><E691B0><EFBFBD>寥<EFBFBD>
- <EFBFBD>堒<EFBFBD>霂<EFBFBD><EFBFBD>嚗尠<EFBFBD> 7銝芸<E98A9D><E88AB8>滚<EFBFBD><E6BB9A>冽迤蝖?
瘚贝<EFBFBD>2: <20>瑕<EFBFBD>Session靽⊥<E99DBD> <20>?
- 霂瑟<EFBFBD>嚗鎭ET /sessions/:id
- <EFBFBD>滚<EFBFBD>嚗?00 OK
- 餈𥪜<EFBFBD><EFBFBD>唳旿嚗𡁜<EFBFBD><EFBFBD>唳旿摰峕㟲嚗<EFBFBD><EFBFBD>隞嗅<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>啜<EFBFBD><EFBFBD><EFBFBD><EFBFBD>啜<EFBFBD><EFBFBD><EFBFBD><EFBFBD>溻<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>𧒄<EFBFBD>湛<EFBFBD>
瘚贝<EFBFBD>3: <20>瑕<EFBFBD>憸<EFBFBD><E686B8><EFBFBD>唳旿 <20>?
- 霂瑟<EFBFBD>嚗鎭ET /sessions/:id/preview
- <EFBFBD>滚<EFBFBD>嚗?00 OK
- 餈𥪜<EFBFBD><EFBFBD>唳旿嚗𡁜<EFBFBD>100銵䕘<EFBFBD>摰鮋<EFBFBD>8銵<EFBFBD><EFBFBD><EFBFBD>刻<EFBFBD><EFBFBD>痹<EFBFBD>
- <EFBFBD>唳旿摰峕㟲<EFBFBD>改<EFBFBD><EFBFBD>?銝剜<E98A9D>摮埈挾甇<E68CBE>&閫<EFBC86><E996AB>
瘚贝<EFBFBD>4: <20>瑕<EFBFBD>摰峕㟲<E5B395>唳旿 <20>?
- 霂瑟<EFBFBD>嚗鎭ET /sessions/:id/full
- <EFBFBD>滚<EFBFBD>嚗?00 OK
- 隞窻SS霂餃<EFBFBD>嚗尠<EFBFBD> 甇<>虜
- <EFBFBD>唳旿銝<EFBFBD><EFBFBD>湔<EFBFBD>改<EFBFBD><EFBFBD>?銝𦒘<E98A9D>隡䭾㺭<E4ADBE>桀<EFBFBD><E6A180>其<EFBFBD><E585B6>?
瘚贝<EFBFBD>5: <20>湔鰵敹<E9B0B5>歲 <20>?
- 霂瑟<EFBFBD>嚗䥪OST /sessions/:id/heartbeat
- <EFBFBD>滚<EFBFBD>嚗?00 OK
- 餈<EFBFBD><EFBFBD><EFBFBD>園𡢿嚗尠<EFBFBD> 撱園鵭10<31><30><EFBFBD>
瘚贝<EFBFBD>6: <20>𣳇膄Session <20>?
- 霂瑟<EFBFBD>嚗鋽ELETE /sessions/:id
- <EFBFBD>滚<EFBFBD>嚗?00 OK
- OSS<EFBFBD><EFBFBD>辣嚗尠<EFBFBD> <20>𣳇膄<F0A3B387>𣂼<EFBFBD>
- DB霈啣<EFBFBD>嚗尠<EFBFBD> <20>𣳇膄<F0A3B387>𣂼<EFBFBD>
瘚贝<EFBFBD>7: 撉諹<E69289><E8ABB9>𣳇膄 <20>?
- 霂瑟<EFBFBD>嚗鎭ET /sessions/:id嚗<64>歇<EFBFBD>𣳇膄嚗?
- <EFBFBD>滚<EFBFBD>嚗?04 Not Found
- 撉諹<EFBFBD>蝏𤘪<EFBFBD>嚗尠<EFBFBD> Session撌脫迤蝖桀<E89D96><E6A180>?
<EFBFBD><EFBFBD> <20>啣<EFBFBD><E595A3><EFBFBD>辣皜<E8BEA3><E79A9C>
<EFBFBD>唳旿摨?
backend/prisma/schema.prisma- <20>啣<EFBFBD>DcToolCSession璅∪<E79285>backend/prisma/migrations/create_tool_c_session.sql- SQL餈<4C>宏<EFBFBD><E5AE8F>辣backend/scripts/create-tool-c-table.mjs- 銵典<E98AB5>撱箄<E692B1><E7AE84>穿<EFBFBD>139銵䕘<E98AB5>
<EFBFBD>滚𦛚撅?
backend/src/modules/dc/tool-c/services/SessionService.ts- 383銵?<3F>?backend/src/modules/dc/tool-c/services/DataProcessService.ts- 303銵?<3F>?
<EFBFBD>批<EFBFBD><EFBFBD>典<EFBFBD>
backend/src/modules/dc/tool-c/controllers/SessionController.ts- 300銵?<3F>?
頝舐眏撅?
backend/src/modules/dc/tool-c/routes/index.ts- <20>湔鰵嚗?2銵?<3F>?
瘚贝<EFBFBD><EFBFBD>𡁏𧋦
backend/test-tool-c-day2.mjs- 383銵?<3F>?
<EFBFBD><EFBFBD>﹝
docs/03-銝𡁜𦛚璅∪<E79285>/DC-<2D>唳旿皜<E697BF><E79A9C><EFBFBD>渡<EFBFBD>/06-撘<><E69298>𤏸扇敶?2025-12-06_撌亙<E6928C>C_Day2撘<32><E69298>穃<EFBFBD><E7A983>鞉<EFBFBD>餌<EFBFBD>.md- <20>祆<EFBFBD>隞?
<EFBFBD>啣<EFBFBD>隞<EFBFBD><EFBFBD><EFBFBD>餉恣: ~1,900+ 銵?
<EFBFBD>㴓 <20>詨<EFBFBD><E8A9A8>蠘<EFBFBD>摰䂿緵
<EFBFBD>蠘<EFBFBD>1: Excel<65><6C>辣銝𠹺<E98A9D> <20>?
瘚<EFBFBD><EFBFBD>:
<EFBFBD>冽<EFBFBD>銝𠹺<EFBFBD>Excel <20>?<3F><>辣撉諹<E69289> <20>?<3F><><EFBFBD>閫<EFBFBD><E996AB> <20>?銝𠹺<E98A9D>OSS <20>?靽嘥<E99DBD><E598A5><EFBFBD>㺭<EFBFBD>桀<EFBFBD>DB <20>?餈𥪜<E9A488>Session
**<2A><><EFBFBD>臭漁<E887AD>?*:
- <EFBFBD>?<3F>嗉氜<E59789>矋<EFBFBD>Excel<65>函<EFBFBD><E587BD><EFBFBD><EFBFBD>憭<EFBFBD><E686AD>
- <EFBFBD>?OSS摮睃<E691AE>嚗𡁏<E59A97>隞嗡<E99A9E>隡惩<E99AA1>鈭穃<E988AD><E7A983>?
- <EFBFBD>?<3F><>㺭<EFBFBD>桀<EFBFBD>蝳鳴<E89DB3>DB<44>芸<EFBFBD><E88AB8><EFBFBD>撠誩<E692A0>閬<EFBFBD>縑<EFBFBD>?
隞<EFBFBD><EFBFBD><EFBFBD><EFBFBD>挾:
// <20><><EFBFBD>閫<EFBFBD><E996AB>嚗<EFBFBD><E59A97><EFBFBD>賜<EFBFBD>嚗?
const workbook = xlsx.read(fileBuffer, { type: 'buffer' });
const data = xlsx.utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]]);
// 銝𠹺<E98A9D><F0A0B9BA>記SS
await storage.upload(fileKey, fileBuffer);
// 靽嘥<E99DBD><E598A5><EFBFBD>㺭<EFBFBD>桀<EFBFBD>DB嚗<42><E59A97>摮睃之<E79D83>唳旿嚗?
await prisma.dcToolCSession.create({ data: { userId, fileName, fileKey, ... } });
<EFBFBD>蠘<EFBFBD>2: Session蝞∠<E89D9E> <20>?
瘚<EFBFBD><EFBFBD>:
<EFBFBD>𥕦遣Session <20>?10<31><30><EFBFBD>餈<EFBFBD><E9A488> <20>?敹<>歲撱園鵭 <20>?<3F>芸𢆡皜<F0A286A1><E79A9C>
**<2A><><EFBFBD>臭漁<E887AD>?*:
- <EFBFBD>?10<31><30><EFBFBD>餈<EFBFBD><E9A488><EFBFBD>箏<EFBFBD>
- <EFBFBD>?敹<>歲撱園鵭嚗<E9B5AD><E59A97>蝡臬<E89DA1><E887AC>嗅<EFBFBD><E59785><EFBFBD><EFBFBD>
- <EFBFBD>?<3F>芸𢆡皜<F0A286A1><E79A9C>餈<EFBFBD><E9A488>Session
- <EFBFBD>?餈<><E9A488>璉<EFBFBD><E79289>亦揣撘蓥<E69298><E893A5>?
隞<EFBFBD><EFBFBD><EFBFBD><EFBFBD>挾:
// <20>𥕦遣<F0A595A6>嗉挽蝵株<E89DB5><E6A0AA><EFBFBD>𧒄<EFBFBD>?
const expiresAt = new Date(Date.now() + 10 * 60 * 1000);
// 敹<>歲撱園鵭
const newExpiresAt = new Date(Date.now() + 10 * 60 * 1000);
await prisma.dcToolCSession.update({
where: { id: sessionId },
data: { expiresAt: newExpiresAt }
});
// 皜<><E79A9C>餈<EFBFBD><E9A488>Session
const expiredSessions = await prisma.dcToolCSession.findMany({
where: { expiresAt: { lt: new Date() } }
});
<EFBFBD>蠘<EFBFBD>3: <20>唳旿<E594B3>瑕<EFBFBD>嚗<EFBFBD><E59A97>閫?摰峕㟲嚗争<E59A97>
瘚<EFBFBD><EFBFBD>:
<EFBFBD>滨垢霂瑟<EFBFBD> <20>?璉<><E79289>兄ession <20>?隞窻SS銝贝蝸 <20>?<3F><><EFBFBD>閫<EFBFBD><E996AB> <20>?餈𥪜<E9A488><F0A5AA9C>唳旿
**<2A><><EFBFBD>臭漁<E887AD>?*:
- <EFBFBD>?<3F>厰<EFBFBD>霂餃<E99C82>嚗𡁻<E59A97>閫?00銵䕘<E98AB5>摰峕㟲霂餃<E99C82><E9A483>券<EFBFBD>
- <EFBFBD>?<3F><><EFBFBD>閫<EFBFBD><E996AB>嚗帋<E59A97><E5B88B>賜<EFBFBD>
- <EFBFBD>?蝻枏<E89DBB>隡睃<E99AA1>嚗𡁜<E59A97>蝡臬虾蝻枏<E89DBB>憸<EFBFBD><E686B8><EFBFBD>唳旿
隞<EFBFBD><EFBFBD><EFBFBD><EFBFBD>挾:
async getPreviewData(sessionId: string) {
const session = await this.getSession(sessionId);
// 隞窻SS銝贝蝸<E8B49D>啣<EFBFBD>摮?
const buffer = await storage.download(session.fileKey);
// <20><><EFBFBD>閫<EFBFBD><E996AB>
const workbook = xlsx.read(buffer, { type: 'buffer' });
const data = xlsx.utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]]);
// 餈𥪜<E9A488><F0A5AA9C>?00銵?
return { ...session, previewData: data.slice(0, 100) };
}
<EFBFBD><EFBFBD> 鈭穃<E988AD><E7A983>蠘<EFBFBD><E8A098><EFBFBD><EFBFBD>摰<EFBFBD><E691B0><EFBFBD>?
<EFBFBD>?敹<>◆<EFBFBD>萄<EFBFBD><E89084><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>100%蝚血<E89D9A>嚗?
| 閫<EFBFBD><EFBFBD> | 閬<EFBFBD><EFBFBD> | 摰䂿緵 | <EFBFBD>嗆<EFBFBD>? |
|---|---|---|---|
| <EFBFBD><EFBFBD>辣摮睃<EFBFBD> | 雿輻鍂storage<EFBFBD>滚𦛚 | <EFBFBD>?<3F><><EFBFBD>㗇<EFBFBD>隞嗡<E99A9E>隡惩<E99AA1>OSS | <EFBFBD>? |
| *<EFBFBD>嗉氜<EFBFBD>? | Excel<EFBFBD><EFBFBD><EFBFBD>閫<EFBFBD><EFBFBD> | <EFBFBD>?xlsx.read(buffer) | <EFBFBD>? |
| <EFBFBD>亙<EFBFBD>蝟餌<EFBFBD> | 雿輻鍂logger | <EFBFBD>?<3F><><EFBFBD>㗇𠯫敹𦯀蝙<F0A6AF80>私latform logger | <EFBFBD>? |
| *<EFBFBD>唳旿摨? | 雿輻鍂<EFBFBD>典<EFBFBD>prisma | <EFBFBD>?import from config/database | <EFBFBD>? |
| 蝳<EFBFBD>迫<EFBFBD>砍𧑐摮睃<EFBFBD> | <EFBFBD>霡s.writeFile | <EFBFBD>?<3F>䭾𧋦<E4ADBE>唳<EFBFBD>隞嗆<E99A9E>雿? | <EFBFBD>? |
| *蝳<EFBFBD>迫蝖祉<EFBFBD><EFBFBD>? | 雿輻鍂<EFBFBD>臬<EFBFBD><EFBFBD>㗛<EFBFBD> | <EFBFBD>?<3F><><EFBFBD>厰<EFBFBD>蝵桀虾<E6A180>滨蔭 | <EFBFBD>? |
隞<EFBFBD><EFBFBD>摰⊥䰻皜<EFBFBD><EFBFBD>嚗<EFBFBD><EFBFBD>朞<EFBFBD>嚗?
- <EFBFBD>臬炏雿輻鍂
storage.upload()<20>屸<EFBFBD>fs.writeFile()嚗?<3F>? - Excel <20>臬炏隞𤾸<E99A9E>摮䁅圾<E48185>琜<EFBFBD><E7909C>屸<EFBFBD>靽嘥<E99DBD><E598A5>唳𧋦<E594B3>堆<EFBFBD> <20>?
- <EFBFBD>臬炏雿輻鍂<EFBFBD>典<EFBFBD>
prisma摰硺<E691B0>嚗?<3F>? - <EFBFBD>臬炏<EFBFBD><EFBFBD><EFBFBD>厰<EFBFBD>蝵桅<EFBFBD>隞?
process.env霂餃<E99C82>嚗?<3F>? - <EFBFBD>臬炏雿輻鍂
logger<20>屸<EFBFBD>console.log嚗?<3F>? - <EFBFBD><EFBFBD><EFBFBD>?async <20>賣㺭<E8B3A3>臬炏<E887AC>?try-catch嚗?<3F>?
- <EFBFBD>臬炏霈啣<EFBFBD>鈭<EFBFBD>祕蝏<EFBFBD><EFBFBD>霂舀𠯫敹梹<EFBFBD> <20>?
- <EFBFBD>臬炏餈𥪜<EFBFBD>鈭<EFBFBD><EFBFBD>憟賜<EFBFBD><EFBFBD>躰秤靽⊥<EFBFBD>嚗?<3F>?
<EFBFBD><EFBFBD> 隞<><E99A9E>韐券<E99F90><E588B8><EFBFBD><EFBFBD>
| <EFBFBD><EFBFBD><EFBFBD> | Day 1 | Day 2 | 憓鮋鵭 |
|---|---|---|---|
| <EFBFBD>啣<EFBFBD>隞<EFBFBD><EFBFBD>銵峕㺭 | ~1,300 | ~1,900 | +46% |
| *API蝡舐<EFBFBD><EFBFBD>? | 3銝芣<EFBFBD>霂? | +6銝芣迤撘? | +200% |
| <EFBFBD>滚𦛚蝐餅㺭 | 1銝? | +2銝? | +200% |
| <EFBFBD>批<EFBFBD><EFBFBD>冽㺭 | 1銝? | +1銝? | +100% |
| <EFBFBD>唳旿摨栞” | 0銝? | +1銝? | <EFBFBD>啣<EFBFBD> |
| *瘚贝<EFBFBD><EFBFBD>朞<EFBFBD><EFBFBD>? | 100% | 100% | 靽脲<EFBFBD> |
<EFBFBD><EFBFBD> API蝡舐<E89DA1>瘙<EFBFBD><E79899>鳴<EFBFBD>Day 2<>湔鰵嚗?
Python敺格<EFBFBD><EFBFBD>?(http://localhost:8000)
| <EFBFBD>寞<EFBFBD> | 蝡舐<EFBFBD> | <EFBFBD>蠘<EFBFBD> | <EFBFBD>嗆<EFBFBD>? |
|---|---|---|---|
| GET | /api/health |
<EFBFBD>亙熒璉<EFBFBD><EFBFBD>? | <EFBFBD>?Day 1 |
| POST | /api/dc/validate |
隞<EFBFBD><EFBFBD>撉諹<EFBFBD> | <EFBFBD>?Day 1 |
| POST | /api/dc/execute |
隞<EFBFBD><EFBFBD><EFBFBD>扯<EFBFBD> | <EFBFBD>?Day 1 |
Node.js<6A>𡒊垢 (http://localhost:3000)
瘚贝<EFBFBD>蝡舐<EFBFBD>嚗㇄ay 1嚗?
| <EFBFBD>寞<EFBFBD> | 蝡舐<EFBFBD> | <EFBFBD>蠘<EFBFBD> | <EFBFBD>嗆<EFBFBD>? |
|---|---|---|---|
| GET | /api/v1/dc/tool-c/test/health |
瘚贝<EFBFBD>Python<EFBFBD>滚𦛚 | <EFBFBD>? |
| POST | /api/v1/dc/tool-c/test/validate |
瘚贝<EFBFBD>隞<EFBFBD><EFBFBD>撉諹<EFBFBD> | <EFBFBD>? |
| POST | /api/v1/dc/tool-c/test/execute |
瘚贝<EFBFBD>隞<EFBFBD><EFBFBD><EFBFBD>扯<EFBFBD> | <EFBFBD>? |
Session蝞∠<EFBFBD>蝡舐<EFBFBD>嚗㇄ay 2嚗争<E59A97>
| <EFBFBD>寞<EFBFBD> | 蝡舐<EFBFBD> | <EFBFBD>蠘<EFBFBD> | <EFBFBD>嗆<EFBFBD>? | 瘚贝<EFBFBD> |
|---|---|---|---|---|
| POST | /api/v1/dc/tool-c/sessions/upload |
銝𠹺<EFBFBD>Excel | <EFBFBD>? | 201 |
| GET | /api/v1/dc/tool-c/sessions/:id |
<EFBFBD>瑕<EFBFBD>Session | <EFBFBD>? | 200 |
| GET | /api/v1/dc/tool-c/sessions/:id/preview |
<EFBFBD>瑕<EFBFBD>憸<EFBFBD><EFBFBD> | <EFBFBD>? | 200 |
| GET | /api/v1/dc/tool-c/sessions/:id/full |
<EFBFBD>瑕<EFBFBD>摰峕㟲 | <EFBFBD>? | 200 |
| DELETE | /api/v1/dc/tool-c/sessions/:id |
<EFBFBD>𣳇膄Session | <EFBFBD>? | 200 |
| POST | /api/v1/dc/tool-c/sessions/:id/heartbeat |
敹<EFBFBD>歲<EFBFBD>湔鰵 | <EFBFBD>? | 200 |
<EFBFBD><EFBFBD> <20><><EFBFBD>舫𠗕<E888AB>寡圾<E5AFA1>?
<EFBFBD>曄<EFBFBD>1: Prisma db push <20>脩<EFBFBD>
<EFBFBD>桅<EFBFBD>: <20>扯<EFBFBD>npx prisma db push<EFBFBD>嗆<EFBFBD>蝷箄<EFBFBD><EFBFBD>𣳇膄<EFBFBD>唳<EFBFBD>銵?
<EFBFBD>笔<EFBFBD>: Prisma Schema銝擧㺭<E693A7>桀<EFBFBD>摰鮋<E691B0>蝏𤘪<E89D8F>銝滚<E98A9D>甇?
閫<EFBFBD><EFBFBD><EFBFBD>寞<EFBFBD>:
- <EFBFBD>𥕦遣<EFBFBD>祉<EFBFBD><EFBFBD><EFBFBD>ode.js<6A>𡁏𧋦嚗Ếreate-tool-c-table.mjs嚗?
- 雿輻鍂
prisma.$executeRawUnsafe()<EFBFBD>湔𦻖<EFBFBD>扯<EFBFBD>SQL - <EFBFBD>芸<EFBFBD>撱摭ool C<><43>”嚗䔶<E59A97>敶勗<E695B6><E58B97>嗡<EFBFBD>銵?
隞<EFBFBD><EFBFBD>:
await prisma.$executeRawUnsafe(`
CREATE TABLE dc_schema.dc_tool_c_sessions (...)
`);
蝏𤘪<EFBFBD>: <20>?銵典<E98AB5>撱箸<E692B1><E7AEB8><EFBFBD><EFBFBD><EFBFBD>䭾㺭<E4ADBE>桐腺憭?
<EFBFBD>曄<EFBFBD>2: 頝臬<E9A09D><E887AC>怠<EFBFBD>撖澆<E69296>憭梯揖
<EFBFBD>桅<EFBFBD>: import { logger } from '@/common/logging' <20>仿<EFBFBD> ERR_MODULE_NOT_FOUND
<EFBFBD>笔<EFBFBD>: TSX<53>刻<EFBFBD>銵峕𧒄銝滩<E98A9D><E6BBA9>怨楝敺<E6A59D><E695BA><EFBFBD>?
閫<EFBFBD><EFBFBD><EFBFBD>寞<EFBFBD>: 雿輻鍂<E8BCBB>詨笆頝臬<E9A09D>撖澆<E69296>
// <20>?<3F>躰秤
import { logger } from '@/common/logging';
// <20>?甇<>&
import { logger } from '../../../../common/logging/index.js';
靽桀<EFBFBD><EFBFBD><EFBFBD>辣:
- TestController.ts <20>?
- PythonExecutorService.ts <20>?
- SessionService.ts <20>?
- DataProcessService.ts <20>?
- SessionController.ts <20>?
<EFBFBD>曄<EFBFBD>3: <20>嗉氜<E59789>䀹沲<E480B9><E6B2B2>挽霈?
<EFBFBD>桅<EFBFBD>: <20>臬炏<E887AC>求B摮睃<E691AE>previewData隞交<E99A9E><E4BAA4><EFBFBD><EFBFBD>扯<EFBFBD>嚗?
<EFBFBD><EFBFBD><EFBFBD>:
- <EFBFBD>寞<EFBFBD>A嚗鋽B摮焳reviewData <20>?<3F>扯<EFBFBD>憟踝<E6869F>雿<EFBFBD><E99BBF><EFBFBD>?<3F>嗉氜<E59789>?閫<><E996AB>
- <EFBFBD>寞<EFBFBD>B嚗𡁜<EFBFBD><EFBFBD>嗡<EFBFBD>OSS霂餃<EFBFBD> <20>?<3F>扯<EFBFBD>蝔滚榆嚗䔶<E59A97>蝚血<E89D9A>閫<EFBFBD><E996AB>
<EFBFBD>喟<EFBFBD>: <20>寞<EFBFBD>B嚗<42><E59A97><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
- <EFBFBD>?<3F>萄<EFBFBD>鈭穃<E988AD><E7A983>蠘<EFBFBD><E8A098>?
- <EFBFBD>?DB摮睃<E691AE><E79D83>誩<EFBFBD>
- <EFBFBD>?<3F>唳旿銝<E697BF><E98A9D>湔<EFBFBD>批撩
- <EFBFBD>𩤃<EFBFBD> 瘥𤩺活憸<E6B4BB><E686B8><EFBFBD><EFBFBD>霂臺SS嚗<53><E59A97>蝡臬虾蝻枏<E89DBB>嚗<EFBFBD>蔣<EFBFBD>滚虾<E6BB9A>改<EFBFBD>
<EFBFBD><EFBFBD> 敺<><E695BA>鈭钅★嚗㇄ay 3嚗?
AI隞<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>滚𦛚
- <EFBFBD>𥕦遣
AICodeService.ts - <EFBFBD><EFBFBD><EFBFBD>LLMFactory
- 霈曇恣System Prompt嚗?0銝東ew-shot蝷箔<E89DB7>嚗?
- 摰䂿緵AI銝窰ython<EFBFBD>扯<EFBFBD><EFBFBD>滚𦛚<EFBFBD><EFBFBD><EFBFBD>
- 瘛餃<EFBFBD><EFBFBD>芣<EFBFBD>靽格迤<EFBFBD>箏<EFBFBD>
AI<EFBFBD>批<EFBFBD><EFBFBD>?
- <EFBFBD>𥕦遣
AIController.ts - POST
/ai/chat- AI撖寡<E69296> - POST
/ai/execute- <20>扯<EFBFBD>AI隞<49><E99A9E> - GET
/ai/history/:sessionId- 撖寡<E69296><E5AFA1><EFBFBD>蟮
瘚贝<EFBFBD><EFBFBD>箸艶
- 瘚贝<EFBFBD>AI<EFBFBD><EFBFBD><EFBFBD>蝞<EFBFBD><EFBFBD>蓥誨<EFBFBD>?
- 瘚贝<EFBFBD>AI<EFBFBD><EFBFBD><EFBFBD><EFBFBD>餌<EFBFBD>皜<EFBFBD><EFBFBD>隞<EFBFBD><EFBFBD>
- 瘚贝<EFBFBD><EFBFBD>芣<EFBFBD>靽格迤<EFBFBD>箏<EFBFBD>
- 蝡臬<EFBFBD>蝡舀<EFBFBD>霂𤏪<EFBFBD>銝𠹺<EFBFBD> <20>?AI憭<49><E686AD> <20>?蝏𤘪<E89D8F>撖澆枂嚗?
<EFBFBD><EFBFBD> Day 2 <20>餌<EFBFBD>
<EFBFBD>鞉<EFBFBD>
- <EFBFBD>?Session蝞∠<EFBFBD>摰峕㟲摰䂿緵: 6銝服PI蝡舐<E89DA1>嚗?/7瘚贝<E7989A><E8B49D>朞<EFBFBD>
- <EFBFBD>?**<2A>嗉氜<E59789>䀹沲<E480B9>?*: 摰<><E691B0>蝚血<E89D9A>鈭穃<E988AD><E7A983>蠘<EFBFBD><E8A098>?
- <EFBFBD>?**<2A>唳旿摨㯄<E691A8><E3AF84>?*: 銵典<E98AB5>撱箸<E692B1><E7AEB8><EFBFBD><EFBFBD>蝝W<E89D9D>隡睃<E99AA1>
- <EFBFBD>?OSS<EFBFBD><EFBFBD><EFBFBD>: <20><>辣銝𠹺<E98A9D>/銝贝蝸/<2F>𣳇膄甇<E88684>虜
- <EFBFBD>?<EFBFBD>躰秤憭<EFBFBD><EFBFBD>摰<EFBFBD><EFBFBD>: <20><><EFBFBD>匧<EFBFBD>撣詨㦤<E8A9A8>舫<EFBFBD><E888AB>匧<EFBFBD><E58CA7>?
<EFBFBD><EFBFBD><EFBFBD>臭漁<EFBFBD>?
- **<2A>嗉氜<E59789>䀹沲<E480B9>?*: Excel<65>函<EFBFBD><E587BD><EFBFBD><EFBFBD>憭<EFBFBD><E686AD>嚗峕<E59A97>銝湔𧒄<E6B994><F0A79284>辣
- <EFBFBD>厰<EFBFBD><EFBFBD>㰘蝸: 憸<><E686B8>100銵䕘<E98AB5>摰峕㟲<E5B395>唳旿<E594B3>厰<EFBFBD><E58EB0>瑕<EFBFBD>
- Session餈<EFBFBD><EFBFBD>: 10<31><30><EFBFBD><EFBFBD>芸𢆡餈<F0A286A1><E9A488>嚗<EFBFBD><E59A97>頝喳辣<E596B3>?
- <EFBFBD>躰秤摰寥<EFBFBD>: OSS<53>𣳇膄憭梯揖銝滚蔣<E6BB9A>䄂B皜<42><E79A9C>
- 摰峕㟲<EFBFBD>亙<EFBFBD>: <20><><EFBFBD>㗇<EFBFBD>雿𣈯<E99BBF><F0A388AF>厩<EFBFBD><E58EA9><EFBFBD><EFBFBD><EFBFBD>亙<EFBFBD>
撘<EFBFBD><EFBFBD>烐<EFBFBD><EFBFBD>?
- 霈∪<EFBFBD>撌交𧒄: 5.5撠𤩺𧒄
- 摰鮋<EFBFBD>撌交𧒄: ~5撠𤩺𧒄
- **隞餃𦛚摰峕<E691B0><E5B395>?*: 100% (6/6)
- 隞<EFBFBD><EFBFBD>韐券<EFBFBD>: 擃矋<E69383>摰峕㟲瘜券<E7989C>+瘚贝<E7989A>嚗?
- **瘚贝<E7989A><E8B49D>朞<EFBFBD><E69C9E>?*: 100% (7/7)
銝衤<EFBFBD>甇仿<EFBFBD><EFBFBD>?
- 摰䂿緵AI隞<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>滚𦛚嚗𡿨LMFactory嚗?
- 霈曇恣System Prompt嚗?0銝東ew-shot嚗?
- <EFBFBD><EFBFBD><EFBFBD>AI銝窰ython<EFBFBD>扯<EFBFBD>
- 蝡臬<EFBFBD>蝡臬<EFBFBD><EFBFBD>賣<EFBFBD>霂?
**撘<><E69298>𤏸<EFBFBD>?: AI Assistant
**摰⊥瓲<E28AA5>嗆<EFBFBD>?: <20>?敺<>鍂<EFBFBD>琿<EFBFBD><E790BF>?
**銝衤<E98A9D>甇?*: Day 3 - AI隞<49><E99A9E><EFBFBD><EFBFBD><EFBFBD><EFBFBD>滚𦛚