diff --git a/content-service-deployment.yaml b/content-service-deployment.yaml index 5223cbf..7b84cf2 100644 --- a/content-service-deployment.yaml +++ b/content-service-deployment.yaml @@ -17,7 +17,7 @@ spec: spec: containers: - name: content-service - image: acrdigitalgarage01.azurecr.io/kt-event-marketing/content-service:latest + image: acrdigitalgarage01.azurecr.io/content-service:latest imagePullPolicy: Always ports: - containerPort: 8084 @@ -41,21 +41,21 @@ spec: memory: 1024Mi startupProbe: httpGet: - path: /actuator/health + path: /api/v1/content/actuator/health port: 8084 initialDelaySeconds: 30 periodSeconds: 10 failureThreshold: 30 livenessProbe: httpGet: - path: /actuator/health/liveness + path: /api/v1/content/actuator/health/liveness port: 8084 initialDelaySeconds: 30 periodSeconds: 10 failureThreshold: 3 readinessProbe: httpGet: - path: /actuator/health/readiness + path: /api/v1/content/actuator/health/readiness port: 8084 initialDelaySeconds: 10 periodSeconds: 5 diff --git a/content-service-service.yaml b/content-service-service.yaml new file mode 100644 index 0000000..6249e7c --- /dev/null +++ b/content-service-service.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + name: content-service + namespace: kt-event-marketing + labels: + app: content-service +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 8084 + protocol: TCP + name: http + selector: + app: content-service diff --git a/content-service/Dockerfile b/content-service/Dockerfile new file mode 100644 index 0000000..9925cb3 --- /dev/null +++ b/content-service/Dockerfile @@ -0,0 +1,24 @@ +# Multi-stage build for Spring Boot application +FROM eclipse-temurin:21-jre-alpine AS builder +WORKDIR /app +COPY build/libs/*.jar app.jar +RUN java -Djarmode=layertools -jar app.jar extract + +FROM eclipse-temurin:21-jre-alpine +WORKDIR /app + +# Create non-root user +RUN addgroup -S spring && adduser -S spring -G spring +USER spring:spring + +# Copy layers from builder +COPY --from=builder /app/dependencies/ ./ +COPY --from=builder /app/spring-boot-loader/ ./ +COPY --from=builder /app/snapshot-dependencies/ ./ +COPY --from=builder /app/application/ ./ + +# Health check +HEALTHCHECK --interval=30s --timeout=3s --start-period=60s --retries=3 \ + CMD wget --no-verbose --tries=1 --spider http://localhost:8084/actuator/health || exit 1 + +ENTRYPOINT ["java", "org.springframework.boot.loader.launch.JarLauncher"] diff --git a/content-service/src/main/java/com/kt/event/content/biz/service/HuggingFaceImageGenerator.java b/content-service/src/main/java/com/kt/event/content/biz/service/HuggingFaceImageGenerator.java deleted file mode 100644 index 3a92e24..0000000 --- a/content-service/src/main/java/com/kt/event/content/biz/service/HuggingFaceImageGenerator.java +++ /dev/null @@ -1,289 +0,0 @@ -package com.kt.event.content.biz.service; - -import com.kt.event.content.biz.domain.Content; -import com.kt.event.content.biz.domain.GeneratedImage; -import com.kt.event.content.biz.domain.ImageStyle; -import com.kt.event.content.biz.domain.Job; -import com.kt.event.content.biz.domain.Platform; -import com.kt.event.content.biz.dto.ContentCommand; -import com.kt.event.content.biz.dto.JobInfo; -import com.kt.event.content.biz.dto.RedisJobData; -import com.kt.event.content.biz.usecase.in.GenerateImagesUseCase; -import com.kt.event.content.biz.usecase.out.CDNUploader; -import com.kt.event.content.biz.usecase.out.ContentWriter; -import com.kt.event.content.biz.usecase.out.JobWriter; -import com.kt.event.content.infra.gateway.client.HuggingFaceApiClient; -import com.kt.event.content.infra.gateway.client.dto.HuggingFaceRequest; -import io.github.resilience4j.circuitbreaker.CallNotPermittedException; -import io.github.resilience4j.circuitbreaker.CircuitBreaker; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.context.annotation.Primary; -import org.springframework.scheduling.annotation.Async; -import org.springframework.stereotype.Service; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -/** - * Hugging Face Inference API 이미지 생성 서비스 - * - * Hugging Face Inference API를 사용하여 Stable Diffusion으로 이미지 생성 (무료) - * - * @Profile("huggingface") - huggingface 프로파일에서만 활성화 - */ -@Slf4j -@Service -@org.springframework.context.annotation.Profile("huggingface") -public class HuggingFaceImageGenerator implements GenerateImagesUseCase { - - private final HuggingFaceApiClient huggingFaceClient; - private final CDNUploader cdnUploader; - private final JobWriter jobWriter; - private final ContentWriter contentWriter; - private final CircuitBreaker circuitBreaker; - - public HuggingFaceImageGenerator( - HuggingFaceApiClient huggingFaceClient, - CDNUploader cdnUploader, - JobWriter jobWriter, - ContentWriter contentWriter, - @Qualifier("huggingfaceCircuitBreaker") CircuitBreaker circuitBreaker) { - this.huggingFaceClient = huggingFaceClient; - this.cdnUploader = cdnUploader; - this.jobWriter = jobWriter; - this.contentWriter = contentWriter; - this.circuitBreaker = circuitBreaker; - } - - @Override - public JobInfo execute(ContentCommand.GenerateImages command) { - log.info("Hugging Face 이미지 생성 요청: eventId={}, styles={}, platforms={}", - command.getEventId(), command.getStyles(), command.getPlatforms()); - - // Job 생성 - String jobId = "job-" + UUID.randomUUID().toString().substring(0, 8); - - Job job = Job.builder() - .id(jobId) - .eventId(command.getEventId()) - .jobType("image-generation") - .status(Job.Status.PENDING) - .progress(0) - .createdAt(java.time.LocalDateTime.now()) - .updatedAt(java.time.LocalDateTime.now()) - .build(); - - // Job 저장 - RedisJobData jobData = RedisJobData.builder() - .id(job.getId()) - .eventId(job.getEventId()) - .jobType(job.getJobType()) - .status(job.getStatus().name()) - .progress(job.getProgress()) - .createdAt(job.getCreatedAt()) - .updatedAt(job.getUpdatedAt()) - .build(); - - jobWriter.saveJob(jobData, 3600); // TTL 1시간 - log.info("Job 생성 완료: jobId={}", jobId); - - // 비동기로 이미지 생성 - processImageGeneration(jobId, command); - - return JobInfo.from(job); - } - - @Async - private void processImageGeneration(String jobId, ContentCommand.GenerateImages command) { - try { - log.info("Hugging Face 이미지 생성 시작: jobId={}", jobId); - - // Content 생성 또는 조회 - Content content = Content.builder() - .eventId(command.getEventId()) - .eventTitle(command.getEventId() + " 이벤트") - .eventDescription("AI 생성 이벤트 이미지") - .createdAt(java.time.LocalDateTime.now()) - .updatedAt(java.time.LocalDateTime.now()) - .build(); - Content savedContent = contentWriter.save(content); - log.info("Content 생성 완료: contentId={}", savedContent.getId()); - - // 스타일 x 플랫폼 조합으로 이미지 생성 - List styles = command.getStyles() != null && !command.getStyles().isEmpty() - ? command.getStyles() - : List.of(ImageStyle.FANCY, ImageStyle.SIMPLE); - - List platforms = command.getPlatforms() != null && !command.getPlatforms().isEmpty() - ? command.getPlatforms() - : List.of(Platform.INSTAGRAM, Platform.KAKAO); - - List images = new ArrayList<>(); - int totalCount = styles.size() * platforms.size(); - int currentCount = 0; - - for (ImageStyle style : styles) { - for (Platform platform : platforms) { - currentCount++; - - // 진행률 업데이트 - int progress = (currentCount * 100) / totalCount; - jobWriter.updateJobStatus(jobId, "IN_PROGRESS", progress); - - // Hugging Face로 이미지 생성 - String prompt = buildPrompt(command, style, platform); - String imageUrl = generateImage(prompt, platform); - - // GeneratedImage 저장 - GeneratedImage image = GeneratedImage.builder() - .eventId(command.getEventId()) - .style(style) - .platform(platform) - .cdnUrl(imageUrl) - .prompt(prompt) - .selected(currentCount == 1) // 첫 번째 이미지를 선택 - .createdAt(java.time.LocalDateTime.now()) - .updatedAt(java.time.LocalDateTime.now()) - .build(); - - if (currentCount == 1) { - image.select(); - } - - GeneratedImage savedImage = contentWriter.saveImage(image); - images.add(savedImage); - log.info("이미지 생성 완료: imageId={}, style={}, platform={}, url={}", - savedImage.getId(), style, platform, imageUrl); - } - } - - // Job 완료 - String resultMessage = String.format("%d개의 이미지가 성공적으로 생성되었습니다.", images.size()); - jobWriter.updateJobStatus(jobId, "COMPLETED", 100); - jobWriter.updateJobResult(jobId, resultMessage); - log.info("Hugging Face Job 완료: jobId={}, 생성된 이미지 수={}", jobId, images.size()); - - } catch (Exception e) { - log.error("Hugging Face 이미지 생성 실패: jobId={}", jobId, e); - jobWriter.updateJobError(jobId, e.getMessage()); - } - } - - /** - * Hugging Face로 이미지 생성 - * - * @param prompt 이미지 생성 프롬프트 - * @param platform 플랫폼 (이미지 크기 결정) - * @return 생성된 이미지 URL - */ - private String generateImage(String prompt, Platform platform) { - try { - // 플랫폼별 이미지 크기 설정 - int width = platform.getWidth(); - int height = platform.getHeight(); - - // Hugging Face API 요청 - HuggingFaceRequest request = HuggingFaceRequest.builder() - .inputs(prompt) - .parameters(HuggingFaceRequest.Parameters.builder() - .negative_prompt("blurry, bad quality, distorted, ugly, low resolution") - .width(width) - .height(height) - .guidance_scale(7.5) - .num_inference_steps(50) - .build()) - .build(); - - log.info("Hugging Face API 호출: prompt={}, size={}x{}", prompt, width, height); - - // 이미지 생성 (동기 방식) - byte[] imageData = generateImageWithCircuitBreaker(request); - log.info("Hugging Face 이미지 생성 완료: size={} bytes", imageData.length); - - // Azure Blob Storage에 업로드 - String fileName = String.format("event-%s-%s-%s.png", - platform.name().toLowerCase(), - UUID.randomUUID().toString().substring(0, 8), - System.currentTimeMillis()); - String azureCdnUrl = cdnUploader.upload(imageData, fileName); - log.info("Azure CDN 업로드 완료: fileName={}, url={}", fileName, azureCdnUrl); - - return azureCdnUrl; - - } catch (Exception e) { - log.error("Hugging Face 이미지 생성 실패: prompt={}", prompt, e); - throw new RuntimeException("이미지 생성 실패: " + e.getMessage(), e); - } - } - - /** - * 이미지 생성 프롬프트 구성 - */ - private String buildPrompt(ContentCommand.GenerateImages command, ImageStyle style, Platform platform) { - StringBuilder prompt = new StringBuilder(); - - // 업종 정보 추가 - if (command.getIndustry() != null && !command.getIndustry().trim().isEmpty()) { - prompt.append(command.getIndustry()).append(" "); - } - - // 기본 프롬프트 - prompt.append("event promotion image"); - - // 지역 정보 추가 - if (command.getLocation() != null && !command.getLocation().trim().isEmpty()) { - prompt.append(" in ").append(command.getLocation()); - } - - // 트렌드 키워드 추가 (최대 3개) - if (command.getTrends() != null && !command.getTrends().isEmpty()) { - prompt.append(", featuring "); - int count = Math.min(3, command.getTrends().size()); - for (int i = 0; i < count; i++) { - if (i > 0) prompt.append(", "); - prompt.append(command.getTrends().get(i)); - } - } - - prompt.append(", "); - - // 스타일별 프롬프트 - switch (style) { - case FANCY: - prompt.append("elegant, luxurious, premium design, vibrant colors, "); - break; - case SIMPLE: - prompt.append("minimalist, clean design, simple layout, modern, "); - break; - case TRENDY: - prompt.append("trendy, contemporary, stylish, modern design, "); - break; - } - - // 플랫폼별 특성 추가 - prompt.append("optimized for ").append(platform.name().toLowerCase()).append(" platform, "); - prompt.append("high quality, detailed, 4k resolution"); - - return prompt.toString(); - } - - /** - * Circuit Breaker로 보호된 Hugging Face 이미지 생성 - * - * @param request Hugging Face 요청 - * @return 생성된 이미지 바이트 데이터 - */ - private byte[] generateImageWithCircuitBreaker(HuggingFaceRequest request) { - try { - return circuitBreaker.executeSupplier(() -> huggingFaceClient.generateImage(request)); - } catch (CallNotPermittedException e) { - log.error("Hugging Face Circuit Breaker가 OPEN 상태입니다. 이미지 생성 차단"); - throw new RuntimeException("Hugging Face API에 일시적으로 접근할 수 없습니다. 잠시 후 다시 시도해주세요.", e); - } catch (Exception e) { - log.error("Hugging Face 이미지 생성 실패", e); - throw new RuntimeException("이미지 생성 실패: " + e.getMessage(), e); - } - } -} diff --git a/content-service/src/main/java/com/kt/event/content/infra/ContentApplication.java b/content-service/src/main/java/com/kt/event/content/infra/ContentApplication.java index 31a8d57..3c6cbed 100644 --- a/content-service/src/main/java/com/kt/event/content/infra/ContentApplication.java +++ b/content-service/src/main/java/com/kt/event/content/infra/ContentApplication.java @@ -1,8 +1,13 @@ package com.kt.event.content.infra; +import com.kt.event.common.security.JwtAuthenticationFilter; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.FilterType; import org.springframework.scheduling.annotation.EnableAsync; /** @@ -13,6 +18,16 @@ import org.springframework.scheduling.annotation.EnableAsync; "com.kt.event.content", "com.kt.event.common" }) +@ComponentScan( + basePackages = { + "com.kt.event.content", + "com.kt.event.common" + }, + excludeFilters = @ComponentScan.Filter( + type = FilterType.ASSIGNABLE_TYPE, + classes = JwtAuthenticationFilter.class + ) +) @EnableAsync @EnableFeignClients(basePackages = "com.kt.event.content.infra.gateway.client") public class ContentApplication { diff --git a/content-service/src/main/java/com/kt/event/content/infra/config/Resilience4jConfig.java b/content-service/src/main/java/com/kt/event/content/infra/config/Resilience4jConfig.java index 93ec6a7..506a60f 100644 --- a/content-service/src/main/java/com/kt/event/content/infra/config/Resilience4jConfig.java +++ b/content-service/src/main/java/com/kt/event/content/infra/config/Resilience4jConfig.java @@ -12,7 +12,7 @@ import java.time.Duration; /** * Resilience4j Circuit Breaker 설정 * - * Hugging Face API, Replicate API 및 Azure Blob Storage에 대한 Circuit Breaker 패턴 적용 + * Replicate API 및 Azure Blob Storage에 대한 Circuit Breaker 패턴 적용 */ @Slf4j @Configuration @@ -89,40 +89,4 @@ public class Resilience4jConfig { return circuitBreaker; } - - /** - * Hugging Face API Circuit Breaker - * - * - 실패율 50% 이상 시 Open - * - 최소 3개 요청 후 평가 - * - Open 후 30초 대기 (Half-Open 전환) - * - Half-Open 상태에서 2개 요청으로 평가 - */ - @Bean - public CircuitBreaker huggingfaceCircuitBreaker() { - CircuitBreakerConfig config = CircuitBreakerConfig.custom() - .failureRateThreshold(50) // 실패율 50% 초과 시 Open - .slowCallRateThreshold(50) // 느린 호출 50% 초과 시 Open - .slowCallDurationThreshold(Duration.ofSeconds(60)) // 60초 이상 걸리면 느린 호출로 판단 - .waitDurationInOpenState(Duration.ofSeconds(30)) // Open 후 30초 대기 - .slidingWindowType(CircuitBreakerConfig.SlidingWindowType.COUNT_BASED) // 횟수 기반 평가 - .slidingWindowSize(10) // 최근 10개 요청 평가 - .minimumNumberOfCalls(3) // 최소 3개 요청 후 평가 - .permittedNumberOfCallsInHalfOpenState(2) // Half-Open에서 2개 요청으로 평가 - .automaticTransitionFromOpenToHalfOpenEnabled(true) // 자동 Half-Open 전환 - .build(); - - CircuitBreaker circuitBreaker = CircuitBreakerRegistry.of(config).circuitBreaker("huggingface"); - - // Circuit Breaker 이벤트 로깅 - circuitBreaker.getEventPublisher() - .onSuccess(event -> log.debug("Hugging Face Circuit Breaker: Success")) - .onError(event -> log.warn("Hugging Face Circuit Breaker: Error - {}", event.getThrowable().getMessage())) - .onStateTransition(event -> log.warn("Hugging Face Circuit Breaker: State transition from {} to {}", - event.getStateTransition().getFromState(), event.getStateTransition().getToState())) - .onSlowCallRateExceeded(event -> log.warn("Hugging Face Circuit Breaker: Slow call rate exceeded")) - .onFailureRateExceeded(event -> log.warn("Hugging Face Circuit Breaker: Failure rate exceeded")); - - return circuitBreaker; - } } diff --git a/content-service/src/main/java/com/kt/event/content/infra/config/SecurityConfig.java b/content-service/src/main/java/com/kt/event/content/infra/config/SecurityConfig.java index 9b78a69..23c002c 100644 --- a/content-service/src/main/java/com/kt/event/content/infra/config/SecurityConfig.java +++ b/content-service/src/main/java/com/kt/event/content/infra/config/SecurityConfig.java @@ -4,13 +4,14 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.web.SecurityFilterChain; /** * Spring Security 설정 - * API 테스트를 위해 일단 모든 요청 허용 (추후 JWT 인증 추가) + * API 테스트를 위해 일단 모든 요청 허용 */ @Configuration @EnableWebSecurity @@ -27,13 +28,20 @@ public class SecurityConfig { session.sessionCreationPolicy(SessionCreationPolicy.STATELESS) ) - // 모든 요청 허용 (테스트용, 추후 JWT 필터 추가 필요) + // 모든 요청 허용 (테스트용) .authorizeHttpRequests(auth -> auth - .requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll() - .requestMatchers("/actuator/**").permitAll() - .anyRequest().permitAll() // TODO: 추후 authenticated()로 변경 + .anyRequest().permitAll() ); return http.build(); } + + /** + * Chrome DevTools 요청 등 정적 리소스 요청을 Spring Security에서 제외 + */ + @Bean + public WebSecurityCustomizer webSecurityCustomizer() { + return (web) -> web.ignoring() + .requestMatchers("/.well-known/**"); + } } diff --git a/content-service/src/main/java/com/kt/event/content/infra/config/SwaggerConfig.java b/content-service/src/main/java/com/kt/event/content/infra/config/SwaggerConfig.java index 8a0f63a..38d2248 100644 --- a/content-service/src/main/java/com/kt/event/content/infra/config/SwaggerConfig.java +++ b/content-service/src/main/java/com/kt/event/content/infra/config/SwaggerConfig.java @@ -36,6 +36,9 @@ public class SwaggerConfig { ) ) .servers(List.of( + new Server() + .url("http://kt-event-marketing-api.20.214.196.128.nip.io/api/v1/content") + .description("VM Development Server"), new Server() .url("http://localhost:8084") .description("Local Development Server"), diff --git a/content-service/src/main/java/com/kt/event/content/infra/gateway/client/HuggingFaceApiClient.java b/content-service/src/main/java/com/kt/event/content/infra/gateway/client/HuggingFaceApiClient.java deleted file mode 100644 index 2e87a38..0000000 --- a/content-service/src/main/java/com/kt/event/content/infra/gateway/client/HuggingFaceApiClient.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.kt.event.content.infra.gateway.client; - -import com.kt.event.content.infra.gateway.client.dto.HuggingFaceRequest; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; -import org.springframework.stereotype.Component; -import org.springframework.web.client.RestClient; - -/** - * Hugging Face Inference API 클라이언트 - * - * API 문서: https://huggingface.co/docs/api-inference/index - * Stable Diffusion 모델: stabilityai/stable-diffusion-2-1 - */ -@Component -public class HuggingFaceApiClient { - - private final RestClient restClient; - - @Value("${huggingface.api.url:https://api-inference.huggingface.co}") - private String apiUrl; - - @Value("${huggingface.api.token:}") - private String apiToken; - - @Value("${huggingface.model:stabilityai/stable-diffusion-2-1}") - private String modelId; - - public HuggingFaceApiClient(RestClient.Builder restClientBuilder) { - this.restClient = restClientBuilder.build(); - } - - /** - * 이미지 생성 요청 (동기 방식) - * - * @param request Hugging Face 요청 - * @return 생성된 이미지 바이트 데이터 - */ - public byte[] generateImage(HuggingFaceRequest request) { - String url = String.format("%s/models/%s", apiUrl, modelId); - - return restClient.post() - .uri(url) - .header(HttpHeaders.AUTHORIZATION, "Bearer " + apiToken) - .contentType(MediaType.APPLICATION_JSON) - .body(request) - .retrieve() - .body(byte[].class); - } -} diff --git a/content-service/src/main/java/com/kt/event/content/infra/gateway/client/dto/HuggingFaceRequest.java b/content-service/src/main/java/com/kt/event/content/infra/gateway/client/dto/HuggingFaceRequest.java deleted file mode 100644 index 94827c8..0000000 --- a/content-service/src/main/java/com/kt/event/content/infra/gateway/client/dto/HuggingFaceRequest.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.kt.event.content.infra.gateway.client.dto; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; - -/** - * Hugging Face Inference API 요청 DTO - * - * API 문서: https://huggingface.co/docs/api-inference/index - */ -@Getter -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class HuggingFaceRequest { - - /** - * 이미지 생성 프롬프트 - */ - private String inputs; - - /** - * 생성 파라미터 - */ - private Parameters parameters; - - @Getter - @Builder - @NoArgsConstructor - @AllArgsConstructor - public static class Parameters { - /** - * Negative prompt (생성하지 않을 내용) - */ - private String negative_prompt; - - /** - * 이미지 너비 - */ - private Integer width; - - /** - * 이미지 높이 - */ - private Integer height; - - /** - * Guidance scale (프롬프트 준수 정도, 기본: 7.5) - */ - private Double guidance_scale; - - /** - * Inference steps (품질, 기본: 50) - */ - private Integer num_inference_steps; - } -} diff --git a/content-service/src/main/java/com/kt/event/content/infra/web/controller/ContentController.java b/content-service/src/main/java/com/kt/event/content/infra/web/controller/ContentController.java index cca9f30..4bde7ce 100644 --- a/content-service/src/main/java/com/kt/event/content/infra/web/controller/ContentController.java +++ b/content-service/src/main/java/com/kt/event/content/infra/web/controller/ContentController.java @@ -31,7 +31,7 @@ import java.util.List; */ @Slf4j @RestController -@RequestMapping("/api/v1/content") +@RequestMapping @RequiredArgsConstructor public class ContentController { diff --git a/content-service/src/main/resources/application.yml b/content-service/src/main/resources/application.yml index a115a4b..1ff0b87 100644 --- a/content-service/src/main/resources/application.yml +++ b/content-service/src/main/resources/application.yml @@ -38,13 +38,6 @@ replicate: model: version: ${REPLICATE_MODEL_VERSION:stability-ai/sdxl:39ed52f2a78e934b3ba6e2a89f5b1c712de7dfea535525255b1aa35c5565e08b} -# HuggingFace API Configuration -huggingface: - api: - url: ${HUGGINGFACE_API_URL:https://api-inference.huggingface.co} - token: ${HUGGINGFACE_API_TOKEN:} - model: ${HUGGINGFACE_MODEL:runwayml/stable-diffusion-v1-5} - # CORS Configuration cors: allowed-origins: ${CORS_ALLOWED_ORIGINS:http://localhost:*} @@ -96,3 +89,5 @@ logging: # Server Configuration server: port: ${SERVER_PORT:8084} + servlet: + context-path: /api/v1/content