iT邦幫忙

2025 iThome 鐵人賽

DAY 4
0
生成式 AI

30 天生成式 AI 實戰挑戰:從基礎到應用系列 第 4

文字 → JSON(更嚴格的結構化輸出與驗證)

  • 分享至 

  • xImage
  •  

新增/修改的程式碼

  1. src/day4_text_to_json.js(新增)
// src/day4_text_to_json.js
import { openai } from "./aiClient.js";
import { PromptBuilder } from "./promptBuilder.js";
import { extractJson, validateBySchema } from "./jsonGuard.js";

/**
 * 新聞 → JSON 結構化摘要
 * Schema:
 * {
 *   "title": string,
 *   "summary": string,
 *   "keywords": string[],
 *   "category": string,   // politics | tech | health | finance | sports | other
 *   "date": string        // YYYY-MM-DD
 * }
 */
const schema = {
  type: "object",
  required: ["title", "summary", "keywords", "category", "date"],
  properties: {
    title: { type: "string" },
    summary: { type: "string" },
    keywords: { type: "object" }, // 注意會驗證是 array
    category: { type: "string" },
    date: { type: "string" }
  },
};

export async function newsToJson(articleText) {
  const pb = new PromptBuilder()
    .setRole("你是一個新聞編輯助手")
    .setGoal("將輸入的新聞文章轉換為結構化 JSON 摘要")
    .addConstraint("輸出必須是純 JSON,不要有多餘文字或 Markdown")
    .addConstraint("keywords 請為 3~5 個字詞陣列")
    .addConstraint("category 必須是 politics, tech, health, finance, sports, other 其中之一")
    .setJsonSchema(schema)
    .setUserInput(articleText);

  const res = await openai.chat.completions.create({
    model: "gpt-4o-mini",
    temperature: 0.2,
    messages: pb.toMessages(),
  });

  const raw = res.choices?.[0]?.message?.content ?? "";
  const obj = extractJson(raw);
  const check = validateBySchema(obj, schema);

  if (!check.ok) {
    throw new Error("JSON 不符合 schema:" + check.errors.join("; "));
  }

  return obj;
}
  1. index.js(更新)
// index.js
import { englishTeacher, codeReview, sentimentClassify } from "./src/day3_prompt_engineering.js";
import { newsToJson } from "./src/day4_text_to_json.js";

const args = Object.fromEntries(
  process.argv.slice(2).reduce((acc, cur, i, arr) => {
    if (cur.startsWith("--")) {
      const key = cur.replace(/^--/, "");
      const val = arr[i + 1] && !arr[i + 1].startsWith("--") ? arr[i + 1] : true;
      acc.push([key, val]);
    }
    return acc;
  }, [])
);

async function main() {
  const task = args.task || "teacher";

  if (task === "teacher") {
    const input = args.text || "He go to school every day.";
    const out = await englishTeacher(input);
    console.log("\n=== 英文老師 ===\n");
    console.log(out);

  } else if (task === "review") {
    const sample =
`function sum(arr){
  let s = 0;
  for (let i=0;i<arr.length;i++){
    s += arr[i]
  }
  return s
}`;
    const out = await codeReview(sample, "javascript");
    console.log("\n=== 程式碼審查 ===\n");
    console.log(out);

  } else if (task === "sentiment") {
    const text = args.text || "今天心情糟透了,事情一團亂。";
    const out = await sentimentClassify(text);
    console.log("\n=== 情緒分類(JSON) ===\n");
    console.log(out);

  } else if (task === "json_summary") {
    const article = args.text || `台北市今天宣布推出全新的智慧交通系統,
    透過 AI 與大數據分析來優化紅綠燈號誌,預計將能減少 20% 的交通壅塞。`;
    const out = await newsToJson(article);
    console.log("\n=== 新聞 JSON 摘要 ===\n");
    console.log(out);

  } else {
    console.log("未知任務,請使用 --task teacher | review | sentiment | json_summary");
  }
}

main().catch((e) => {
  console.error("發生錯誤:", e.message);
  process.exit(1);
});
  1. package.json(新增 Script)
{
  "scripts": {
    "day4:json": "node index.js --task json_summary --text \"OpenAI 公布新模型,將大幅提升效能與效率。\""
  }
}

如何執行

# 跑新聞 → JSON 摘要
npm run day4:json --silent

輸出結果(範例):

{
  "title": "台北市啟動智慧交通系統",
  "summary": "台北市政府宣布推出 AI 與大數據驅動的智慧交通系統,預計能有效減少交通壅塞 20%。",
  "keywords": ["智慧交通", "AI", "大數據", "紅綠燈優化"],
  "category": "tech",
  "date": "2025-09-04"
}

上一篇
Day 3:提示工程(Prompt Engineering)
下一篇
多輪對話(Chat History)
系列文
30 天生成式 AI 實戰挑戰:從基礎到應用5
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言