66import com .jobdri .jobdri_api .domain .jobposting .dto .response .JobPostingAsyncStatusResponse ;
77import com .jobdri .jobdri_api .domain .jobposting .dto .response .JobPostingAsyncSubmitResponse ;
88import com .jobdri .jobdri_api .domain .jobposting .dto .response .JobPostingExtractResponse ;
9- import com .jobdri .jobdri_api .domain .jobposting .dto .response .JobPostingIngestResponse ;
109import com .jobdri .jobdri_api .domain .jobposting .service .JobPostingAiService ;
1110import com .jobdri .jobdri_api .domain .jobposting .service .JobPostingAsyncFacadeService ;
12- import com .jobdri .jobdri_api .domain .jobposting .service .JobPostingIngestService ;
1311import com .jobdri .jobdri_api .domain .user .service .UserService ;
1412import com .jobdri .jobdri_api .global .apiPayload .ApiResponse ;
1513import com .jobdri .jobdri_api .global .security .UserDetailsImpl ;
3836public class JobPostingAiController {
3937
4038 private final JobPostingAiService jobPostingAiService ;
41- private final JobPostingIngestService jobPostingIngestService ;
4239 private final JobPostingAsyncFacadeService jobPostingAsyncFacadeService ;
4340 private final UserService userService ;
4441
@@ -75,123 +72,25 @@ public ApiResponse<JobPostingExtractResponse> extractJobPostingFromMultipart(
7572 }
7673
7774 @ Operation (
78- summary = "채용 공고 추출부터 분류, 생성, 저장까지 일괄 처리" ,
79- description = "이미지 또는 텍스트 공고를 추출하고, trigram 후보 검색과 AI 재분류를 거쳐 최종 소분류를 선택한 뒤 공고를 생성하고 저장합니다 ."
75+ summary = "채용 공고 비동기 일괄 처리 접수 " ,
76+ description = "이미지 또는 텍스트 공고를 비동기로 추출, 분류, 생성, 저장합니다. 응답으로 받은 taskId로 상태를 조회할 수 있습니다 ."
8077 )
8178 @ ApiResponses (value = {
8279 @ io .swagger .v3 .oas .annotations .responses .ApiResponse (
8380 responseCode = "200" ,
84- description = "분류 confidence가 충분하여 저장까지 완료된 경우" ,
81+ description = "비동기 작업이 정상 접수된 경우" ,
8582 content = @ Content (
8683 mediaType = "application/json" ,
8784 schema = @ Schema (implementation = ApiResponse .class ),
8885 examples = @ ExampleObject (value = """
8986 {
9087 "isSuccess": true,
9188 "code": "COMMON2000",
92- "message": "채용 공고 추출 및 저장에 성공했습니다.",
89+ "message": "채용 공고 비동기 작업 접수에 성공했습니다.",
9390 "result": {
94- "savedToDatabase": true,
95- "message": "채용 공고 추출 및 저장에 성공했습니다.",
96- "extracted": {
97- "companyName": "삼성전자",
98- "jobTitle": "백엔드 개발자",
99- "task": "백엔드 서비스 개발 및 운영",
100- "requirements": "Java/Spring 기반 개발 경험",
101- "preferredQualifications": "대용량 트래픽 처리 경험",
102- "rawText": "채용 공고 원문 내용",
103- "confidence": 0.92
104- },
105- "candidates": [
106- {
107- "detailClassificationId": 101,
108- "detailClassificationName": "Java/Spring",
109- "middleClassificationName": "백엔드",
110- "bigClassificationName": "개발",
111- "score": 0.91
112- }
113- ],
114- "classification": {
115- "detailClassificationId": 101,
116- "detailClassificationName": "Java/Spring",
117- "middleClassificationName": "백엔드",
118- "bigClassificationName": "개발",
119- "reason": "Spring Boot, JPA, API 개발 맥락이 가장 강합니다.",
120- "confidence": 0.87
121- },
122- "generated": {
123- "companyName": "삼성전자",
124- "jobTitle": "Java/Spring 백엔드 개발자",
125- "task": "백엔드 서비스 개발 및 운영\\ nAPI 설계 및 성능 개선",
126- "requirements": "Java/Spring 기반 개발 경험\\ nRDB 사용 경험",
127- "preferredQualifications": "대용량 트래픽 처리 경험\\ nRedis 사용 경험",
128- "summary": "서비스 백엔드 개발과 운영을 담당할 인재를 찾습니다."
129- },
130- "saved": {
131- "jobPostingId": 10,
132- "companyId": 3,
133- "companyName": "삼성전자",
134- "detailClassificationId": 101,
135- "detailClassificationName": "Java/Spring",
136- "task": "백엔드 서비스 개발 및 운영\\ nAPI 설계 및 성능 개선",
137- "requirement": "Java/Spring 기반 개발 경험\\ nRDB 사용 경험",
138- "preferred": "대용량 트래픽 처리 경험\\ nRedis 사용 경험"
139- }
140- },
141- "error": null
142- }
143- """ )
144- )
145- ),
146- @ io .swagger .v3 .oas .annotations .responses .ApiResponse (
147- responseCode = "200" ,
148- description = "분류 confidence가 낮아 저장을 보류한 경우" ,
149- content = @ Content (
150- mediaType = "application/json" ,
151- schema = @ Schema (implementation = ApiResponse .class ),
152- examples = @ ExampleObject (value = """
153- {
154- "isSuccess": true,
155- "code": "COMMON2000",
156- "message": "채용 공고 추출 및 저장에 성공했습니다.",
157- "result": {
158- "savedToDatabase": false,
159- "message": "소분류 분류 confidence가 낮아 저장을 보류했습니다.",
160- "extracted": {
161- "companyName": "어떤회사",
162- "jobTitle": "개발자",
163- "task": "서비스 개발",
164- "requirements": "개발 경험",
165- "preferredQualifications": "우대 사항",
166- "rawText": "채용 공고 원문 내용",
167- "confidence": 0.79
168- },
169- "candidates": [
170- {
171- "detailClassificationId": 101,
172- "detailClassificationName": "Java/Spring",
173- "middleClassificationName": "백엔드",
174- "bigClassificationName": "개발",
175- "score": 0.62
176- },
177- {
178- "detailClassificationId": 102,
179- "detailClassificationName": "Node.js",
180- "middleClassificationName": "백엔드",
181- "bigClassificationName": "개발",
182- "score": 0.58
183- }
184- ],
185- "classification": {
186- "detailClassificationId": 101,
187- "detailClassificationName": "Java/Spring",
188- "middleClassificationName": "백엔드",
189- "bigClassificationName": "개발",
190- "reason": "후보 간 차이가 크지 않습니다.",
191- "confidence": 0.49
192- },
193- "generated": null,
194- "saved": null
91+ "taskId": "f7f4eac0-b241-4d40-bf39-5b10c8a53943",
92+ "status": "PENDING",
93+ "message": "채용 공고 비동기 작업이 접수되었습니다."
19594 },
19695 "error": null
19796 }
@@ -200,23 +99,7 @@ public ApiResponse<JobPostingExtractResponse> extractJobPostingFromMultipart(
20099 )
201100 })
202101 @ PostMapping (value = "/ingest" , consumes = MediaType .MULTIPART_FORM_DATA_VALUE )
203- public ApiResponse <JobPostingIngestResponse > ingestJobPosting (
204- @ AuthenticationPrincipal UserDetailsImpl userDetails ,
205- @ ModelAttribute JobPostingIngestMultipartRequest request
206- ) {
207- var user = validateAuthenticatedUser (userDetails );
208- return ApiResponse .onSuccess (
209- "채용 공고 추출 및 저장에 성공했습니다." ,
210- jobPostingIngestService .ingestAndCreate (user , request )
211- );
212- }
213-
214- @ Operation (
215- summary = "채용 공고 비동기 일괄 처리 접수" ,
216- description = "이미지 또는 텍스트 공고를 비동기로 추출, 분류, 생성, 저장합니다. 응답으로 받은 taskId로 상태를 조회할 수 있습니다."
217- )
218- @ PostMapping (value = "/ingest/async" , consumes = MediaType .MULTIPART_FORM_DATA_VALUE )
219- public ApiResponse <JobPostingAsyncSubmitResponse > submitIngestJobPostingAsync (
102+ public ApiResponse <JobPostingAsyncSubmitResponse > ingestJobPosting (
220103 @ AuthenticationPrincipal UserDetailsImpl userDetails ,
221104 @ ModelAttribute JobPostingIngestMultipartRequest request
222105 ) {
0 commit comments