feat: Marketing Tip Summary

This commit is contained in:
yuhalog
2025-06-17 14:05:21 +09:00
parent f9a5007cfd
commit 14c5164c41
2 changed files with 157 additions and 14 deletions
@@ -102,7 +102,7 @@ class MarketingTipService:
당신의 임무는 매장 정보를 바탕으로, 적은 비용으로 효과를 낼 수 있는 현실적이고 실행 가능한 마케팅 팁을 제안하는 것입니다.
지역성, 지역의 현재 날씨 확인하고, 현재 트렌드까지 고려해주세요.
소상공인을 위한 현실적이고 바로 실행할 수 있는 실용적인 마케팅 팁을 생성해주세요.
협업보다는 할인, 포스팅 등 당장 실현 가능한 현실적인 방법을 추천해주세요.
협업보다는 할인, 포스팅 등 당장 실현 가능한 현실적이면서도 창의적인 방법을 추천해주세요.
매장 정보:
- 매장명: {store_name}
@@ -130,9 +130,7 @@ class MarketingTipService:
4. **시의성**: 현재 계절, 유행, 트렌드를 반영
5. **지역성**: 지역 특성 및 현재 날씨를 고려할 것
응답 형식 (300자 내외, 간결하게):
html 형식으로 출력
출력해야할 내용:
- 핵심 마케팅 팁 (1개)
- 실행 방법 (1개)
- 예상 비용과 기대 효과
@@ -140,7 +138,8 @@ html 형식으로 출력
- 참고했던 실제 성공한 마케팅
- 오늘의 응원의 문장 (간결하게 1개)
아래 형식그대로 출력해주세요!
아래 HTML 템플릿 형식응답해주세요. <h3> 태그는 절대 변경하지 말고, <p> 태그 내용만 새로 작성해주세요
<p> 태그 내용 외에 다른 내용은 절대 넣지 마세요 :
<h3>✨ 핵심 마케팅 팁</h3>
<p>[여기에 새로운 핵심 마케팅 팁 작성]</p>
@@ -155,7 +154,7 @@ html 형식으로 출력
<p>[여기에 새로운 주의사항 내용 작성]</p>
<h3>📈 참고했던 실제 성공한 마케팅</h3>
<p>[여기에 새로운 참고 사례 내용 작성]</p>
<p>[여기에 새로운 참고 사례 내용 작성, 존재하지 않는 사례는 절대 참고하지 말고, 실제 존재하는 마케팅 성공 사례로만 작성. 참고했던 존재하는 url로 함께 표기]</p>
<h3>🙌 오늘의 응원의 문장</h3>
<p>[여기에 응원의 문장 작성]</p>
@@ -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("&nbsp;", " ") // HTML 엔티티 처리
.replaceAll("&lt;", "<")
.replaceAll("&gt;", ">")
.replaceAll("&amp;", "&")
.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 "개인화된 마케팅 팁이 생성되었습니다.";
}
/**