Event Service API 통합 및 AI 추천 조회 로직 개선

- eventApi에 getAiRecommendations 메서드 추가
- Job COMPLETED 시 Event Service의 공개 API로 추천 결과 조회
- AI Service Internal API 대신 Event Service API 사용
- 타입 정의 통합 및 중복 제거
- 환경변수 포트 설정 수정 (AI_HOST: 8083)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
박세원 2025-10-30 20:03:42 +09:00
parent e3f1e2e3c7
commit 86ae038a31
3 changed files with 92 additions and 81 deletions

View File

@ -19,7 +19,8 @@ import {
Alert, Alert,
} from '@mui/material'; } from '@mui/material';
import { ArrowBack, Edit, Insights } from '@mui/icons-material'; import { ArrowBack, Edit, Insights } from '@mui/icons-material';
import { aiApi, eventApi, AIRecommendationResult, EventRecommendation } from '@/shared/api'; import { eventApi } from '@/shared/api';
import type { AiRecommendationResult, EventRecommendation } from '@/shared/api/eventApi';
// 디자인 시스템 색상 // 디자인 시스템 색상
const colors = { const colors = {
@ -82,7 +83,7 @@ export default function RecommendationStep({
const [polling, setPolling] = useState(false); const [polling, setPolling] = useState(false);
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
const [aiResult, setAiResult] = useState<AIRecommendationResult | null>(null); const [aiResult, setAiResult] = useState<AiRecommendationResult | null>(null);
const [selected, setSelected] = useState<number | null>(null); const [selected, setSelected] = useState<number | null>(null);
const [editedData, setEditedData] = useState<Record<number, { title: string; description: string }>>({}); const [editedData, setEditedData] = useState<Record<number, { title: string; description: string }>>({});
@ -206,8 +207,8 @@ export default function RecommendationStep({
console.log('✅ Job 상태:', status); console.log('✅ Job 상태:', status);
if (status.status === 'COMPLETED') { if (status.status === 'COMPLETED') {
// AI 추천 결과 조회 // AI 추천 결과 조회 (Event Service API 사용)
const recommendations = await aiApi.getRecommendations(evtId); const recommendations = await eventApi.getAiRecommendations(evtId);
setAiResult(recommendations); setAiResult(recommendations);
setLoading(false); setLoading(false);
setPolling(false); setPolling(false);

View File

@ -56,78 +56,7 @@ aiApiClient.interceptors.response.use(
} }
); );
// Types // Types (eventApi.ts로 이동됨 - import해서 사용)
export interface TrendKeyword {
keyword: string;
relevance: number;
description: string;
}
export interface TrendAnalysis {
industryTrends: TrendKeyword[];
regionalTrends: TrendKeyword[];
seasonalTrends: TrendKeyword[];
}
export interface ExpectedMetrics {
newCustomers: {
min: number;
max: number;
};
repeatVisits?: {
min: number;
max: number;
};
revenueIncrease: {
min: number;
max: number;
};
roi: {
min: number;
max: number;
};
socialEngagement?: {
estimatedPosts: number;
estimatedReach: number;
};
}
export interface EventRecommendation {
optionNumber: number;
concept: string;
title: string;
description: string;
targetAudience: string;
duration: {
recommendedDays: number;
recommendedPeriod?: string;
};
mechanics: {
type: 'DISCOUNT' | 'GIFT' | 'STAMP' | 'EXPERIENCE' | 'LOTTERY' | 'COMBO';
details: string;
};
promotionChannels: string[];
estimatedCost: {
min: number;
max: number;
breakdown?: {
material?: number;
promotion?: number;
discount?: number;
};
};
expectedMetrics: ExpectedMetrics;
differentiator: string;
}
export interface AIRecommendationResult {
eventId: string;
trendAnalysis: TrendAnalysis;
recommendations: EventRecommendation[];
generatedAt: string;
expiresAt: string;
aiProvider: 'CLAUDE' | 'GPT4';
}
export interface JobStatusResponse { export interface JobStatusResponse {
jobId: string; jobId: string;
@ -170,11 +99,11 @@ export const aiApi = {
return response.data; return response.data;
}, },
// AI 추천 결과 조회 (Internal API) // AI 추천 결과 조회 (Internal API) - Deprecated: eventApi.getAiRecommendations 사용
getRecommendations: async (eventId: string): Promise<AIRecommendationResult> => { // getRecommendations: async (eventId: string): Promise<AiRecommendationResult> => {
const response = await aiApiClient.get<AIRecommendationResult>(`/internal/recommendations/${eventId}`); // const response = await aiApiClient.get<AiRecommendationResult>(`/internal/recommendations/${eventId}`);
return response.data; // return response.data;
}, // },
}; };
export default aiApi; export default aiApi;

View File

@ -111,6 +111,78 @@ export interface EventJobStatusResponse {
completedAt?: string; completedAt?: string;
} }
export interface TrendKeyword {
keyword: string;
relevance: number;
description: string;
}
export interface TrendAnalysis {
industryTrends: TrendKeyword[];
regionalTrends: TrendKeyword[];
seasonalTrends: TrendKeyword[];
}
export interface ExpectedMetrics {
newCustomers: {
min: number;
max: number;
};
repeatVisits?: {
min: number;
max: number;
};
revenueIncrease: {
min: number;
max: number;
};
roi: {
min: number;
max: number;
};
socialEngagement?: {
estimatedPosts: number;
estimatedReach: number;
};
}
export interface EventRecommendation {
optionNumber: number;
concept: string;
title: string;
description: string;
targetAudience: string;
duration: {
recommendedDays: number;
recommendedPeriod?: string;
};
mechanics: {
type: 'DISCOUNT' | 'GIFT' | 'STAMP' | 'EXPERIENCE' | 'LOTTERY' | 'COMBO';
details: string;
};
promotionChannels: string[];
estimatedCost: {
min: number;
max: number;
breakdown?: {
material?: number;
promotion?: number;
discount?: number;
};
};
expectedMetrics: ExpectedMetrics;
differentiator: string;
}
export interface AiRecommendationResult {
eventId: string;
trendAnalysis: TrendAnalysis;
recommendations: EventRecommendation[];
generatedAt: string;
expiresAt?: string;
aiProvider: 'CLAUDE' | 'GPT4';
}
export interface SelectRecommendationRequest { export interface SelectRecommendationRequest {
recommendationId: string; recommendationId: string;
customizations?: { customizations?: {
@ -262,6 +334,15 @@ export const eventApi = {
return response.data; return response.data;
}, },
// AI 추천 결과 조회 (Job COMPLETED 후)
getAiRecommendations: async (eventId: string): Promise<AiRecommendationResult> => {
const response = await eventApiClient.get<AiRecommendationResult>(
`/events/${eventId}/ai-recommendations`
);
console.log('✅ AI 추천 결과 조회:', response.data);
return response.data;
},
// AI 추천 선택 // AI 추천 선택
selectRecommendation: async ( selectRecommendation: async (
eventId: string, eventId: string,