Skip to content

Commit 942e72d

Browse files
authored
[feat]: 반말 모드 기능 추가 (moduwa-aac#80)
2 parents dbe9e8e + bb1f97c commit 942e72d

File tree

3 files changed

+42
-15
lines changed

3 files changed

+42
-15
lines changed

src/ai-prediction/controllers/ai.style.controller.js

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,26 @@ const transformStyleController = async (req, res, next) => {
2020
console.log('🟣 AI Style 요청 받음:', req.body);
2121

2222
// 검증된 데이터 추출 (미들웨어에서 이미 검증 완료)
23-
const { words, endingCards, refresh = false } = req.body;
23+
const { words, endingCards, tone, refresh = false } = req.body;
2424
const userId = req.user?.userId; // 인증된 사용자 ID (학습 데이터 가중치 적용용)
2525

26+
// tone 우선 + endingCards 합성 정규화
27+
let normalizedEndingCards = Array.isArray(endingCards) ? [...endingCards] : [];
28+
29+
if (tone) {
30+
// endingCards 안에 존댓말/반말이 들어와도 tone이 우선이므로 제거
31+
normalizedEndingCards = normalizedEndingCards.filter(
32+
(card) => card !== '존댓말' && card !== '반말'
33+
);
34+
35+
const toneCard = tone === 'HONORIFIC' ? '존댓말' : '반말';
36+
normalizedEndingCards.unshift(toneCard);
37+
}
38+
2639
// 캐시 조회 (refresh가 false일 때만)
27-
if (!refresh && words.length > 0 && endingCards.length > 0) {
40+
if (!refresh && words.length > 0 && normalizedEndingCards.length > 0) {
2841
const cacheContext = { previousMessages: [] };
29-
const cacheKey = generateCacheKey(words, cacheContext, 'styles', endingCards);
42+
const cacheKey = generateCacheKey(words, cacheContext, 'styles', normalizedEndingCards);
3043
const cached = await getFromCache(cacheKey);
3144

3245
if (cached?.sentences) {
@@ -54,12 +67,12 @@ const transformStyleController = async (req, res, next) => {
5467

5568
// AI 문장 추천 호출 (userId 전달하여 학습 데이터 가중치 적용)
5669
console.log('🤖 FastAPI 호출:', { words, endingCards, refresh, userId });
57-
const result = await transformSentenceStyle(words, endingCards, refresh, userId);
70+
const result = await transformSentenceStyle(words, normalizedEndingCards, refresh, userId);
5871

5972
// 캐시 저장 (원본 sentences만 저장, 사용자별 가중치 미적용)
60-
if (words.length > 0 && endingCards.length > 0) {
73+
if (words.length > 0 && normalizedEndingCards.length > 0) {
6174
const cacheContext = { previousMessages: [] };
62-
const cacheKey = generateCacheKey(words, cacheContext, 'styles', endingCards);
75+
const cacheKey = generateCacheKey(words, cacheContext, 'styles', normalizedEndingCards);
6376
await saveToCache(cacheKey, {
6477
words: result.words,
6578
endingCards: result.endingCards,

src/ai-prediction/middlewares/ai.validator.js

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export const validatePredictRequest = (req, res, next) => {
3535
* POST /api/ai/styles
3636
*/
3737
export const validateStyleRequest = (req, res, next) => {
38-
const { words, endingCards } = req.body;
38+
const { words, endingCards, tone } = req.body;
3939

4040
// 낱말 카드 검증
4141
if (!words || !Array.isArray(words) || words.length === 0) {
@@ -47,17 +47,31 @@ export const validateStyleRequest = (req, res, next) => {
4747
return next(new ValidationError('낱말 카드는 최대 10개까지 선택 가능합니다'));
4848
}
4949

50-
// 어미 선택 카드 검증 (배열, 1~5개)
51-
if (!endingCards || !Array.isArray(endingCards)) {
52-
return next(new ValidationError('어미 선택 카드를 최소 1개 이상 선택해주세요'));
50+
const hasTone = typeof tone === 'string' && tone.length > 0;
51+
const hasEndingCards = Array.isArray(endingCards);
52+
53+
// tone도 endingCards도 없으면 에러
54+
if (!hasTone && !hasEndingCards) {
55+
return next(new ValidationError('어미 선택 카드 또는 tone 중 하나는 반드시 제공해야 합니다'));
5356
}
5457

55-
if (endingCards.length === 0) {
56-
return next(new ValidationError('어미 선택 카드를 최소 1개 이상 선택해주세요'));
58+
// tone 값 검증 (있을 때만)
59+
if (hasTone) {
60+
const validTones = ['HONORIFIC', 'INFORMAL'];
61+
if (!validTones.includes(tone)) {
62+
return next(new ValidationError('tone은 HONORIFIC 또는 INFORMAL만 가능합니다'));
63+
}
5764
}
5865

59-
if (endingCards.length > 5) {
60-
return next(new ValidationError('어미 선택 카드는 최대 5개까지 선택 가능합니다'));
66+
// endingCards 검증 (있을 때만)
67+
if (hasEndingCards) {
68+
if (endingCards.length === 0) {
69+
return next(new ValidationError('어미 선택 카드를 최소 1개 이상 선택해주세요'));
70+
}
71+
72+
if (endingCards.length > 5) {
73+
return next(new ValidationError('어미 선택 카드는 최대 5개까지 선택 가능합니다'));
74+
}
6175
}
6276

6377
next();

src/ai-prediction/routes/ai.prediction.route.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ router.get('/contexts', authenticate, contextController);
297297
* /api/ai/styles:
298298
* post:
299299
* summary: 문장 스타일 변환
300-
* description: 낱말 카드 + 어미 카드를 조합하여 특정 스타일의 문장을 생성합니다. predictions와 동일한 Cache-First 전략을 사용합니다.
300+
* description: 낱말 카드 + 어미 카드를 조합하여 특정 스타일의 문장을 생성합니다. predictions와 동일한 Cache-First 전략을 사용합니다. `endingCards`, `tone` 중 `tone`이 우선 적용됩니다.
301301
* tags: [AI]
302302
* security:
303303
* - bearerAuth: []

0 commit comments

Comments
 (0)