우리의 테이블이 미래를 예측한다면?
I’m ready to translate the article for you, but I don’t have the full text of the post. Could you please paste the content you’d like translated (excluding the source line you already provided)? Once I have the text, I’ll keep the source link at the top and translate everything else into Korean while preserving the original formatting, markdown, and technical terms.
Predictive Student Grade Tracker
Using Syncfusion React Data Grid + Azure OpenAI
The Idea
최근 Syncfusion 웨비나에서 AI를 UI 컴포넌트에 직접 결합할 수 있다는 것을 배웠습니다.
학생의 향후 GPA를 수동으로 계산하는 대신, LLM이 대신 계산하도록 할 수 있습니다.
사용 사례:
교수는 각 학생의 1학년, 2학년, 3학년 GPA를 나열한 대시보드를 확인합니다.
“Calculate Grade” 버튼을 누르면 앱은 다음을 수행해야 합니다:
- 이전 3년 데이터를 기반으로 4학년(최종) GPA를 예측합니다.
- 총 GPA를 네 학년 모두의 평균으로 계산합니다.
- 아래 스케일을 사용해 총 GPA에서 총 등급을 도출합니다:
| GPA range | Grade |
|---|---|
| 0 – 2.5 | F |
| 2.6 – 2.9 | C |
| 3.0 – 3.4 | B |
| 3.5 – 3.9 | B+ |
| 4.0 – 4.4 | A |
| 4.5 – 5.0 | A+ |
LLM은 현재 그리드 데이터를 위 프롬프트와 함께 받아 JSON 페이로드를 반환하고, 그리드는 자동으로 업데이트됩니다.
전체 구현 (TypeScript)
import { loadCultureFiles } from '../common/culture-loader';
import { Grid, Toolbar, Page, QueryCellInfoEventArgs } from '@syncfusion/ej2-grids';
import { Button } from '@syncfusion/ej2-buttons';
import { predictiveData, predictive } from './data-source';
/* -------------------------------------------------
Predictive Data Entry
------------------------------------------------- */
loadCultureFiles();
Grid.Inject(Page, Toolbar);
const grid = new Grid({
dataSource: predictiveData,
toolbar: [{ template: `Calculate Grade` }],
queryCellInfo: customizeCell,
columns: [
{ field: 'StudentID', isPrimaryKey: true, headerText: 'Student ID', textAlign: 'Right', width: 100 },
{ field: 'StudentName', headerText: 'Student Name', width: 100 },
{ field: 'FirstYearGPA', headerText: 'First Year GPA', textAlign: 'Center', width: 100 },
{ field: 'SecondYearGPA', headerText: 'Second Year GPA', textAlign: 'Center', width: 100 },
{ field: 'ThirdYearGPA', headerText: 'Third Year GPA', textAlign: 'Center', width: 100 },
{ field: 'FinalYearGPA', headerText: 'Final Year GPA', visible: false, textAlign: 'Center', width: 100 },
{ field: 'TotalGPA', headerText: 'Total GPA', visible: false, textAlign: 'Center', width: 100 },
{ field: 'TotalGrade', headerText: 'Total Grade', visible: false, textAlign: 'Center', width: 100 }
],
enableHover: false,
created: onCreated
});
grid.appendTo('#Grid');
/* -------------------------------------------------
Grid lifecycle & UI handlers
------------------------------------------------- */
function onCreated(): void {
const button = document.getElementById('calculate_Grade') as HTMLButtonElement;
button.onclick = calculateGrade;
new Button({ isPrimary: true }, '#calculate_Grade');
}
function calculateGrade(): void {
grid.showSpinner();
executePrompt();
}
/* -------------------------------------------------
Helper utilities
------------------------------------------------- */
function delay(ms: number): Promise {
return new Promise(resolve => setTimeout(resolve, ms));
}
/* -------------------------------------------------
AI interaction
------------------------------------------------- */
function executePrompt(): void {
const prompt = `
Final year GPA column should be updated based on GPA of FirstYearGPA, SecondYearGPA and ThirdYearGPA columns.
Total GPA should update based on average of all years GPA.
Total Grade update based on total GPA.
Grading scale: 0‑2.5 = F, 2.6‑2.9 = C, 3.0‑3.4 = B, 3.5‑3.9 = B+, 4.0‑4.4 = A, 4.5‑5 = A+.
Average value decimal should not exceed 1 digit.
`.trim();
const gridReportJson = JSON.stringify(grid.dataSource);
const userInput = generatePrompt(gridReportJson, prompt);
// Azure OpenAI request (wrapper defined elsewhere)
const aiOutput = (window as any).getAzureChatAIRequest({
messages: [{ role: 'user', content: userInput }]
});
aiOutput.then((result: string) => {
// Strip possible markdown fences returned by the model
const cleanResult = result.replace(/```json/g, '').replace(/```/g, '').trim();
const generatedData: predictive[] = JSON.parse(cleanResult);
grid.hideSpinner();
if (generatedData.length) {
grid.showColumns(['Final Year GPA', 'Total GPA', 'Total Grade']);
updateRows(generatedData);
}
});
}
/* -------------------------------------------------
Grid row update
------------------------------------------------- */
async function updateRows(generatedData: predictive[]): Promise {
await delay(300);
for (const item of generatedData) {
grid.setRowData(item.StudentID, item);
await delay(300);
}
}
/* -------------------------------------------------
Cell styling
------------------------------------------------- */
function customizeCell(args: QueryCellInfoEventArgs): void {
const data = args.data as predictive;
if (args.column!.field === 'FinalYearGPA' || args.column
!.field === 'TotalGPA') {
if (data.FinalYearGPA! > 0 || data.TotalGPA! > 0) {
args.cell!.classList.add('e-PredictiveColumn');
}
}
if (args.column!.field === 'TotalGrade') {
if (data.TotalGPA! = 4.5) {
args.cell!.classList.add('e-activecolor');
} else if (data.TotalGPA! > 0) {
args.cell!.classList.add('e-PredictiveColumn');
}
}
}
/* -------------------------------------------------
Prompt generator
------------------------------------------------- */
function generatePrompt(data: string, userInput: string): string {
return `
Given the following datasource bound to the Grid table:
${data}
Return a new datasource based on the user query:
${userInput}
Output **only** valid JSON – no extra text or markdown.
`.trim();
}
작동 방식 – 단계별
- 그리드 생성 – Student ID, Name, 그리고 세 개의 과거 GPA에 대한 열이 정의됩니다.
- 툴바 버튼 –
created()가 Calculate Grade 버튼을 삽입하고 이를calculateGrade()에 연결합니다. - 사용자 클릭 –
calculateGrade()가 스피너를 표시하고executePrompt()를 호출합니다. - 프롬프트 구성 –
generatePrompt()가 현재 그리드 데이터(JSON)를 LLM을 위한 자연어 지시와 결합합니다. - Azure OpenAI 호출 –
getAzureChatAIRequest()가 프롬프트를 전송하고; 모델은 예측된 Final GPA, Total GPA, 그리고 Grade가 포함된 JSON 페이로드를 반환합니다. - 결과 처리 – JSON 문자열에서 마크다운 구분자를 제거하고 파싱한 뒤
updateRows()를 통해 그리드에 다시 입력합니다. - 스타일링 –
customizeCell()이 CSS 클래스를 추가하여 예측 셀을 돋보이게 합니다(예: 낙제 학점은 빨간색, 최고 학점은 초록색).
기억해야 할 사항
| Concern | Recommendation |
|---|---|
| 프롬프트 일관성 | 지시를 짧고 결정적으로 유지하고, 모호한 표현을 피하세요. |
| JSON 검증 | LLM 호출을 try/catch 로 감싸고, UI를 업데이트하기 전에 파싱된 객체를 검증하세요. |
| 요청 제한 | Azure OpenAI는 요청 할당량이 있습니다 – 필요에 따라 배치 업데이트하거나 버튼을 디바운스하세요. |
| 보안 | 클라이언트에 Azure OpenAI 키를 절대 노출하지 마세요; 래퍼(getAzureChatAIRequest)는 안전한 백엔드를 통해 프록시해야 합니다. |
| 성능 | delay(300) 호출은 UI에 부드러운 “타이핑” 느낌을 주지만, 프로덕션에서는 제거할 수 있습니다. |
최종 생각
Syncfusion Data Grid에 LLM을 직접 삽입함으로써 정적 테이블을 몇 줄의 코드만으로 예측 분석 컴포넌트로 바꿨습니다. 동일한 패턴은 실시간으로 표 형식 데이터를 풍부하게 만들어야 하는 모든 시나리오—판매 예측, 재고 감소, 위험 점수 등—에 재사용할 수 있습니다.
한 번 시도해 보고, 프롬프트를 도메인에 맞게 조정하면 맞춤형 ML 모델을 처음부터 구축하지 않아도 UI가 지능형으로 변하는 것을 확인할 수 있습니다! 🚀
요약
- 최종 출력은 동적 데이터이며, 4번째 열은 전적으로 AI에 의해 생성됩니다.
리소스
-
GitHub 저장소:
Syncfusion / smart‑ai‑samples (TypeScript)