| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394 |
- import Foundation
- enum TitleAnalysisEngine {
- static func analyze(title: String, goal: TitleGoal) -> TitleAnalysis {
- let length = title.count
- let lengthScore = scoreLength(length)
- let engagementScore = scoreEngagement(title, goal: goal)
- let clarityScore = scoreClarity(title)
- let overall = (lengthScore + engagementScore + clarityScore) / 3
- let suggestions = makeSuggestions(title: title, length: length, goal: goal)
- return TitleAnalysis(
- overallScore: overall,
- lengthScore: lengthScore,
- engagementScore: engagementScore,
- clarityScore: clarityScore,
- suggestions: suggestions
- )
- }
- private static func scoreLength(_ length: Int) -> Int {
- switch length {
- case 0: 0
- case 1...50: 95
- case 51...80: 85
- case 81...120: 70
- case 121...200: 50
- case 201...300: 30
- default: 10
- }
- }
- private static func scoreEngagement(_ title: String, goal: TitleGoal) -> Int {
- var score = 50
- let lower = title.lowercased()
- if title.contains("?") { score += 10 }
- if title.range(of: #"\d+"#, options: .regularExpression) != nil { score += 8 }
- if lower.contains("how") || lower.contains("why") || lower.contains("what") { score += 6 }
- if lower.contains("you") || lower.contains("your") { score += 5 }
- if title == title.uppercased() && title.count > 5 { score -= 15 }
- switch goal {
- case .question where !title.contains("?"): score -= 10
- case .listicle where title.range(of: #"\d+"#, options: .regularExpression) == nil: score -= 8
- case .curiosity where !lower.contains("secret") && !lower.contains("nobody") && !lower.contains("actually"): score -= 3
- default: break
- }
- return min(100, max(0, score))
- }
- private static func scoreClarity(_ title: String) -> Int {
- var score = 70
- let words = title.split(separator: " ").count
- if words >= 4 && words <= 12 { score += 15 }
- if words < 3 { score -= 20 }
- if words > 20 { score -= 15 }
- if title.contains(" ") { score -= 5 }
- if title.hasPrefix(" ") || title.hasSuffix(" ") { score -= 10 }
- return min(100, max(0, score))
- }
- private static func makeSuggestions(title: String, length: Int, goal: TitleGoal) -> [String] {
- var tips: [String] = []
- if length > 120 {
- tips.append("Shorten to under 80 characters for better mobile visibility.")
- } else if length < 20 {
- tips.append("Add more context — very short titles can feel vague in feeds.")
- }
- if !title.contains("?") && goal == .question {
- tips.append("Reframe as a question to invite comments.")
- }
- if title.range(of: #"\d+"#, options: .regularExpression) == nil && goal == .listicle {
- tips.append("Include a number (e.g. \"5 tips\") for listicle-style engagement.")
- }
- let lower = title.lowercased()
- if goal == .curiosity && !lower.contains("?") {
- tips.append("Add a curiosity hook — hint at a surprising outcome.")
- }
- if tips.isEmpty {
- tips.append("Strong base title — try variants with different hooks below.")
- }
- return tips
- }
- }
|