ai
Stencil.js กับ Machine Learning Pipeline —
Stencil.js สำหรับ ML Dashboard

Stencil.js เป็น Compiler สร้าง Web Components ใช้ได้ทุก Framework TypeScript JSX Native Web Components ขนาดเล็ก Performance สูง
เนื้อหาเกี่ยวข้อง — บทความที่เกี่ยวข้อง: LLM Fine-tuning LoRA MLOps Workflow —
ML Pipeline Dashboard ต้องการ Components แสดง Model Metrics, Training Progress, Prediction Results ใช้ Stencil.js สร้าง Reusable Components
เนื้อหาเกี่ยวข้อง — ทำความเข้าใจ Prometheus PromQL Scaling Strategy วิธี Scale — คู่มือฉบับสมบูรณ์ 2026
Stencil.js Component Development
// === Stencil.js ML Dashboard Components ===
// npm init stencil
// เลือก component
// 1. ML Metric Card Component
// src/components/ml-metric-card/ml-metric-card.tsx
import { Component, Prop, h, State, Watch } from '@stencil/core';
@Component({
tag: 'ml-metric-card',
styleUrl: 'ml-metric-card.css',
shadow: true,
})
export class MlMetricCard {
@Prop() metricName: string = '';
@Prop() metricValue: number = 0;
@Prop() unit: string = '';
@Prop() trend: 'up' | 'down' | 'stable' = 'stable';
@Prop() threshold: number = 0;
@State() isAlert: boolean = false;
@Watch('metricValue')
handleValueChange(newValue: number) {
this.isAlert = this.threshold > 0 && newValue < this.threshold;
}
componentWillLoad() {
this.handleValueChange(this.metricValue);
}
private getTrendIcon(): string {
switch (this.trend) {
case 'up': return '▲';
case 'down': return '▼';
default: return '●';
}
}
private getTrendColor(): string {
switch (this.trend) {
case 'up': return '#22c55e';
case 'down': return '#ef4444';
default: return '#6b7280';
}
}
render() {
return (
{this.metricName}
{this.metricValue.toFixed(4)}
{this.unit}
{this.getTrendIcon()} {this.trend}
);
}
}
// 2. Training Progress Component
// src/components/ml-training-progress/ml-training-progress.tsx
@Component({
tag: 'ml-training-progress',
styleUrl: 'ml-training-progress.css',
shadow: true,
})
export class MlTrainingProgress {
@Prop() currentEpoch: number = 0;
@Prop() totalEpochs: number = 100;
@Prop() loss: number = 0;
@Prop() accuracy: number = 0;
@Prop() status: 'training' | 'completed' | 'failed' = 'training';
private getProgressPercent(): number {
return (this.currentEpoch / this.totalEpochs) * 100;
}
render() {
const percent = this.getProgressPercent();
return (
Training Progress
{this.status}
Epoch: {this.currentEpoch}/{this.totalEpochs}
Loss: {this.loss.toFixed(4)}
Accuracy: {(this.accuracy * 100).toFixed(1)}%
);
}
}
// 3. Prediction Result Component
@Component({
tag: 'ml-prediction',
shadow: true,
})
export class MlPrediction {
@Prop() predictions: string = '[]'; // JSON string
@State() parsedPredictions: Array<{label: string, confidence: number}> = [];
componentWillLoad() {
try {
this.parsedPredictions = JSON.parse(this.predictions);
} catch (e) {
this.parsedPredictions = [];
}
}
render() {
return (
Predictions
{this.parsedPredictions.map(pred => (
{pred.label}
{(pred.confidence * 100).toFixed(1)}%
))}
);
}
}
console.log("Stencil.js ML Components:");
console.log(" ml-metric-card: แสดง Metric พร้อม Trend");
console.log(" ml-training-progress: Training Progress Bar");
console.log(" ml-prediction: Prediction Results");
ML Model Integration

# ml_api_server.py — FastAPI ML Model Server
# pip install fastapi uvicorn scikit-learn numpy
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from typing import List, Dict, Optional
from datetime import datetime
import numpy as np
app = FastAPI(title="ML Pipeline API")
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
)
# Models
class PredictionRequest(BaseModel):
features: List[float]
model_name: str = "default"
class PredictionResponse(BaseModel):
predictions: List[Dict[str, float]]
model_name: str
latency_ms: float
class TrainingStatus(BaseModel):
model_name: str
current_epoch: int
total_epochs: int
loss: float
accuracy: float
status: str # training, completed, failed
class ModelMetrics(BaseModel):
model_name: str
accuracy: float
precision: float
recall: float
f1_score: float
latency_p50_ms: float
latency_p99_ms: float
predictions_today: int
# In-memory state
training_status = TrainingStatus(
model_name="image-classifier-v2",
current_epoch=75, total_epochs=100,
loss=0.0823, accuracy=0.9456,
status="training",
)
@app.get("/api/metrics", response_model=ModelMetrics)
async def get_metrics():
"""Get Model Metrics สำหรับ Dashboard"""
return ModelMetrics(
model_name="image-classifier-v2",
accuracy=0.9456,
precision=0.9312,
recall=0.9589,
f1_score=0.9449,
latency_p50_ms=12.5,
latency_p99_ms=45.2,
predictions_today=15234,
)
@app.get("/api/training/status", response_model=TrainingStatus)
async def get_training_status():
"""Get Training Status"""
return training_status
@app.post("/api/predict", response_model=PredictionResponse)
async def predict(request: PredictionRequest):
"""Run Prediction"""
start = datetime.now()
# Simulated prediction
np.random.seed(42)
labels = ["cat", "dog", "bird", "fish"]
confidences = np.random.dirichlet(np.ones(len(labels)))
predictions = [
{"label": label, "confidence": float(conf)}
for label, conf in sorted(
zip(labels, confidences),
key=lambda x: x[1], reverse=True
)
]
latency = (datetime.now() - start).total_seconds() * 1000
return PredictionResponse(
predictions=predictions,
model_name=request.model_name,
latency_ms=latency,
)
@app.get("/api/pipeline/status")
async def pipeline_status():
"""Pipeline Status Overview"""
return {
"stages": [
{"name": "Data Ingestion", "status": "completed", "records": 50000},
{"name": "Feature Engineering", "status": "completed", "features": 128},
{"name": "Model Training", "status": "running", "epoch": 75},
{"name": "Evaluation", "status": "pending"},
{"name": "Deployment", "status": "pending"},
],
"last_updated": datetime.now().isoformat(),
}
# uvicorn ml_api_server:app --host 0.0.0.0 --port 8000
print("ML API Server:")
print(" GET /api/metrics - Model Metrics")
print(" GET /api/training/status - Training Status")
print(" POST /api/predict - Run Prediction")
print(" GET /api/pipeline/status - Pipeline Overview")
Dashboard Integration
-->
// Stencil.js Build Commands
// npm run build — Production build
// npm run generate — Generate new component
// npm run test — Run tests
// npm run test.watch — Watch mode
// stencil.config.ts
// import { Config } from '@stencil/core';
// export const config: Config = {
// namespace: 'ml-components',
// outputTargets: [
// { type: 'dist', esmLoaderPath: '../loader' },
// { type: 'dist-custom-elements' },
// { type: 'www', serviceWorker: null },
// ],
// };
console.log("Dashboard Integration:");
console.log(" Components: ml-metric-card, ml-training-progress, ml-prediction");
console.log(" API: FastAPI ML Server");
console.log(" Update: Auto-refresh every 5s");
Best Practices
- Shadow DOM: ใช้ Shadow DOM แยก CSS ป้องกัน Style Leaking
- Props: ใช้ Primitive Types สำหรับ Props (string, number, boolean)
- Lazy Loading: ใช้ Stencil Lazy Loading โหลด Components ที่ต้องใช้
- API Integration: ใช้ REST API เชื่อมกับ ML Model Server
- Real-time: ใช้ WebSocket สำหรับ Real-time Updates
- Testing: เขียน Unit Tests สำหรับ Components ด้วย Jest
Stencil.js คืออะไร
Compiler สร้าง Web Components ใช้ได้ทุก Framework React Angular Vue Ionic TypeScript JSX Native Web Components ขนาดเล็ก Performance สูง
แนะนำเพิ่มเติม — ติดตาม XM Signal
เนื้อหาเกี่ยวข้อง — อ่านต่อ: Embedding Model Remote Work Setup





