package outreach import ( "strings" ) func NormalizeDraftText(text string) string { text = strings.ReplaceAll(text, "\r\n", "\n") text = strings.ReplaceAll(text, "\r", "\n") text = strings.TrimSpace(text) text = humanizeDraftLineBreaks(text) return trimDraftText(text) } func humanizeDraftLineBreaks(text string) string { if text == "" || strings.Contains(text, "\n") { return text } if len([]rune(text)) < 40 { return text } sentences := splitSentences(text) if len(sentences) <= 1 { return text } paragraphs := make([]string, 0, (len(sentences)+1)/2) for i := 0; i < len(sentences); { end := i + 2 if end > len(sentences) { end = len(sentences) } paragraphs = append(paragraphs, strings.Join(sentences[i:end], "")) i = end } return strings.Join(paragraphs, "\n\n") } func splitSentences(text string) []string { runes := []rune(text) if len(runes) == 0 { return nil } out := make([]string, 0, 4) var current strings.Builder for i := 0; i < len(runes); i++ { ch := runes[i] current.WriteRune(ch) if !isSentenceEnd(ch) { continue } // Keep ellipsis / repeated punctuation attached to the same sentence. for i+1 < len(runes) && isSentenceEnd(runes[i+1]) { i++ current.WriteRune(runes[i]) } if sentence := strings.TrimSpace(current.String()); sentence != "" { out = append(out, sentence) } current.Reset() } if tail := strings.TrimSpace(current.String()); tail != "" { out = append(out, tail) } return out } func isSentenceEnd(ch rune) bool { switch ch { case '。', '!', '?', '!', '?', '…': return true default: return false } }