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

View File

@ -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>

View File

@ -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 firstSentence;
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 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 "개인화된 마케팅 팁이 생성되었습니다.";
}
/**