1+ package kb_hack .backend .domain .openAI .service ;
2+
3+ import kb_hack .backend .domain .announce .Announce ;
4+ import kb_hack .backend .domain .announce .mapper .AnnounceMapper ;
5+ import kb_hack .backend .domain .business .BusinessPlus ;
6+ import kb_hack .backend .domain .business .mapper .BusinessMapper ;
7+ import lombok .RequiredArgsConstructor ;
8+ import lombok .extern .slf4j .Slf4j ;
9+ import org .springframework .stereotype .Service ;
10+ import reactor .core .publisher .Flux ;
11+ import reactor .core .publisher .Mono ;
12+ import reactor .util .retry .Retry ;
13+
14+ import java .time .Duration ;
15+ import java .util .ArrayList ;
16+ import java .util .List ;
17+ import java .util .stream .Collectors ;
18+
19+ @ Slf4j
20+ @ Service
21+ @ RequiredArgsConstructor
22+ public class AiRecommendationService {
23+
24+ private final AiService openAiService ;
25+ private final BusinessMapper businessMapper ; // 사업장 정보
26+ private final AnnounceMapper announceMapper ; // 전체 공고 목록
27+
28+ // DB 조회
29+ public Announce recommendAnnounce (Long memberId ){
30+ BusinessPlus userBusiness = businessMapper .findBusinessAndClassInfoByMemberId (memberId )
31+ .orElseThrow (() -> new IllegalArgumentException ("사용자 사업장 정보를 찾을 수 없습니다." ));
32+
33+ List <Announce > activeAnnouncements = announceMapper .findAll ();
34+
35+ String businessInfo = String .format (
36+ "사용자 사업장 : %s , %s" ,
37+ userBusiness .getBusinessNm (),
38+ userBusiness .getBusinessAddr ()
39+ );
40+
41+ String announcesInfo = activeAnnouncements .stream ()
42+ .map (a -> {
43+ // DB 데이터가 길기 때문에, 공고 설명을 HTML 제거 후 50자 이내로 요약
44+ String plainDesc = a .getDescription ().replaceAll ("<[^>]*>" , "" ).replaceAll ("\\ s+" , " " ).trim ();
45+ if (plainDesc .length () > 50 ) {
46+ plainDesc = plainDesc .substring (0 , 50 ) + "..." ;
47+ }
48+ return String .format ("ID:%d, 제목:%s, 요약설명:%s" , a .getAnnounceId (), a .getAnnounceTitle (), plainDesc );
49+ })
50+ .collect (Collectors .joining ("\n " ));
51+ log .info (announcesInfo );
52+
53+ String aiPrompt = String .join ("\n " ,
54+ "사업장 정보" , businessInfo ,
55+ " 지원사업 목록 " , announcesInfo
56+ );
57+
58+ String recommendedIdString = openAiService .getAiResponseId (aiPrompt );
59+
60+ // 4. 최종 ID로 DB에서 공고 객체 조회 및 반환
61+ if (recommendedIdString != null ) {
62+ try {
63+ Long finalId = Long .parseLong (recommendedIdString .trim ());
64+ return announceMapper .findById2 (finalId ) // 최종 공고 조회
65+ .orElse (null );
66+ } catch (NumberFormatException e ) {
67+ log .error ("AI 응답이 유효한 ID 숫자가 아닙니다: {}" , recommendedIdString , e );
68+ }
69+ }
70+
71+ return null ;
72+ }
73+ }
0 commit comments