mirror of
https://github.com/won-ktds/smarketing-backend.git
synced 2026-06-13 04:49:10 +00:00
feat: Marketing Tip Summary
This commit is contained in:
+152
-8
@@ -142,23 +142,167 @@ public class MarketingTipService implements MarketingTipUseCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* 마케팅 팁 요약 생성 (첫 50자 또는 첫 번째 문장)
|
||||
* 마케팅 팁 요약 생성 (핵심 마케팅 팁 섹션에서 첫 번째 문장 추출)
|
||||
*
|
||||
* @param fullContent AI로 생성된 전체 마케팅 팁 HTML 콘텐츠
|
||||
* @return 핵심 마케팅 팁의 첫 번째 문장
|
||||
*/
|
||||
private String generateTipSummary(String fullContent) {
|
||||
if (fullContent == null || fullContent.trim().isEmpty()) {
|
||||
return "마케팅 팁이 생성되었습니다.";
|
||||
}
|
||||
|
||||
// 첫 번째 문장으로 요약 (마침표 기준)
|
||||
String[] sentences = fullContent.split("[.!?]");
|
||||
String firstSentence = sentences.length > 0 ? sentences[0].trim() : fullContent;
|
||||
try {
|
||||
// 1. "✨ 핵심 마케팅 팁" 섹션 추출
|
||||
String coreSection = extractCoreMarketingTipSection(fullContent);
|
||||
|
||||
// 50자 제한
|
||||
if (firstSentence.length() > 50) {
|
||||
return firstSentence.substring(0, 47) + "...";
|
||||
if (coreSection != null && !coreSection.trim().isEmpty()) {
|
||||
// 2. HTML 태그 제거
|
||||
String cleanText = removeHtmlTags(coreSection);
|
||||
|
||||
// 3. 첫 번째 의미있는 문장 추출
|
||||
String summary = extractFirstMeaningfulSentence(cleanText);
|
||||
|
||||
// 4. 길이 제한 (100자 이내)
|
||||
if (summary.length() > 100) {
|
||||
summary = summary.substring(0, 97) + "...";
|
||||
}
|
||||
|
||||
return summary;
|
||||
}
|
||||
|
||||
// 핵심 팁 섹션을 찾지 못한 경우 fallback 처리
|
||||
return extractFallbackSummary(fullContent);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.warn("마케팅 팁 요약 생성 중 오류 발생, 기본 메시지 반환: {}", e.getMessage());
|
||||
return "맞춤형 마케팅 팁이 생성되었습니다.";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* "✨ 핵심 마케팅 팁" 섹션 추출
|
||||
*/
|
||||
private String extractCoreMarketingTipSection(String fullContent) {
|
||||
// 핵심 마케팅 팁 섹션 시작 패턴들
|
||||
String[] corePatterns = {
|
||||
"✨ 핵심 마케팅 팁",
|
||||
"<h3>✨ 핵심 마케팅 팁</h3>",
|
||||
"핵심 마케팅 팁"
|
||||
};
|
||||
|
||||
// 다음 섹션 시작 패턴들
|
||||
String[] nextSectionPatterns = {
|
||||
"🚀 실행 방법",
|
||||
"<h3>🚀 실행 방법</h3>",
|
||||
"💰 예상 비용",
|
||||
"<h3>💰 예상 비용"
|
||||
};
|
||||
|
||||
for (String pattern : corePatterns) {
|
||||
int startIndex = fullContent.indexOf(pattern);
|
||||
if (startIndex != -1) {
|
||||
// 패턴 뒤부터 시작
|
||||
int contentStart = startIndex + pattern.length();
|
||||
|
||||
// 다음 섹션까지의 내용 추출
|
||||
int endIndex = fullContent.length();
|
||||
for (String nextPattern : nextSectionPatterns) {
|
||||
int nextIndex = fullContent.indexOf(nextPattern, contentStart);
|
||||
if (nextIndex != -1 && nextIndex < endIndex) {
|
||||
endIndex = nextIndex;
|
||||
}
|
||||
}
|
||||
|
||||
return fullContent.substring(contentStart, endIndex).trim();
|
||||
}
|
||||
}
|
||||
|
||||
return firstSentence;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML 태그 제거
|
||||
*/
|
||||
private String removeHtmlTags(String htmlText) {
|
||||
if (htmlText == null) return "";
|
||||
|
||||
return htmlText
|
||||
.replaceAll("<[^>]+>", "") // HTML 태그 제거
|
||||
.replaceAll(" ", " ") // HTML 엔티티 처리
|
||||
.replaceAll("<", "<")
|
||||
.replaceAll(">", ">")
|
||||
.replaceAll("&", "&")
|
||||
.replaceAll("\\s+", " ") // 연속된 공백을 하나로
|
||||
.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* 첫 번째 의미있는 문장 추출
|
||||
*/
|
||||
private String extractFirstMeaningfulSentence(String cleanText) {
|
||||
if (cleanText == null || cleanText.trim().isEmpty()) {
|
||||
return "마케팅 팁이 생성되었습니다.";
|
||||
}
|
||||
|
||||
// 문장 분할 (마침표, 느낌표, 물음표 기준)
|
||||
String[] sentences = cleanText.split("[.!?]");
|
||||
|
||||
for (String sentence : sentences) {
|
||||
String trimmed = sentence.trim();
|
||||
|
||||
// 의미있는 문장인지 확인 (10자 이상, 특수문자만으로 구성되지 않음)
|
||||
if (trimmed.length() >= 10 &&
|
||||
!trimmed.matches("^[\\s\\p{Punct}]*$") && // 공백과 구두점만으로 구성되지 않음
|
||||
!isOnlyEmojisOrSymbols(trimmed)) { // 이모지나 기호만으로 구성되지 않음
|
||||
|
||||
// 문장 끝에 마침표 추가 (없는 경우)
|
||||
if (!trimmed.endsWith(".") && !trimmed.endsWith("!") && !trimmed.endsWith("?")) {
|
||||
trimmed += ".";
|
||||
}
|
||||
|
||||
return trimmed;
|
||||
}
|
||||
}
|
||||
|
||||
// 의미있는 문장을 찾지 못한 경우 원본의 처음 50자 반환
|
||||
if (cleanText.length() > 50) {
|
||||
return cleanText.substring(0, 47) + "...";
|
||||
}
|
||||
|
||||
return cleanText;
|
||||
}
|
||||
|
||||
/**
|
||||
* 이모지나 기호만으로 구성되었는지 확인
|
||||
*/
|
||||
private boolean isOnlyEmojisOrSymbols(String text) {
|
||||
// 한글, 영문, 숫자가 포함되어 있으면 의미있는 텍스트로 판단
|
||||
return !text.matches(".*[\\p{L}\\p{N}].*");
|
||||
}
|
||||
|
||||
/**
|
||||
* 핵심 팁 섹션을 찾지 못한 경우 대체 요약 생성
|
||||
*/
|
||||
private String extractFallbackSummary(String fullContent) {
|
||||
// HTML 태그 제거 후 첫 번째 의미있는 문장 찾기
|
||||
String cleanContent = removeHtmlTags(fullContent);
|
||||
|
||||
// 첫 번째 문단에서 의미있는 문장 추출
|
||||
String[] paragraphs = cleanContent.split("\\n\\n");
|
||||
|
||||
for (String paragraph : paragraphs) {
|
||||
String trimmed = paragraph.trim();
|
||||
if (trimmed.length() >= 20) { // 충분히 긴 문단
|
||||
String summary = extractFirstMeaningfulSentence(trimmed);
|
||||
if (summary.length() >= 10) {
|
||||
return summary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 모든 방법이 실패한 경우 기본 메시지
|
||||
return "개인화된 마케팅 팁이 생성되었습니다.";
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user