iT邦幫忙

2026 iThome 鐵人賽

DAY 9
0

DAY 8 完成 Slash Command 後,今天開始加入 AI 公司要處理的專案資料。

我準備了五筆範例專案,並建立 /projects。指令會從 projects.json 讀取資料,再用只有執行者看得到的 Embed 顯示內容。讀檔、驗證與 Discord 排版則拆開處理,避免全部塞進 bot.py

今天完成的內容

  • 定義 ProjectRequirementChange
  • 建立 JsonProjectRepository
  • 使用 PROJECTS_FILE 設定資料位置
  • 建立 /projects 私密 Embed
  • 使用 Fake Repository 測試指令

專案資料格式

Agent 後續會依照同一份資料討論,所以除了專案名稱,還要保存需求、預算、期限及驗收條件。

欄位 用途
idcategorytitle 專案編號、類別與名稱
requirements 一筆或多筆需求
budgetdeadline 預算與期限
acceptance_criteria 驗收條件
requirement_changes 後續需求變更

專案與需求變更都使用不可修改的 dataclass

@dataclass(frozen=True)
class RequirementChange:
    id: str
    project_id: str
    description: str
    reason: str
    requested_at: date
    status: str

@dataclass(frozen=True)
class Project:
    id: str
    category: str
    title: str
    requirements: tuple[str, ...]
    budget: int
    deadline: date
    acceptance_criteria: tuple[str, ...]
    requirement_changes: tuple[RequirementChange, ...] = ()

frozen=True 可避免程式直接改掉原始資料。客戶提出新要求時,會新增一筆 RequirementChange,保留變更原因與時間。

從 JSON 轉成 Project

projects.json 最外層使用 projects 陣列。以下是簡化後的單筆資料:

{
  "projects": [
    {
      "id": "PRJ-001",
      "category": "企業網站",
      "title": "咖啡店品牌官網",
      "requirements": ["製作響應式品牌首頁", "加入聯絡表單"],
      "budget": 80000,
      "deadline": "2026-10-15",
      "acceptance_criteria": ["手機與桌面版皆可正常瀏覽"],
      "requirement_changes": []
    }
  ]
}

Project.from_dict() 會檢查必填文字、陣列、預算及日期格式,也會確認需求變更的 project_id 與專案一致。資料不正確時拋出 ProjectDataError,不讓錯誤內容繼續傳到 Discord。

為什麼加入 Repository?

如果 /projects 自己開啟 JSON,它就要同時負責讀檔、解析、驗證與顯示。加入 Repository 後,指令只需要取得整理好的 Project

/projects
    ↓
ProjectRepository
    ↓
JsonProjectRepository
    ↓
projects.json

目前介面只有同步的 list_projects()

class ProjectRepository(Protocol):
    def list_projects(self) -> list[Project]:
        ...

JsonProjectRepository 負責讀取 UTF-8 檔案、解析 JSON,再逐筆呼叫 Project.from_dict()。找不到檔案或 JSON 格式錯誤時,會統一轉成 ProjectRepositoryError

資料路徑放在環境設定:

PROJECTS_FILE=projects.json

未來移動資料檔時,只要調整設定,不必修改 Repository。

建立 /projects 指令

指令先向 Repository 取得專案,再建立 Embed:

projects = project_repository.list_projects()

embed = discord.Embed(
    title="📁 專案清單",
    description=f"目前共有 {len(projects)} 個專案。",
    color=discord.Color.blue(),
)

for project in projects:
    embed.add_field(
        name=f"{project.id}|{project.title}",
        value=format_project(project),
        inline=False,
    )

await interaction.response.send_message(
    embed=embed,
    ephemeral=True,
)

ephemeral=True 表示只有執行指令的人能看見。若 Repository 發生錯誤,Discord 只顯示簡短訊息,詳細原因留在日誌。

https://ithelp.ithome.com.tw/upload/images/20260923/20183880aUX6g7rEcB.png

今天完成到哪裡?

專案資料已拆成 Model、Repository 與 Discord 顯示三個部分。五筆範例可以轉成 Project/projects 也有 Fake Repository 測試保護。

當時還沒確認指令是否出現在 Discord 選單。下一篇會加入 /start,讓使用者用專案 ID 啟動流程。


上一篇
DAY 8|建立第一個 Slash Command
系列文
AI 公司模擬器:Discord x Multi-Agent 架構實作9
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言