AI 어시스턴트
사용자가 말로 그리드에 요청합니다. 서버가 AI 모델에게 묻고, 검사를 거친 정렬·필터·그룹·서식·계산 컬럼·차트 동작으로 답하며, 답마다 되돌릴 수 있습니다.
실행 예제AI 어시스턴트
말로 요청하면 서버가 정렬·필터·그룹·서식·차트로 바꿔 줍니다. 모든 답은 되돌릴 수 있습니다.
이 데모의 코드
import { createGrid, type Row } from '@freegridjs/core';
import { button, separator, text, tr, type DemoContext } from '../ui';
import '../data'; // registers the grid's language packs
export default function mount(ctx: DemoContext) {
const { lang } = ctx;
const h = (en: string, ko: string) => tr(lang, { en, ko });
const regions = lang === 'ko' ? ['서울', '부산', '대구', '광주'] : ['East', 'West', 'North', 'South'];
const products = lang === 'ko' ? ['노트북', '모니터', '키보드', '마우스', '책상'] : ['Laptop', 'Monitor', 'Keyboard', 'Mouse', 'Desk'];
const prices = [1290, 320, 59, 25, 410];
const data: Row[] = Array.from({ length: 120 }, (_, i) => {
const p = (i * 7) % 5;
return {
id: i + 1,
date: `2026-${String(1 + (i % 12)).padStart(2, '0')}-${String(1 + ((i * 3) % 28)).padStart(2, '0')}`,
region: regions[i % 4],
product: products[p],
qty: 1 + ((i * 13) % 17),
price: prices[p],
};
});
const suggestions = lang === 'ko'
? ['지역별로 묶어 줘', '수량 10 이상 강조', '수량 상위 5개', '금액 컬럼 추가', '지역별 차트', '초기화']
: ['Group by region', 'Highlight qty above 10', 'Top 5 by qty', 'Add an amount column', 'Chart by region', 'Reset'];
const grid = createGrid(ctx.host, {
columns: [
{ field: 'date', header: h('Date', '날짜'), type: 'date', width: 110 },
{ field: 'region', header: h('Region', '지역'), width: 100 },
{ field: 'product', header: h('Product', '제품'), width: 120 },
{ field: 'qty', header: h('Qty', '수량'), type: 'number', width: 80 },
{ field: 'price', header: h('Price', '단가'), type: 'number', format: '#,##0', width: 100 },
],
data, locale: lang, getRowId: r => String(r.id),
// this demo's endpoint reads a few phrases; a real one asks a model (see "Server examples")
assistant: { url: '/api/demo-assistant', sampleRows: 3, suggestions },
});
grid.on('assistantAnswer', e => ctx.log(`assistantAnswer → ${e.applied.map(a => a.type).join(', ') || '-'}${e.skipped.length ? ` (${h('skipped', '건너뜀')} ${e.skipped.length})` : ''}`));
text(ctx, h('Open the assistant and ask in plain words. This demo server only knows a few phrases; your server asks a model and understands anything. Each answer has an Undo.',
'어시스턴트를 열고 말로 요청해 보세요. 이 데모 서버는 몇 가지 표현만 알아듣지만, 실제 서버는 모델에게 물어 어떤 요청이든 처리합니다. 답마다 되돌리기가 있습니다.'));
separator(ctx);
button(ctx, h('Open AI assistant', 'AI 어시스턴트 열기'), () => grid.openAssistant());
button(ctx, h('Ask: group by region', '요청: 지역별로 묶기'), async () => {
const res = await grid.askAssistant(suggestions[0]);
ctx.log(res.message);
});
return grid;
}AI 어시스턴트를 켜면 사용자가 "서울만 보여 주고 금액순으로 정렬해 줘", "지연된 주문을 빨갛게", "지역별 합계 차트"처럼 말로 요청할 수 있습니다. 그리드는 요청을 우리 서버로 보내고, 서버가 AI 모델(Claude 등)에게 물어 정렬·필터·그룹·피벗·조건부 서식·계산 컬럼·요약·차트 같은 동작 목록으로 답합니다. 모델 API 키는 서버에만 있고 브라우저에는 노출되지 않습니다.
설정
const grid = createGrid(el, {
columns, data,
assistant: {
url: '/api/grid-ai', // 우리 서버의 주소 (모델 API 키는 서버에만)
sampleRows: 5, // 예시로 보낼 행 수, 0이면 행은 보내지 않음
suggestions: ['지역별 매출', '지연 주문 강조', '금액 컬럼 추가'],
context: () => ({ screen: '주문 관리' }),
},
});
grid.openAssistant(); // 대화 창 (우클릭 메뉴에도 있음)
const res = await grid.askAssistant('이번 달 매출 상위 10개 거래처'); // 창 없이 코드로
console.log(res.message, res.applied, res.skipped);
res.undo(); // 그리드를 원래대로무엇이 서버로 가나요
행 데이터 전체가 아니라 컬럼 요약(종류, 빈 값 수, 고유 값 수, 최솟값·최댓값·평균, 자주 나오는 값)과 현재 화면 상태, 그리고 sampleRows만큼의 예시 행만 보냅니다. 개인정보가 있는 화면이라면 sampleRows: 0으로 행을 하나도 보내지 않을 수 있습니다.
// 그리드가 보내는 요청 (POST JSON)
{
"prompt": "서울만 보여 주고 금액순 정렬",
"locale": "ko",
"rowCount": 1200, "totalRows": 1200,
"columns": [
{ "id": "region", "header": "지역", "distinct": 4, "top": [{ "value": "서울", "count": 410 }] },
{ "id": "amount", "header": "금액", "type": "number", "min": 1200, "max": 980000, "avg": 41250 }
],
"sample": [ { "region": "서울", "amount": 32000 } ],
"state": { "sort": [], "filters": {}, "groupBy": [], "conditionalFormats": [] }
}
// 서버의 답
{
"message": "서울 주문만 남기고 금액이 큰 순서로 정렬했습니다.",
"actions": [
{ "type": "filter", "colId": "region", "model": { "type": "set", "values": ["서울"] } },
{ "type": "sort", "sort": [{ "colId": "amount", "dir": "desc" }] }
]
}동작과 안전장치
그리드는 서버가 보낸 동작을 실행하기 전에 하나씩 검사합니다. 없는 컬럼, 잘못된 필터 모델, 해석되지 않는 수식, 모르는 동작은 실행하지 않고 skipped로 알려 줍니다. 코드를 실행하는 동작은 없습니다. 답마다 되돌리기가 있어 정렬·필터·컬럼·서식을 요청 전으로 돌릴 수 있습니다.
| 이름 | 타입 | 설명 |
|---|---|---|
sort / filter / clearFilters / quickFilter / advancedFilter | { type, sort } / { type, colId, model } | 정렬과 필터. setSort·setFilter와 같은 모델을 씁니다. |
groupBy / pivot | { type, colIds, expand? } / { type, pivot } | 행을 묶거나 피벗 테이블로 바꿉니다. |
showColumns / hideColumns | { type, colIds } | 컬럼을 보이거나 숨깁니다. |
conditionalFormat / clearConditionalFormats | { type, format } | 조건부 서식을 추가합니다. |
addColumn | { type, column: { id, header, formula, type } } | 계산 컬럼을 추가합니다. 수식이 올바라야 합니다. |
summary / chart / message | { type, summary } / { type, chartType, colIds } / { type, text } | 요약 행, 컬럼으로 그린 차트, 또는 답만 보여 줍니다. |
서버 만들기
Node(Express)와 Python(FastAPI) 예제를 저장소의 examples/ai-assistant에 두었습니다. 둘 다 같은 프롬프트로 모델의 도구 호출(tool use)을 써서 위 형식의 답을 받습니다. 운영에서는 로그인 확인과 요청 횟수 제한을 꼭 거세요.
// Node (Express) + Claude: examples/ai-assistant/node/assistant.js 전체 예제 참고
import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic(); // ANTHROPIC_API_KEY 환경 변수
app.post('/api/grid-ai', requireLogin, async (req, res) => {
const out = await client.messages.create({
model: 'claude-sonnet-5-5',
max_tokens: 2048,
system: SYSTEM_PROMPT, // 동작 목록과 규칙
tools: [GRID_ACTIONS_TOOL],
tool_choice: { type: 'tool', name: 'grid_actions' },
messages: [{ role: 'user', content: JSON.stringify(req.body) }],
});
const input = out.content.find(b => b.type === 'tool_use')?.input ?? {};
res.json({ message: input.message ?? '', actions: input.actions ?? [] });
});위 데모의 서버는 비용 없이 체험할 수 있도록 정해진 몇 가지 표현만 알아듣는 규칙 기반 서버입니다. 실제 서버는 모델에게 물어보므로 자유로운 요청을 이해합니다.
이 페이지에 대한 질문
사용자가 그리드에 말로 요청할 수 있나요?
네. assistant 옵션을 켜면 그리드가 요청과 컬럼 요약을 우리 서버로 보내고, 서버가 AI 모델에게 물어 정렬·필터·그룹·서식·차트 같은 동작으로 답합니다. 그리드는 동작을 검사한 뒤 적용합니다.
AI 어시스턴트가 데이터를 모델에 보내나요?
서버가 전달하는 만큼만 갑니다. 그리드는 컬럼 요약과 예시 행 몇 개(sampleRows, 0이면 없음)만 보내고, 모델 API 키는 서버에만 있습니다.