昨天使用兩個 HTTP Request 來做「AI摘要」與「任務提取」,但在後來的持續測試中發現 JSON 無法處理換行符號、引號等特殊字符的摘要內容,導致無法正常傳遞,今天會專注在解決這些問題上。
我也將錄音檔更換為會議的錄音demo了
在持續測試的過程中,我遇到了以下的錯誤訊息
{
"errorMessage": "JSON parameter needs to be valid JSON",
"errorDetails": "The model has crashed without additional information"
}
\n
、"
、**
等字符確認了問題根源在於 n8n HTTP Request 節點對動態 JSON 內容的處理限制。
刪除原有的「AI摘要」和「任務提取」節點
在 Webhook 節點後添加 Code 節點,選擇「Code in JavaScript」
將節點命名為「AI摘要與任務提取」
$http.request()
方法在 JavaScript 中運作更穩定const webhookData = $input.first().json.body;
const inputText = webhookData.text;
const instruction = webhookData.instruction || "請幫我整理出重點並提取任務";
console.log('開始處理 AI 摘要與任務提取...');
console.log('輸入文字長度:', inputText.length);
console.log('處理指令:', instruction);
// AI 摘要
async function generateSummary(text) {
const summaryPayload = {
model: "qwen2.5-taiwan-7b-instruct-i1",
messages: [
{
role: "user",
content: `請摘要以下內容,重點說明主要討論事項:${text}`
}
],
temperature: 0.5,
max_tokens: 300
};
try {
console.log('發送摘要請求到 LM Studio...');
const response = await this.helpers.httpRequest({
method: 'POST',
url: 'http://host.docker.internal:1234/v1/chat/completions',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(summaryPayload),
timeout: 120000
});
// 解析回應
const responseData = typeof response === 'string' ? JSON.parse(response) : response;
if (responseData.choices && responseData.choices[0] && responseData.choices[0].message) {
console.log('摘要生成成功');
return responseData.choices[0].message.content;
} else {
throw new Error('摘要API回應格式異常');
}
} catch (error) {
console.error('摘要生成失敗:', error.message);
return `摘要生成失敗:${error.message}`;
}
}
// 任務提取
async function extractTasks(summaryText) {
const taskPayload = {
model: "qwen2.5-taiwan-7b-instruct-i1",
messages: [
{
role: "user",
content: `請從以下摘要中提取所有行動項目和待辦事項,以條列式呈現,若無則說沒有指派任何行動:${summaryText}`
}
],
temperature: 0.5,
max_tokens: 300
};
try {
console.log('發送任務提取請求到 LM Studio...');
const response = await this.helpers.httpRequest({
method: 'POST',
url: 'http://host.docker.internal:1234/v1/chat/completions',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(taskPayload),
timeout: 120000
});
// 解析回應
const responseData = typeof response === 'string' ? JSON.parse(response) : response;
if (responseData.choices && responseData.choices[0] && responseData.choices[0].message) {
console.log('任務提取成功');
return responseData.choices[0].message.content;
} else {
throw new Error('任務提取API回應格式異常');
}
} catch (error) {
console.error('任務提取失敗:', error.message);
return `任務提取失敗:${error.message}`;
}
}
// 主要處理流程
try {
// 生成摘要
const summaryResult = await generateSummary(inputText);
// 基於摘要做任務提取
const tasksResult = await extractTasks(summaryResult);
// 回傳結果
const result = {
summary: summaryResult,
tasks: tasksResult,
processing_info: {
input_length: inputText.length,
summary_length: summaryResult.length,
tasks_length: tasksResult.length,
processed_at: new Date().toISOString(),
status: 'success'
}
};
console.log('AI 處理完成!');
console.log('摘要長度:', summaryResult.length);
console.log('任務長度:', tasksResult.length);
return [{ json: result }];
} catch (error) {
console.error('AI 處理過程發生錯誤:', error.message);
// 錯誤處理,回傳錯誤資訊
return [{
json: {
summary: `處理失敗:${error.message}`,
tasks: "無法提取任務",
processing_info: {
status: 'error',
error_message: error.message,
processed_at: new Date().toISOString()
}
}
}];
}
Code 節點成功處理了 JSON 特殊字符問題,不再出現格式錯誤,並加入了完整的錯誤處理機制。
在測試的過程中,我還發現的超時問題,於是我也調整了 LM Studio 和節點「AI摘要與任務提取」timeout 的設定
Context Length: 2048
GPU Offload: 0 -> 5
CPU Thread Pool Size: 4
Evaluation Batch Size: 256 -> 512
Offload KV Cache to GPU Memory: OFF
Keep Model in Memory: ON
LM Studio 處理速度大幅提升,解決了超時的問題。
將「Respond to Webhook」節點的 JSON 修改為
{
"status": {{ JSON.stringify($json.processing_info.status) }},
"summary": {{ JSON.stringify($json.summary) }},
"tasks": {{ JSON.stringify($json.tasks) }}
}
最終成功的輸出結果
{
"status": "success",
"summary": "今天會議的主要討論事項是專案進度。主要內容包括:\n\n1. **需求分析**:需要在週五前完成初步報告。\n2. **資料庫架構設計**:\n - John負責處理資料庫架構的設計文件,需在週三前準備出稿,包括ER圖和資料表規劃,並協助Mary進行系統測試的規劃。\n3. **前端介面設計**:\n - Mary負責完成前端介面的圓形設計,特別是使用者登入合宜標版的部分,需在週四前提供可互動的圓形供團隊檢視,並準備使用者體驗測試的問卷調查。\n4. **客戶會議準備**:需要準備展示材料,John負責技術架構簡報,Mary負責使用者介面展示。兩位要在週五下午3點前完成材料準備,以便進行最後的整合測試。\n\n所有成員需在週末前完成整合測試。如果還有其他問題,將留待下次會議討論。",
"tasks": "### 行動項目及待辦事項\n\n1. **需求分析**\n - 在週五前完成初步報告。\n\n2. **資料庫架構設計**\n - John:\n - 負責處理資料庫架構的設計文件。\n - 需在週三前準備出稿,包括ER圖和資料表規劃,並協助Mary進行系統測試的規劃。\n\n3. **前端介面設計**\n - Mary:\n - 完成前端介面的圓形設計,特別是使用者登入合宜標版的部分。\n - 在週四前提供可互動的圓形供團隊檢視,並準備使用者體驗測試的問卷調查。\n\n4. **客戶會議準備**\n - John:\n - 負責技術架構簡報。\n - 在週五下午3點前完成材料準備,以便進行最後的整合測試。\n - Mary:\n - 負責使用者介面展示。\n - 在週五下午3點前完成材料準備,以便進行最後的整合測試。\n\n5. **整合測試**\n - 所有成員需在週末前完成整合測試。"
}
建立測試程式 src/test_workflow_stability.py
,測試較為複雜的內容
import requests
import json
def test_complex_content():
# 測試包含特殊字符的複雜內容
test_data = {
"text": """會議重點:
1. "客戶需求"分析 - 需要更新
2. 系統架構\n包含多行說明
3. John說:"這很重要!"
4. 時程:2025/9/20前完成""",
"instruction": "請摘要並提取任務"
}
response = requests.post(
"http://localhost:5678/webhook/m2a-test",
json=test_data,
timeout=180
)
if response.status_code == 200:
result = response.json()
print("複雜內容測試成功")
print(f"摘要:{result['summary'][:100]}...")
print(f"任務:{result['tasks'][:100]}...")
else:
print(f"❌ 測試失敗:{response.status_code}")
if __name__ == "__main__":
test_complex_content()
成功摘要較為複雜的內容
✅ 複雜內容測試成功
摘要:會議主要內容包括:
1. **需求分析**:需要進行更新,以滿足當前客戶的需求。
2. **系統架構**:討論了系統的整體設計和架構,這是會議的重要部分。
3. John強調指出,某項議題或決策非常...
任務:- 需求分析需要進行更新。
- 系統架構的整體設計和架構需進一步討論。
- 某項議題或決策需特別注意,可能影響後續程序。
- 所有工作需在2025年9月20日前完成。
以上是會議中的主要行動項目...
✅ 完成項目
📝 關鍵發現
今天學會了如何診斷和解決系統整合的問題,從最初的 JSON 格式錯誤,到發現 HTTP Request 節點的限制到使用 Code 節點解決問題,整個實作的過程中讓我對 n8n 的架構有了更深入的了解。
我也在解決 JSON 問題的過程中,發現 Code 節點提供了比 HTTP Request 節點更強大的功能,可以進行複雜的資料處理、條件判斷、錯誤恢復等,這對我後續開發更複雜的功能時,提供了更大的彈性空間。
我也將大二選修的「預防醫學概論」裡所提到的「預防勝於治療」的概念,透過建立錯誤處理機制,使得系統的可靠性大幅提升。
🎯 明天計劃
建立 Notion 資料庫整合,讓摘要和任務能夠自動儲存到結構化的資料庫中。