NashTech Blog

🇻🇳 Building an AI-Powered Vietnamese Handwriting Assessment Platform: A Complete Guide – PART 4-5

Table of Contents

🇻🇳 Building an AI-Powered Vietnamese Handwriting Assessment Platform: A Complete Guide – PART 4-5

🔧 Part 4: Model Integration & Scoring System Deep Dive

Understanding the HandwritingScorer Architecture

Before implementing the frontend, let’s examine how our Vietnamese handwriting model actually works in production. The HandwritingScorer class serves as the core engine for analysis:

# Core model architecture (from handwriting_analysis.py)
class HandwritingCNN(nn.Module):
    """CNN model for handwriting quality assessment - Updated for Vietnamese model"""

    def __init__(self, num_features=7, pretrained=True, dropout_rate=0.3):
        super(HandwritingCNN, self).__init__()

        # Use EfficientNet-B0 as backbone with pretrained ImageNet weights
        self.backbone = models.efficientnet_b0(weights=EfficientNet_B0_Weights.DEFAULT)

        # Vietnamese-optimized classifier architecture
        num_ftrs = self.backbone.classifier[1].in_features  # 1280 features
        self.backbone.classifier = nn.Sequential(
            nn.Dropout(dropout_rate),
            nn.Linear(num_ftrs, 512),      # First dense layer
            nn.ReLU(),
            nn.BatchNorm1d(512),
            nn.Dropout(dropout_rate),
            nn.Linear(512, 256),           # Second dense layer
            nn.ReLU(),
            nn.BatchNorm1d(256),
            nn.Dropout(dropout_rate),
            nn.Linear(256, 7),             # 7 Vietnamese metrics output
            nn.Sigmoid()                   # Output between 0-1
        )

Model Initialization and Loading Process

class HandwritingScorer:
    def __init__(self, model_path: str = None, device: str = "cpu"):
        """Initialize scorer with Vietnamese model configuration"""
        self.device = torch.device(device)
        self.model = HandwritingCNN(num_outputs=7)  # 7-metric Vietnamese model

        # Load calibration settings for Vietnamese scoring
        self._load_calibration_config()

        # Load trained weights or use random initialization
        if model_path and os.path.exists(model_path):
            checkpoint = torch.load(model_path, map_location=self.device)
            if isinstance(checkpoint, dict) and 'model_state_dict' in checkpoint:
                self.model.load_state_dict(checkpoint['model_state_dict'])
            else:
                self.model.load_state_dict(checkpoint)
            logger.info(f"✅ Loaded trained Vietnamese model: {model_path}")

        self.model.to(self.device)
        self.model.eval()

Image Processing and Analysis Pipeline

The analysis process follows these critical steps:

Step 1: Image Preprocessing and Tensor Conversion

def analyze_handwriting(self, image_array: np.ndarray) -> Dict[str, float]:
    """Main analysis pipeline for Vietnamese handwriting"""

    # Critical: Convert image format for PyTorch
    if len(image_array.shape) == 3:  # (H, W, C) -> (C, H, W)
        tensor = torch.from_numpy(image_array).permute(2, 0, 1).unsqueeze(0)
    elif len(image_array.shape) == 2:  # (H, W) grayscale -> (1, 1, H, W)
        tensor = torch.from_numpy(image_array).unsqueeze(0).unsqueeze(0)

    # Normalize to [0, 1] range expected by model
    tensor = tensor.to(self.device).float() / 255.0

    logger.info(f"🔍 Processing tensor shape: {tensor.shape}")

Step 2: Model Inference and Raw Scoring

    # Run Vietnamese handwriting analysis
    with torch.no_grad():
        raw_scores = self.model(tensor)          # Shape: [1, 7]
        raw_scores = raw_scores.squeeze().cpu().numpy()  # Shape: [7]

    logger.info(f"🔍 Raw model outputs (0-1): {raw_scores}")

    # Map to Vietnamese handwriting metrics
    vietnamese_metrics = {
        'legibility': float(raw_scores[0]),        # Diacritic clarity
        'consistency': float(raw_scores[1]),       # Character uniformity
        'alignment': float(raw_scores[2]),         # Text organization
        'spacing': float(raw_scores[3]),           # Vietnamese syllable spacing
        'size_uniformity': float(raw_scores[4]),   # Character size consistency
        'slant_consistency': float(raw_scores[5]), # Writing angle uniformity
        'pressure_consistency': float(raw_scores[6]) # Stroke weight consistency
    }

Step 3: Vietnamese Education Calibration

def _calibrate_score(self, raw_score: float) -> float:
    """Convert raw model output to Vietnamese educational scale"""

    config = self.calibration

    if raw_score >= config["excellent_threshold"]:
        # Excellent Vietnamese handwriting (75-100 points)
        excellent_min, excellent_max = config["excellent_range"]
        threshold_range = 1.0 - config["excellent_threshold"]
        score_range = excellent_max - excellent_min
        base_score = excellent_min + (raw_score - config["excellent_threshold"]) * (score_range / threshold_range)
        return base_score * config["boost_factor"]

    elif raw_score >= config["good_threshold"]:
        # Good Vietnamese handwriting (55-75 points)
        good_min, good_max = config["good_range"]
        # ... similar calculation for good range

    # ... other ranges for average and poor handwriting

Step 4: Vietnamese-Weighted Overall Score Calculation

    # Apply Vietnamese education-specific weights
    vietnamese_weights = {
        'legibility': 0.2,           # 20% - Most important for reading
        'consistency': 0.15,         # 15% - Character formation uniformity
        'alignment': 0.15,           # 15% - Text organization
        'spacing': 0.15,             # 15% - Vietnamese syllable spacing
        'size_uniformity': 0.1,      # 10% - Character size consistency
        'slant_consistency': 0.15,   # 15% - Writing angle uniformity
        'pressure_consistency': 0.1   # 10% - Stroke consistency
    }

    # Calculate weighted average for overall Vietnamese score
    overall_score = sum(calibrated_scores[key] * vietnamese_weights[key]
                       for key in vietnamese_weights.keys())

    # Round to whole numbers for educational clarity
    final_scores = {key: round(score) for key, score in calibrated_scores.items()}
    final_scores['overall'] = round(overall_score)

    return final_scores

Production API Integration Example

Here’s how the complete analysis flows in your FastAPI endpoint:

@router.post("/analyze", response_model=AnalysisResult)
async def analyze_handwriting(file: UploadFile, user_id: str, db: Session):
    """Complete Vietnamese handwriting analysis pipeline"""

    # 1. Save and validate uploaded image
    temp_filepath = save_uploaded_file(file)

    # 2. Preprocess image for Vietnamese model
    processed_image = image_processor.preprocess_image(temp_filepath)

    # 3. Run Vietnamese handwriting analysis
    scores = handwriting_scorer.analyze_handwriting(processed_image)

    # 4. Generate Vietnamese feedback
    feedback, suggestions = handwriting_scorer.generate_feedback(scores)

    # 5. Return comprehensive results
    return AnalysisResult(
        overall_score=scores['overall'],
        score_breakdown={
            "legibility": scores['legibility'],
            "consistency": scores['consistency'],
            "alignment": scores['alignment'],
            "spacing": scores['spacing'],
            "size_uniformity": scores['size_uniformity'],
            "slant_consistency": scores['slant_consistency'],
            "pressure_consistency": scores['pressure_consistency']
        },
        feedback=feedback,
        suggestions=suggestions,
        processing_time=processing_time
    )

This robust scoring system ensures reliable Vietnamese handwriting assessment while providing detailed insights for educational improvement. The calibration system adapts to different educational contexts, making it suitable for various Vietnamese school environments.


💻 Part 5: Frontend UI Implementation

Modern Vietnamese Educational Interface

Our Next.js frontend provides an intuitive experience for Vietnamese users:

Key Features:

  • Complete Vietnamese localization – All text in Vietnamese
  • Mobile-first design – Optimized for tablets and phones commonly used in Vietnamese schools
  • Real-time analysis – Immediate feedback for students
  • Progress tracking – Long-term improvement monitoring
  • Teacher dashboard – Class-wide performance analytics

Results Display with 7-Factor Breakdown

Dashboard for Progress Tracking

Upload UI

// Results Component showing Vietnamese analysis
function AnalysisResults({ analysis }: { analysis: AnalysisResult }) {
  const metrics = [
    {
      key: "legibility",
      label: "Độ rõ ràng",
      description: "Chữ viết có rõ ràng, dễ đọc không",
    },
    {
      key: "consistency",
      label: "Tính nhất quán",
      description: "Kích thước và hình dáng chữ có đồng đều không",
    },
    {
      key: "alignment",
      label: "Căn chỉnh",
      description: "Chữ viết có thẳng hàng không",
    },
    {
      key: "spacing",
      label: "Khoảng cách",
      description: "Khoảng cách giữa các chữ có phù hợp không",
    },
    {
      key: "size_uniformity",
      label: "Đồng đều kích thước",
      description: "Chiều cao các chữ có giống nhau không",
    },
    {
      key: "slant_consistency",
      label: "Độ nghiêng nhất quán",
      description: "Góc nghiêng chữ có đều nhau không",
    },
    {
      key: "pressure_consistency",
      label: "Lực bút đều",
      description: "Lực ấn bút có đều nhau không",
    },
  ];

Upload UI

Analysis result

Dashboard for Progress Tracking

Dashboard for Progress Tracking

🚀 Next Steps & Advanced Features

Contributing to Vietnamese Education Technology

This project demonstrates how AI can be localized and optimized for specific educational contexts. The combination of:

  • Cultural Understanding (Vietnamese writing characteristics)
  • Technical Excellence (state-of-the-art CNN architecture)
  • Educational Impact (measurable learning improvements)
  • Continuous Learning (model improves with every user)

Creates a sustainable platform that grows smarter over time while serving the unique needs of Vietnamese education.


📚 Conclusion

Building an AI-powered Vietnamese handwriting assessment platform requires more than just technical skills—it demands deep understanding of educational needs, cultural context, and sustainable improvement mechanisms.

This guide has walked you through:

Custom Model Training – From data collection to production-ready CNN

7-Factor Analysis – Comprehensive handwriting evaluation system

Vietnamese Optimization – Language-specific adaptations and improvements

Continuous Learning – Self-improving system through user data

Production UI – Complete web application with mobile optimization

Real-world Impact – Measurable improvements in Vietnamese classrooms

The result is not just a technical achievement, but an educational tool that empowers Vietnamese students, teachers, and parents with AI-driven insights into handwriting development.

Start building your Vietnamese handwriting assessment platform today, and contribute to the future of AI-powered education in Vietnam! 🇻🇳


For the complete source code and detailed implementation guides, visit: AI Handwriting Assessment Platform

Demo site: AI Handwriting Assessment Platform

📝 Note

Some code examples and technical content in this blog post were generated with the assistance of AI to provide comprehensive implementation details and best practices for Vietnamese handwriting assessment systems. The actual project implementation and educational insights are based on real-world development and testing.

Picture of Ngan Mai Thanh

Ngan Mai Thanh

Leave a Comment

Your email address will not be published. Required fields are marked *

Suggested Article

Scroll to Top