Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package site.icebang.domain.workflow.mapper;

import java.util.Optional;

import org.apache.ibatis.annotations.Mapper;

import site.icebang.domain.workflow.model.TaskIoData;

@Mapper
public interface TaskIoDataMapper {
void insert(TaskIoData taskIoData);

Optional<TaskIoData> findOutputByTaskRunId(Long taskRunId);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package site.icebang.domain.workflow.mapper;

import java.util.Optional;

import org.apache.ibatis.annotations.Mapper;

import site.icebang.domain.workflow.model.TaskRun;
Expand All @@ -9,4 +11,6 @@ public interface TaskRunMapper {
void insert(TaskRun taskRun);

void update(TaskRun taskRun);

Optional<TaskRun> findLatestSuccessRunInJob(Long jobRunId, String taskName);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package site.icebang.domain.workflow.model;

import java.time.Instant;

import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
public class TaskIoData {
private Long id;
private Long taskRunId;
private String ioType;
private String name;
private String dataType;
private String dataValue; // JSON을 문자열로 저장
private Long dataSize;
private Instant createdAt;

public TaskIoData(
Long taskRunId,
String ioType,
String name,
String dataType,
String dataValue,
Long dataSize) {
this.taskRunId = taskRunId;
this.ioType = ioType;
this.name = name;
this.dataType = dataType;
this.dataValue = dataValue;
this.dataSize = dataSize;
this.createdAt = Instant.now();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package site.icebang.domain.workflow.runner.fastapi.body;

import java.util.Map;
import java.util.Optional;

import org.springframework.stereotype.Component;
Expand All @@ -11,13 +10,16 @@

import lombok.RequiredArgsConstructor;

import site.icebang.domain.workflow.model.JobRun;
import site.icebang.domain.workflow.model.Task;
import site.icebang.domain.workflow.service.WorkflowContextService;

@Component
@RequiredArgsConstructor
public class BlogPublishBodyBuilder implements TaskBodyBuilder {

private final ObjectMapper objectMapper;
private final WorkflowContextService contextService;
private static final String TASK_NAME = "블로그 발행 태스크";
private static final String RAG_SOURCE_TASK = "블로그 RAG 생성 태스크";

Expand All @@ -27,33 +29,40 @@ public boolean supports(String taskName) {
}

@Override
public ObjectNode build(Task task, Map<String, JsonNode> workflowContext) {
public ObjectNode build(Task task, JobRun jobRun) {
ObjectNode body = objectMapper.createObjectNode();

// RAG에서 생성된 블로그 콘텐츠 가져오기
Optional.ofNullable(workflowContext.get(RAG_SOURCE_TASK))
.ifPresent(
ragResult -> {
JsonNode data = ragResult.path("data");

// 제목, 내용, 태그 설정
Optional.ofNullable(data.path("title"))
.filter(node -> !node.isMissingNode())
.ifPresent(titleNode -> body.set("post_title", titleNode));

Optional.ofNullable(data.path("content"))
.filter(node -> !node.isMissingNode())
.ifPresent(contentNode -> body.set("post_content", contentNode));

Optional.ofNullable(data.path("tags"))
.filter(node -> !node.isMissingNode())
.ifPresent(tagsNode -> body.set("post_tags", tagsNode));
});
String blog_name = task.getSettings().path("blog_name").asText("");
body.put("tag", task.getSettings().get("tag").asText());
body.put("blog_name", blog_name);
body.put("blog_id", task.getSettings().get("blog_id").asText());
body.put("blog_pw", task.getSettings().get("blog_pw").asText());
Optional<JsonNode> ragResultOpt = contextService.getPreviousTaskOutput(jobRun, RAG_SOURCE_TASK);
ragResultOpt.ifPresent(
ragResult -> {
JsonNode data = ragResult.path("data");

// 📌 1. .path()로 노드를 가져옵니다.
JsonNode titleNode = data.path("title");
// 📌 2. .isMissingNode()로 노드가 존재하는지 확인합니다.
if (!titleNode.isMissingNode()) {
body.set("post_title", titleNode);
}

JsonNode contentNode = data.path("content");
if (!contentNode.isMissingNode()) {
body.set("post_content", contentNode);
}

JsonNode tagsNode = data.path("tags");
if (!tagsNode.isMissingNode()) {
body.set("post_tags", tagsNode);
}
});

Optional<JsonNode> settingsOpt = Optional.ofNullable(task.getSettings());
settingsOpt.ifPresent(
settings -> {
body.put("tag", settings.path("tag").asText());
body.put("blog_name", settings.path("blog_name").asText());
body.put("blog_id", settings.path("blog_id").asText());
body.put("blog_pw", settings.path("blog_pw").asText());
});

return body;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package site.icebang.domain.workflow.runner.fastapi.body;

import java.util.Map;
import java.util.Optional;

import org.springframework.stereotype.Component;
Expand All @@ -11,14 +10,19 @@

import lombok.RequiredArgsConstructor;

import site.icebang.domain.workflow.model.JobRun;
import site.icebang.domain.workflow.model.Task;
import site.icebang.domain.workflow.service.WorkflowContextService;

@Component
@RequiredArgsConstructor
public class BlogRagBodyBuilder implements TaskBodyBuilder {

private final ObjectMapper objectMapper;
private final WorkflowContextService contextService; // 📌 컨텍스트 서비스 주입
private static final String TASK_NAME = "블로그 RAG 생성 태스크";

// 📌 데이터 소스가 되는 이전 Task들의 이름
private static final String KEYWORD_SOURCE_TASK = "키워드 검색 태스크";
private static final String PRODUCT_SELECT_SOURCE_TASK = "상품 선택 태스크";
private static final String OCR_SOURCE_TASK = "이미지 OCR 태스크";
Expand All @@ -28,23 +32,35 @@ public boolean supports(String taskName) {
return TASK_NAME.equals(taskName);
}

/**
* 여러 이전 Task들의 결과를 DB에서 조회하고 조합하여 '블로그 RAG 생성'을 위한 Request Body를 생성합니다.
*
* @param task 실행할 Task의 도메인 모델
* @param jobRun 현재 실행 중인 Job의 기록 객체 (이전 Task 결과를 조회하는 키로 사용)
* @return 생성된 JSON Body
*/
@Override
public ObjectNode build(Task task, Map<String, JsonNode> workflowContext) {
public ObjectNode build(Task task, JobRun jobRun) {
ObjectNode body = objectMapper.createObjectNode();

// 키워드 정보 가져오기
Optional.ofNullable(workflowContext.get(KEYWORD_SOURCE_TASK))
// 1. '키워드 검색 태스크' 결과에서 키워드 정보 가져오기
Optional<JsonNode> keywordResult =
contextService.getPreviousTaskOutput(jobRun, KEYWORD_SOURCE_TASK);
keywordResult
.map(node -> node.path("data").path("keyword"))
.ifPresent(keywordNode -> body.set("keyword", keywordNode));

// OCR 번역 결과 가져오기 (새로 추가)
Optional.ofNullable(workflowContext.get(OCR_SOURCE_TASK))
// 2. '이미지 OCR 태스크' 결과에서 번역 언어 정보 가져오기
Optional<JsonNode> ocrResult = contextService.getPreviousTaskOutput(jobRun, OCR_SOURCE_TASK);
ocrResult
.map(node -> node.path("data").path("translation_language"))
.filter(node -> !node.isMissingNode() && !node.asText().trim().isEmpty())
.ifPresent(translationNode -> body.set("translation_language", translationNode));

// 선택된 상품 정보 가져오기
Optional.ofNullable(workflowContext.get(PRODUCT_SELECT_SOURCE_TASK))
// 3. '상품 선택 태스크' 결과에서 선택된 상품 정보 가져오기
Optional<JsonNode> productSelectResult =
contextService.getPreviousTaskOutput(jobRun, PRODUCT_SELECT_SOURCE_TASK);
productSelectResult
.map(node -> node.path("data").path("selected_product"))
.ifPresent(productNode -> body.set("product_info", productNode));

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package site.icebang.domain.workflow.runner.fastapi.body;

import java.util.Map;
import java.util.Optional;

import org.springframework.stereotype.Component;
Expand All @@ -11,28 +10,41 @@

import lombok.RequiredArgsConstructor;

import site.icebang.domain.workflow.model.JobRun;
import site.icebang.domain.workflow.model.Task;
import site.icebang.domain.workflow.service.WorkflowContextService;

@Component
@RequiredArgsConstructor
public class ImageOcrBodyBuilder implements TaskBodyBuilder {

private final ObjectMapper objectMapper;
private final WorkflowContextService contextService; // 📌 컨텍스트 서비스 주입
private static final String TASK_NAME = "이미지 OCR 태스크";
private static final String KEYWORD_SOURCE_TASK = "키워드 검색 태스크";
private static final String SOURCE_TASK_NAME = "키워드 검색 태스크";

@Override
public boolean supports(String taskName) {
return TASK_NAME.equals(taskName);
}

/**
* 이전 Task 결과(키워드)를 DB에서 조회하여 OCR Task의 Request Body를 생성합니다.
*
* @param task 실행할 Task의 도메인 모델
* @param jobRun 현재 실행 중인 Job의 기록 객체
* @return 생성된 JSON Body
*/
@Override
public ObjectNode build(Task task, Map<String, JsonNode> workflowContext) {
public ObjectNode build(Task task, JobRun jobRun) {
ObjectNode body = objectMapper.createObjectNode();

// 키워드 정보 가져오기 (OCR 처리용)
Optional.ofNullable(workflowContext.get(KEYWORD_SOURCE_TASK))
.map(node -> node.path("data").path("keyword"))
// 📌 컨텍스트 서비스를 통해 DB에서 '키워드 검색 태스크'의 결과를 조회합니다.
Optional<JsonNode> sourceResult =
contextService.getPreviousTaskOutput(jobRun, SOURCE_TASK_NAME);

sourceResult
.map(result -> result.path("data").path("keyword"))
.filter(node -> !node.isMissingNode() && !node.asText().trim().isEmpty())
.ifPresent(keywordNode -> body.set("keyword", keywordNode));

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
package site.icebang.domain.workflow.runner.fastapi.body;

import java.util.Map;
import java.util.Optional;

import org.springframework.stereotype.Component;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;

import lombok.RequiredArgsConstructor;

import site.icebang.domain.workflow.model.JobRun;
import site.icebang.domain.workflow.model.Task;

@Component
Expand All @@ -24,10 +24,22 @@ public boolean supports(String taskName) {
return TASK_NAME.equals(taskName);
}

/**
* Task에 주입된 사용자 정의 설정(settings)을 기반으로 Request Body를 생성합니다.
*
* @param task 실행할 Task의 도메인 모델 (settings 포함)
* @param jobRun 현재 실행 중인 Job의 기록 객체 (이 빌더에서는 사용되지 않음)
* @return 생성된 JSON Body (예: {"tag": "google"})
*/
@Override
public ObjectNode build(Task task, Map<String, JsonNode> workflowContext) {
// 이 Task는 항상 정적인 Body를 가집니다.
String tag = task.getSettings().get("tag").asText();
public ObjectNode build(Task task, JobRun jobRun) {
// 📌 Task에 동적으로 주입된 settings에서 'tag' 값을 가져옵니다.
// settings가 없거나 'tag' 필드가 없으면 기본값으로 "naver"를 사용합니다.
String tag =
Optional.ofNullable(task.getSettings())
.map(settings -> settings.path("tag").asText("naver"))
.orElse("naver");

return objectMapper.createObjectNode().put("tag", tag);
}
}
Loading
Loading