smithery/raydocs

skin-matching

皮肤双胞胎匹?

Installation

$ npx skills add smithery/raydocs --skill skin-matching

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery/raydocs · top by installs.

npx skills add smithery/raydocs

Browse all from smithery/raydocs

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 7,970 B
  • docs SUMMARY.md 147 B

History

  1. First recorded snapshot · 0 installs

SKILL.md

皮肤匹配技能

概述

通过皮肤指纹向量匹配相似用户,推荐他们验证有效的产品。

皮肤指纹设计

struct SkinFingerprint: Codable {
    // 基础信息(用于匹配)
    let skinType: SkinType              // 肤质
    let ageRange: AgeRange              // 年龄段
    let gender: Gender?                 // 性别(可选)
    let region: String?                 // 地区/气候(可选)
    
    // 问题向量(0-1归一化)
    let issueVector: [Double]           // [spots, acne, pores, wrinkles, redness, evenness, texture]
    
    // 计算后的向量表示
    var vector: [Double] {
        var v: [Double] = []
        
        // One-hot编码肤质
        v.append(contentsOf: skinType.oneHot)
        
        // 年龄归一化
        v.append(ageRange.normalized)
        
        // 问题向量
        v.append(contentsOf: issueVector)
        
        return v
    }
}

enum SkinType: String, Codable, CaseIterable {
    case dry, oily, combination, sensitive
    
    var oneHot: [Double] {
        Self.allCases.map { $0 == self ? 1.0 : 0.0 }
    }
}

enum AgeRange: String, Codable {
    case under20, age20to25, age25to30, age30to35, age35to40, over40
    
    var normalized: Double {
        switch self {
        case .under20: return 0.1
        case .age20to25: return 0.25
        case .age25to30: return 0.4
        case .age30to35: return 0.55
        case .age35to40: return 0.7
        case .over40: return 0.85
        }
    }
}

相似度计算

class SkinMatcher {
    /// 计算余弦相似度
    func cosineSimilarity(_ a: [Double], _ b: [Double]) -> Double {
        guard a.count == b.count, !a.isEmpty else { return 0 }
        
        let dotProduct = zip(a, b).map(*).reduce(0, +)
        let magnitudeA = sqrt(a.map { $0 * $0 }.reduce(0, +))
        let magnitudeB = sqrt(b.map { $0 * $0 }.reduce(0, +))
        
        guard magnitudeA > 0, magnitudeB > 0 else { return 0 }
        return dotProduct / (magnitudeA * magnitudeB)
    }
    
    /// 加权相似度(肤质权重更高)
    func weightedSimilarity(user: SkinFingerprint, other: SkinFingerprint) -> Double {
        let basicSimilarity = cosineSimilarity(user.vector, other.vector)
        
        // 肤质必须相同才算高度相似
        let skinTypeBonus = user.skinType == other.skinType ? 0.2 : -0.3
        
        // 年龄接近加分
        let ageDiff = abs(user.ageRange.normalized - other.ageRange.normalized)
        let ageBonus = ageDiff < 0.2 ? 0.1 : 0
        
        return min(1.0, max(0, basicSimilarity + skinTypeBonus + ageBonus))
    }
    
    /// 查找皮肤双胞胎
    func findSkinTwins(
        for user: SkinFingerprint,
        from pool: [UserProfile],
        limit: Int = 10
    ) -> [SkinTwin] {
        pool
            .map { profile -> SkinTwin in
                let similarity = weightedSimilarity(user: user, other: profile.fingerprint)
                return SkinTwin(
                    userId: profile.id,
                    similarity: similarity,
                    skinProfile: profile.anonymized,
                    effectiveProducts: profile.effectiveProducts
                )
            }
            .filter { $0.similarity >= 0.6 }  // 最低相似度阈值
            .sorted { $0.similarity > $1.similarity }
            .prefix(limit)
            .map { $0 }
    }
}

匹配结果模型

struct SkinTwin: Identifiable {
    let id = UUID()
    let userId: String
    let similarity: Double              // 0-1
    let skinProfile: AnonymousProfile
    let effectiveProducts: [EffectiveProduct]
    
    var matchLevel: MatchLevel {
        switch similarity {
        case 0.9...: return .twin        // 皮肤双胞胎
        case 0.8..<0.9: return .verySimilar
        case 0.7..<0.8: return .similar
        default: return .somewhatSimilar
        }
    }
}

enum MatchLevel: String {
    case twin = "皮肤双胞胎 👯"
    case verySimilar = "非常相似"
    case similar = "相似"
    case somewhatSimilar = "有点相似"
}

struct AnonymousProfile: Codable {
    let skinType: SkinType
    let ageRange: String                // "25-30岁"
    let mainConcerns: [SkinConcern]
    let region: String?
    // 不包含任何可识别个人信息
}

struct EffectiveProduct: Identifiable {
    let id: String
    let product: Product
    let usageDuration: Int              // 使用天数
    let improvementPercent: Double      // 改善百分比
    let verifiedAt: Date
}

推荐分数计算

struct ProductRecommendationScore {
    let product: Product
    let score: Double
    let reasons: [String]
    
    static func calculate(
        product: Product,
        userFingerprint: SkinFingerprint,
        skinTwins: [SkinTwin]
    ) -> ProductRecommendationScore {
        var score: Double = 0
        var reasons: [String] = []
        
        // 1. 相似用户有效率 (权重40%)
        let relevantTwins = skinTwins.filter { twin in
            twin.effectiveProducts.contains { $0.product.id == product.id }
        }
        if !relevantTwins.isEmpty {
            let weightedEffectiveness = relevantTwins.reduce(0.0) { sum, twin in
                let effectiveness = twin.effectiveProducts
                    .first { $0.product.id == product.id }?
                    .improvementPercent ?? 0
                return sum + twin.similarity * effectiveness
            } / relevantTwins.reduce(0.0) { $0 + $1.similarity }
            
            score += weightedEffectiveness * 0.4
            reasons.append("\(relevantTwins.count)位相似用户验证有效")
        }
        
        // 2. 成分适配度 (权重30%)
        let ingredientMatch = calculateIngredientMatch(product, userFingerprint)
        score += ingredientMatch * 0.3
        if ingredientMatch > 0.7 {
            reasons.append("成分适合你的肤质")
        }
        
        // 3. 问题匹配度 (权重20%)
        let concernMatch = calculateConcernMatch(product, userFingerprint)
        score += concernMatch * 0.2
        if concernMatch > 0.7 {
            reasons.append("针对你的皮肤问题")
        }
        
        // 4. 刺激风险扣分 (权重10%)
        let riskPenalty = calculateRiskPenalty(product, userFingerprint)
        score -= riskPenalty * 0.1
        if riskPenalty > 0.3 {
            reasons.append("⚠️ 部分成分可能刺激")
        }
        
        return ProductRecommendationScore(
            product: product,
            score: min(1.0, max(0, score)),
            reasons: reasons
        )
    }
}

数据贡献机制

struct DataContribution {
    /// 用户贡献追踪数据时调用
    func contribute(
        session: TrackingSession,
        report: TrackingReport,
        consentLevel: ConsentLevel
    ) {
        switch consentLevel {
        case .anonymous:
            // 只贡献统计数据,不关联用户
            uploadAnonymousStats(report)
        case .pseudonymous:
            // 贡献数据并参与匹配,但不显示可识别信息
            uploadForMatching(session, report)
        case .public:
            // 公开分享,可被其他用户看到
            uploadPublic(session, report)
        case .none:
            // 不贡献数据
            break
        }
    }
    
    enum ConsentLevel {
        case anonymous      // 匿名统计
        case pseudonymous   // 参与匹配但不公开
        case `public`       // 公开分享
        case none           // 完全私密
    }
}

验证

  • 相似度计算准确
  • 匹配结果排序正确
  • 推荐分数合理
  • 隐私保护到位
  • 冷启动时有合理降级