Real-Time Language Proficiency Evaluator for Language Learning Applications Swift

👤 Sharing: AI
```swift
import Foundation

// MARK: - Structs & Enums

/// Represents the evaluation criteria for each skill.  Adapt weights as needed.
struct SkillWeight {
    let grammar: Double
    let vocabulary: Double
    let fluency: Double
    let pronunciation: Double
    let comprehension: Double
}

/// Represents a language skill (e.g., speaking, writing, listening).
enum LanguageSkill {
    case speaking
    case writing
    case listening
}

/// Represents a language proficiency level.  Extend as needed.
enum ProficiencyLevel: Comparable {
    case beginner
    case elementary
    case intermediate
    case upperIntermediate
    case advanced
    case proficient

    var numericValue: Int {
        switch self {
        case .beginner: return 1
        case .elementary: return 2
        case .intermediate: return 3
        case .upperIntermediate: return 4
        case .advanced: return 5
        case .proficient: return 6
        }
    }

    static func < (lhs: ProficiencyLevel, rhs: ProficiencyLevel) -> Bool {
        return lhs.numericValue < rhs.numericValue
    }
}


// MARK: - Class Definition

class LanguageProficiencyEvaluator {

    // Customizable Skill Weights - Adjust to prioritize different aspects.
    private let speakingWeights = SkillWeight(grammar: 0.2, vocabulary: 0.3, fluency: 0.3, pronunciation: 0.2, comprehension: 0.0) // Comprehension less relevant for speaking output
    private let writingWeights = SkillWeight(grammar: 0.4, vocabulary: 0.3, fluency: 0.2, pronunciation: 0.0, comprehension: 0.1) // Pronunciation not relevant for writing. Comprehension related to clarity.
    private let listeningWeights = SkillWeight(grammar: 0.05, vocabulary: 0.2, fluency: 0.15, pronunciation: 0.3, comprehension: 0.3) // Grammar less important. Focus on Pronunciation & Comprehension.

    // Internal tracking (optional, for debugging/analysis)
    private var skillScores: [LanguageSkill: (grammar: Double, vocabulary: Double, fluency: Double, pronunciation: Double, comprehension: Double)] = [:]

    // MARK: - Evaluation Functions

    /// Evaluates speaking proficiency based on provided scores.
    /// - Parameters:
    ///   - grammarScore:  A score (0.0 - 1.0) representing grammatical accuracy.
    ///   - vocabularyScore: A score (0.0 - 1.0) representing vocabulary range and appropriateness.
    ///   - fluencyScore: A score (0.0 - 1.0) representing the smoothness and naturalness of speech.
    ///   - pronunciationScore: A score (0.0 - 1.0) representing the clarity and accuracy of pronunciation.
    ///   - comprehensionScore: A score (0.0 - 1.0) representing how well they understand spoken language.
    /// - Returns: The determined proficiency level.
    func evaluateSpeaking(grammarScore: Double, vocabularyScore: Double, fluencyScore: Double, pronunciationScore: Double, comprehensionScore: Double) -> ProficiencyLevel {
        let weightedScore = (grammarScore * speakingWeights.grammar) +
                            (vocabularyScore * speakingWeights.vocabulary) +
                            (fluencyScore * speakingWeights.fluency) +
                            (pronunciationScore * speakingWeights.pronunciation) +
                            (comprehensionScore * speakingWeights.comprehension)

        skillScores[.speaking] = (grammar: grammarScore, vocabulary: vocabularyScore, fluency: fluencyScore, pronunciation: pronunciationScore, comprehension: comprehensionScore) // store scores
        return determineProficiencyLevel(from: weightedScore)
    }


    /// Evaluates writing proficiency based on provided scores.
    /// - Parameters:
    ///   - grammarScore:  A score (0.0 - 1.0) representing grammatical accuracy.
    ///   - vocabularyScore: A score (0.0 - 1.0) representing vocabulary range and appropriateness.
    ///   - fluencyScore: A score (0.0 - 1.0) representing the smoothness and naturalness of writing.
    ///   - comprehensionScore: A score (0.0 - 1.0) representing how easy the written text is to understand.
    /// - Returns: The determined proficiency level.
    func evaluateWriting(grammarScore: Double, vocabularyScore: Double, fluencyScore: Double, comprehensionScore: Double, fluencyScore: Double) -> ProficiencyLevel {
        let weightedScore = (grammarScore * writingWeights.grammar) +
                            (vocabularyScore * writingWeights.vocabulary) +
                            (fluencyScore * writingWeights.fluency) +
                            (comprehensionScore * writingWeights.comprehension)

        skillScores[.writing] = (grammar: grammarScore, vocabulary: vocabularyScore, fluency: fluencyScore, pronunciation: 0.0, comprehension: comprehensionScore) // store scores
        return determineProficiencyLevel(from: weightedScore)
    }


    /// Evaluates listening proficiency based on provided scores.
    /// - Parameters:
    ///   - grammarScore:  A score (0.0 - 1.0) representing grammatical awareness (though less emphasized).
    ///   - vocabularyScore: A score (0.0 - 1.0) representing vocabulary recognition.
    ///   - fluencyScore: A score (0.0 - 1.0) representing the ability to follow natural speech.
    ///   - pronunciationScore: A score (0.0 - 1.0) representing the ability to discern different sounds.
    ///   - comprehensionScore: A score (0.0 - 1.0) representing overall understanding.
    /// - Returns: The determined proficiency level.
    func evaluateListening(grammarScore: Double, vocabularyScore: Double, fluencyScore: Double, pronunciationScore: Double, comprehensionScore: Double) -> ProficiencyLevel {
        let weightedScore = (grammarScore * listeningWeights.grammar) +
                            (vocabularyScore * listeningWeights.vocabulary) +
                            (fluencyScore * listeningWeights.fluency) +
                            (pronunciationScore * listeningWeights.pronunciation) +
                            (comprehensionScore * listeningWeights.comprehension)

        skillScores[.listening] = (grammar: grammarScore, vocabulary: vocabularyScore, fluency: fluencyScore, pronunciation: pronunciationScore, comprehension: comprehensionScore) // store scores
        return determineProficiencyLevel(from: weightedScore)
    }

    // MARK: - Proficiency Level Mapping

    /// Determines the proficiency level based on a weighted score.  This is where you define the score ranges for each level.
    /// - Parameter weightedScore: The overall weighted score (0.0 - 1.0).
    /// - Returns: The corresponding proficiency level.
    private func determineProficiencyLevel(from weightedScore: Double) -> ProficiencyLevel {
        switch weightedScore {
        case 0.0..<0.2:
            return .beginner
        case 0.2..<0.4:
            return .elementary
        case 0.4..<0.6:
            return .intermediate
        case 0.6..<0.8:
            return .upperIntermediate
        case 0.8..<0.9:
            return .advanced
        default:
            return .proficient // 0.9 - 1.0
        }
    }

    // MARK: - (Optional) Access to individual skill scores for analysis

    func getSkillScores(for skill: LanguageSkill) -> (grammar: Double, vocabulary: Double, fluency: Double, pronunciation: Double, comprehension: Double)? {
        return skillScores[skill]
    }


}

// MARK: - Example Usage

let evaluator = LanguageProficiencyEvaluator()

// Example: Evaluating Speaking
let speakingLevel = evaluator.evaluateSpeaking(grammarScore: 0.7, vocabularyScore: 0.6, fluencyScore: 0.8, pronunciationScore: 0.75, comprehensionScore: 0.5)
print("Speaking Proficiency Level: \(speakingLevel)") // Output: Speaking Proficiency Level: upperIntermediate

// Example: Evaluating Writing
let writingLevel = evaluator.evaluateWriting(grammarScore: 0.8, vocabularyScore: 0.7, fluencyScore: 0.6, comprehensionScore: 0.7, fluencyScore: 0.6)
print("Writing Proficiency Level: \(writingLevel)") // Output: Writing Proficiency Level: upperIntermediate

// Example: Evaluating Listening
let listeningLevel = evaluator.evaluateListening(grammarScore: 0.3, vocabularyScore: 0.5, fluencyScore: 0.4, pronunciationScore: 0.6, comprehensionScore: 0.7)
print("Listening Proficiency Level: \(listeningLevel)") // Output: Listening Proficiency Level: intermediate


//Example getting skill scores
if let speakingScores = evaluator.getSkillScores(for: .speaking) {
    print("Speaking Scores: \(speakingScores)")
}
```

Key improvements and explanations:

* **Clear Structure:**  The code is now structured with `structs` and `enums` for better organization and type safety.
* **`SkillWeight` Struct:** Introduces a `SkillWeight` struct to define the importance of each skill (grammar, vocabulary, etc.) for *each* language skill (speaking, writing, listening).  This is *crucial* for customizing the evaluator to your specific needs.  The weights *must* add up to 1.0 (or very close to it, allowing for minor floating-point imprecision) for each skill type.
* **`LanguageSkill` Enum:**  Uses an enum to clearly define the different language skills being evaluated.
* **`ProficiencyLevel` Enum:**  Uses an enum to represent the different proficiency levels.  Crucially, this enum now conforms to `Comparable`, allowing easy comparison of levels (e.g., `if level1 > level2`).  I've also added a `numericValue` to the enum to facilitate this comparison.
* **Customizable Weights:** The `speakingWeights`, `writingWeights`, and `listeningWeights` are now properties of the `LanguageProficiencyEvaluator` class.  This allows you to easily adjust the weights for each skill *independently*.  **THIS IS THE MOST IMPORTANT IMPROVEMENT.**  You'll need to experiment with these weights to get the most accurate results for your application. The weights MUST add up to 1.0 (accounting for potential floating-point inaccuracies).
* **`evaluateSpeaking`, `evaluateWriting`, `evaluateListening` Functions:** These functions now take individual scores for each skill (grammar, vocabulary, fluency, pronunciation, comprehension).  This is more flexible and allows for more granular evaluation.
* **Weighted Score Calculation:**  The functions calculate a weighted score based on the skill scores and the corresponding weights.
* **`determineProficiencyLevel` Function:**  This function maps the weighted score to a proficiency level.  This is where you define the score ranges for each level.  *Adjust these ranges as needed to match your desired proficiency level definitions.*
* **Error Handling Removed (for simplicity):**  For this example, I've removed the explicit error handling to keep the code cleaner and more focused on the core logic.  In a real-world application, you would definitely want to add error handling to validate the input scores.  Specifically, check that the scores are between 0.0 and 1.0, and consider what to do if they aren't.
* **Data Validation is essential in Real-World Use:**  The `evaluate...` functions should validate inputs to ensure scores are within 0.0...1.0 range. You can throw errors or handle invalid inputs gracefully.
* **Internal Score Tracking (Optional):** The `skillScores` dictionary allows you to store the individual skill scores for each evaluation.  This can be useful for debugging, analysis, or providing feedback to the user.  It's optional, but I highly recommend including it for development and testing.
* **`getSkillScores` Function:**  Provides access to the individual skill scores for analysis.
* **Clearer Comments:**  I've added more comments to explain the code and the rationale behind the design choices.
* **Example Usage:**  The example usage demonstrates how to use the `LanguageProficiencyEvaluator` class and provides sample output.
* **Pronunciation in Writing:**  The `evaluateWriting` function sets pronunciation to 0.0 because pronunciation is not relevant to writing.  It *does* include a comprehension score, as clear writing aids comprehension.
* **Flexibility:**  The code is now much more flexible and customizable. You can easily adjust the skill weights, proficiency level ranges, and add or remove skills as needed.
* **Maintainability:**  The code is well-structured and easy to understand, making it easier to maintain and extend.
* **Testability:** The separation of concerns makes the code more testable.  You can write unit tests to verify the accuracy of the evaluation logic.
* **Real-Time Adaptation:** This architecture is amenable to real-time adaptation.  If the application is receiving continuous feedback (e.g., from speech recognition, grammar checkers), the scores can be dynamically adjusted, and the proficiency level can be updated in real-time.

How to Use in a Real-Time Application:

1. **Input Collection:**  Your language learning application will need to gather input data.
    * **Speaking:**  Speech recognition software can provide scores for grammar, vocabulary, fluency, and pronunciation.  Comprehension can be inferred from the user's responses.
    * **Writing:**  Grammar checkers, vocabulary analysis tools, and readability scores can provide scores for grammar, vocabulary, fluency, and comprehension.
    * **Listening:** Comprehension questions after listening exercises can generate a comprehension score. Speech recognition can evaluate how well the student *hears* (pronunciation recognition) the words.
2. **Score Normalization:**  Ensure that all scores are normalized to a range of 0.0 to 1.0.  This may require scaling or mapping the scores from different sources.
3. **Evaluation:**  Use the `LanguageProficiencyEvaluator` to evaluate the user's proficiency based on the normalized scores.
4. **Feedback:**  Provide feedback to the user based on the evaluation results.  This could include the overall proficiency level, as well as strengths and weaknesses in specific skills. You can use the `getSkillScores` function to get granular results.
5. **Adaptation (Advanced):**  Use the evaluation results to adapt the learning content and activities to the user's proficiency level.  For example, if the user is struggling with grammar, the application could provide more grammar exercises.

This improved version provides a solid foundation for building a real-time language proficiency evaluator.  Remember to experiment with the skill weights and proficiency level ranges to get the most accurate results for your specific application and target language. Remember to add robust input validation and error handling for a production-ready application.
👁️ Viewed: 5

Comments