AIoT κΈ°λ° μ§λ₯ν μλμ§ κ΄λ¦¬ μμ€ν μ ν΄λΌμ΄μΈνΈμ λλ€.
LLMκ³Ό MCP(Model Context Protocol)λ₯Ό κ²°ν©νμ¬ μμ°μ΄ κΈ°λ° μλμ§ κ΄λ¦¬ μΈν°νμ΄μ€λ₯Ό ꡬννμ΅λλ€. μ¬μ©μλ λνλ₯Ό ν΅ν΄ μ λ ₯ λ°μ΄ν° μ‘°ν, TimesFM κΈ°λ° μκ³μ΄ μμΈ‘, IoT κΈ°κΈ° μ μ΄λ₯Ό μνν μ μμ΅λλ€. SSE(Server-Sent Events) μ€νΈλ¦¬λ°μΌλ‘ μ€μκ° μλ΅μ μ 곡νλ©°, λΆμμ κΈ°λ° μμΈ‘μΌλ‘ λΆνμ€μ± ꡬκ°κΉμ§ μκ°ννμ¬ λ°μ΄ν° κΈ°λ° μμ¬κ²°μ μ μ§μν©λλ€.
π 2025 Advantech AIoT Innoworks Project μ°μμ (3λ±)
- Framework: Next.js 15 (App Router)
- Language: TypeScript 5.9
- Styling: Tailwind CSS 4
- API Communication: SSE (Server-Sent Events)
- Node.js >= 18.18.0
npm install
npm run dev # κ°λ° μλ² (http://localhost:3000)
npm run build # νλ‘λμ
λΉλ
npm run lint # ESLint κ²μ¬# .env.local
NEXT_PUBLIC_API_URL=<λ°±μλ API μ£Όμ>app/
βββ _api/ # API ν΅μ λ μ΄μ΄ (μ¬μλ, νμμμ, μλ¬ μ²λ¦¬)
βββ _lib/ # λΉμ¦λμ€ λ‘μ§
βββ _hooks/ # 컀μ€ν
React Hooks
βββ _components/ # UI μ»΄ν¬λνΈ
βββ chat/[id]/ # λμ μ±ν
λ°© νμ΄μ§
βββ types.ts # TypeScript νμ
μ μ
μ€μκ° μλ΅μ μν Server-Sent Events ꡬν:
const response = await createChatRoom(question, {
onAnswerChunk: ({ chunk, accumulated }) => {
setStreamingAnswer(accumulated);
},
});κ΄μ¬μ¬ λΆλ¦¬ μμΉμ λ°λΌ _api/ λλ ν 리μμ ν΅μ λ‘μ§μ λΆλ¦¬:
- μ§μ λ°±μ€ν κΈ°λ° μλ μ¬μλ
- AbortControllerλ₯Ό νμ©ν νμμμ μ²λ¦¬
- 컀μ€ν
μλ¬ ν΄λμ€(
ChatApiError)λ₯Ό ν΅ν μλ¬ μ κ·ν
UI λ‘μ§κ³Ό λΉμ¦λμ€ λ‘μ§μ λΆλ¦¬νμ¬ μ¬μ¬μ©μ±κ³Ό ν μ€νΈ μ©μ΄μ± ν보:
useChatMessaging: λ©μμ§ μ μ‘/μμ λ° μ€νΈλ¦¬λ° μν κ΄λ¦¬useChatRoomList: μ±ν λ°© λͺ©λ‘ μ‘°ν λ° λ¬΄ν μ€ν¬λ‘€useAutoScroll: μ€νΈλ¦¬λ° μλ΅ μ μλ μ€ν¬λ‘€ (μ¬μ©μ μ€ν¬λ‘€ μ λΉνμ±ν)
BigInt IDμ μ λ°λ μμ€ λ°©μ§λ₯Ό μν λ¬Έμμ΄ μ κ·ν:
function normalizeIdValue(value: unknown): string {
if (typeof value === 'bigint') return value.toString();
if (typeof value === 'string') {
try { return BigInt(value).toString(); }
catch { return value; }
}
return String(value);
}- ESLint:
next/core-web-vitals,next/typescriptκ·μΉ μ μ© - TypeScript: strict λͺ¨λ