smithery.ai

ingredient-scanner

扫描护肤品成分表,OCR识别并AI解读成分功效与风险。实现成分扫描功能时使用此技能。

First seen Mar 21, 2026

Installation

$ npx skills add https://smithery.ai

Also in this package

Other skills from smithery.ai · top by installs.

npx skills add https://smithery.ai

Browse all from smithery.ai

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 6,225 B
  • docs SUMMARY.md 142 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 1 installs

SKILL.md

成分扫描技能

概述

拍摄护肤品成分表,通过OCR识别成分,并使用AI解读功效与风险。

处理流程

拍照 → OCR识别 → 成分标准化 → 本地匹配 → AI解读 → 结果展示

1. OCR识别模块

import Vision

class IngredientOCR {
    func recognizeText(from image: UIImage) async throws -> [String] {
        guard let cgImage = image.cgImage else {
            throw OCRError.invalidImage
        }
        
        let request = VNRecognizeTextRequest()
        request.recognitionLevel = .accurate
        request.recognitionLanguages = ["en-US", "zh-Hans", "zh-Hant"]
        request.usesLanguageCorrection = true
        
        let handler = VNImageRequestHandler(cgImage: cgImage)
        try handler.perform([request])
        
        let text = request.results?
            .compactMap { $0.topCandidates(1).first?.string }
            .joined(separator: " ") ?? ""
        
        return parseIngredients(from: text)
    }
    
    private func parseIngredients(from text: String) -> [String] {
        // 成分表通常用逗号分隔
        let separators = CharacterSet(charactersIn: ",,、;;")
        return text
            .components(separatedBy: separators)
            .map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
            .filter { !$0.isEmpty }
    }
}

2. 成分标准化

class IngredientNormalizer {
    // 成分别名映射
    private let aliasMap: [String: String] = [
        "水": "Water",
        "纯净水": "Water",
        "去离子水": "Water",
        "烟酰胺": "Niacinamide",
        "维生素B3": "Niacinamide",
        "视黄醇": "Retinol",
        "维A醇": "Retinol",
        "透明质酸": "Hyaluronic Acid",
        "玻尿酸": "Hyaluronic Acid",
        "水杨酸": "Salicylic Acid",
        "抗坏血酸": "Ascorbic Acid",
        "维生素C": "Ascorbic Acid",
        // ... 更多映射
    ]
    
    func normalize(_ ingredient: String) -> String {
        let trimmed = ingredient.trimmingCharacters(in: .whitespacesAndNewlines)
        return aliasMap[trimmed] ?? trimmed
    }
}

3. 本地成分库匹配

struct IngredientInfo: Codable {
    let name: String
    let function: IngredientFunction
    let safetyRating: Int           // 1-10
    let irritationRisk: IrritationLevel
    let benefits: [String]
    let warnings: [String]?
    let concentration: String?       // 有效浓度范围
}

class IngredientDatabase {
    private var ingredients: [String: IngredientInfo] = [:]
    
    func lookup(_ name: String) -> IngredientInfo? {
        let normalized = name.lowercased()
        return ingredients[normalized]
    }
    
    func loadLocalDatabase() {
        // 从本地JSON加载常见成分信息
        guard let url = Bundle.main.url(forResource: "ingredients", withExtension: "json"),
              let data = try? Data(contentsOf: url),
              let decoded = try? JSONDecoder().decode([String: IngredientInfo].self, from: data) else {
            return
        }
        ingredients = decoded
    }
}

4. AI解读

func analyzeIngredients(
    ingredients: [String],
    userProfile: UserProfile?
) async throws -> IngredientAnalysis {
    let prompt = """
    作为护肤品成分分析专家,请分析以下成分表:
    
    成分:\(ingredients.joined(separator: ", "))
    
    用户信息:
    - 肤质:\(userProfile?.skinType.rawValue ?? "未知")
    - 主要问题:\(userProfile?.concerns.map(\.rawValue).joined(separator: ", ") ?? "未知")
    - 已知过敏:\(userProfile?.allergies.joined(separator: ", ") ?? "无")
    
    请以JSON格式返回分析结果:
    {
      "overallRating": 0-10,
      "suitability": "suitable/caution/unsuitable",
      "highlights": ["亮点成分1", "亮点成分2"],
      "warnings": ["风险提示1"],
      "conflicts": ["冲突提示(如与用户已用产品冲突)"],
      "summary": "一句话总结"
    }
    """
    
    return try await geminiService.analyze(prompt: prompt)
}

5. 结果模型

struct IngredientAnalysis: Codable {
    let ingredients: [ParsedIngredient]
    let overallRating: Double
    let suitability: Suitability
    let highlights: [String]
    let warnings: [String]
    let conflicts: [String]?
    let summary: String
}

struct ParsedIngredient: Codable {
    let name: String
    let normalizedName: String
    let function: IngredientFunction?
    let safetyRating: Int?
    let isHighlight: Bool
    let isWarning: Bool
}

enum Suitability: String, Codable {
    case suitable    // 适合
    case caution     // 谨慎使用
    case unsuitable  // 不适合
}

6. 冲突检测规则

struct ConflictRule {
    let ingredient1: String
    let ingredient2: String
    let severity: ConflictSeverity
    let description: String
}

enum ConflictSeverity {
    case warning    // 建议分开使用
    case danger     // 不建议同时使用
}

let conflictRules: [ConflictRule] = [
    ConflictRule(
        ingredient1: "Retinol",
        ingredient2: "AHA",
        severity: .warning,
        description: "A醇和果酸同时使用可能导致刺激,建议早晚分开使用"
    ),
    ConflictRule(
        ingredient1: "Retinol",
        ingredient2: "BHA",
        severity: .warning,
        description: "A醇和水杨酸同时使用可能导致刺激"
    ),
    ConflictRule(
        ingredient1: "Retinol",
        ingredient2: "Benzoyl Peroxide",
        severity: .danger,
        description: "A醇和过氧化苯甲酰会相互抵消效果"
    ),
    ConflictRule(
        ingredient1: "Vitamin C",
        ingredient2: "Niacinamide",
        severity: .warning,
        description: "高浓度时可能互相影响效果,建议间隔15分钟使用"
    )
]

验证

  • OCR识别准确率 > 90%
  • 成分标准化覆盖常见别名
  • 本地成分库包含200+常见成分
  • 冲突检测规则完整
  • AI解读结果结构正确