Skip to content

Commit

Permalink
Merge pull request #26 from 2024-2-3M1S/refact/#24-readme
Browse files Browse the repository at this point in the history
#24 [ Refact ] - Readme 생성 API
  • Loading branch information
bbabbi authored Dec 2, 2024
2 parents 22b8fef + 68c6b03 commit 77665f5
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,9 @@ public class ReadmeController {
private final UploadReadmeService uploadReadmeService;

@PostMapping("/generate")
public ResponseEntity<ReadmeResponse> generateAndSaveReadme(@RequestBody ReadmeRequest readmeRequest) {
log.info("Received request to generate and save README: {}", readmeRequest);
public ResponseEntity<ReadmeResponse> generateReadme(@RequestBody ReadmeRequest readmeRequest) {
try {
ReadmeResponse response = createReadmeService.generateAndSaveReadme(readmeRequest);
log.info("Generated and saved README: {}", response);
ReadmeResponse response = createReadmeService.generateReadme(readmeRequest);
return ResponseEntity.ok(response);
} catch (Exception e) {
log.error("Error while generating markdown", e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
public class ReadmeRequest {
private String title;
private String description;
private List<String> stack;
private List<String> teamMembers;
private List<TechStack> stack;
private List<TeamMember> teamMembers;
private String installation;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.autorepo.server.domain.readme.dto.request;

import lombok.Data;

@Data
public class TeamMember {
private String name;
private String position;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.autorepo.server.domain.readme.dto.request;

import lombok.Data;

@Data
public class TechStack {
private String name;
private String color;
private String icon;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

public record ReadmeResponse(
String title,
String content,
String imageUrl
String content
) {
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@

import lombok.RequiredArgsConstructor;
import org.autorepo.server.domain.readme.dto.request.ReadmeRequest;
import org.autorepo.server.domain.readme.dto.request.TechStack;
import org.autorepo.server.domain.readme.dto.request.TeamMember;
import org.autorepo.server.domain.readme.dto.response.ReadmeResponse;
import org.autorepo.server.domain.readme.entity.Readme;
import org.autorepo.server.domain.readme.repository.ReadmeRepository;
import org.autorepo.server.global.utils.MarkdownToImageConverter;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -16,46 +15,64 @@
@Transactional
public class CreateReadmeService {

private final MarkdownToImageConverter markdownToImageConverter;
private final ReadmeRepository readmeRepository;

public ReadmeResponse generateAndSaveReadme(ReadmeRequest readmeRequest) {
public ReadmeResponse generateReadme(ReadmeRequest readmeRequest) {
String markdown = generateMarkdown(readmeRequest);
String imageUrl = markdownToImageConverter.convertMarkdownToImage(markdown, readmeRequest.getTitle());
Readme readme = saveReadme(readmeRequest, markdown, imageUrl);
return new ReadmeResponse(readme.getTitle(), readme.getContent(), readme.getImageUrl());
}

private Readme saveReadme(ReadmeRequest readmeRequest, String markdown, String imageUrl) {
Readme readme = new Readme();
readme.setTitle(readmeRequest.getTitle());
readme.setContent(markdown);
readme.setImageUrl(imageUrl);
return readmeRepository.save(readme);
return new ReadmeResponse(readmeRequest.getTitle(), markdown);
}

public String generateMarkdown(ReadmeRequest readmeRequest) {
// 마크다운 생성 로직 (기존 코드 사용)
StringBuilder prompt = new StringBuilder();

prompt.append("# ").append(readmeRequest.getTitle()).append("\n");
prompt.append("프로젝트 설명: ").append(readmeRequest.getDescription()).append("\n\n");
// 제목과 설명
prompt.append("# 🩵").append(readmeRequest.getTitle()).append("\n");
prompt.append("**프로젝트 설명**: ").append(readmeRequest.getDescription()).append("\n\n");

// 소개 섹션
prompt.append("## 🚀 소개\n").append(readmeRequest.getDescription()).append("\n\n");
prompt.append("## 🛠️ 기술 스택\n").append(categorizeStack(readmeRequest.getStack())).append("\n");
prompt.append("## 💻 설치 방법\n").append(generateInstallationGuide(readmeRequest.getStack())).append("\n\n");
prompt.append("## 👥 팀원\n");
if (readmeRequest.getTeamMembers() != null && !readmeRequest.getTeamMembers().isEmpty()) {
for (String member : readmeRequest.getTeamMembers()) {
prompt.append("- ").append(member).append("\n");
}

// 기술 스택 섹션
if (readmeRequest.getStack() != null && !readmeRequest.getStack().isEmpty()) {
prompt.append("## 🛠️ 기술 스택\n");
prompt.append(generateTechStackSection(readmeRequest.getStack())).append("\n\n");
}

// 설치 방법 섹션
if (readmeRequest.getInstallation() != null && !readmeRequest.getInstallation().isEmpty()) {
prompt.append("## 💻 설치 방법\n").append(readmeRequest.getInstallation()).append("\n\n");
} else {
prompt.append("- 팀원 정보가 없습니다.\n");
prompt.append("## 💻 설치 방법\n").append(generateInstallationGuide(readmeRequest.getStack())).append("\n\n");
}

// 팀원 섹션
if (readmeRequest.getTeamMembers() != null && !readmeRequest.getTeamMembers().isEmpty()) {
prompt.append("## 👥 팀원\n").append(generateTeamMemberSection(readmeRequest.getTeamMembers())).append("\n");
}

return prompt.toString();
}

private String categorizeStack(List<String> techStack) {
// 기술 스택 분류 로직 (기존 코드 사용)
private String generateTechStackSection(List<TechStack> techStacks) {
StringBuilder section = new StringBuilder();

// 라벨 생성
for (TechStack stack : techStacks) {
String badgeUrl = getBadgeUrl(stack);
section.append(String.format("![%s](%s) ", stack.getName(), badgeUrl));
}
section.append("\n\n");

// 기술 스택 표 생성 (카테고리별 분류)
section.append(categorizeStack(techStacks));

return section.toString();
}

private String getBadgeUrl(TechStack stack) {
return String.format("https://img.shields.io/badge/%s-%s?style=for-the-badge&logo=%s&logoColor=white",
stack.getName().replace(" ", "%20"), stack.getColor(), stack.getIcon());
}

private String categorizeStack(List<TechStack> techStacks) {
Map<String, List<String>> categories = new HashMap<>();
categories.put("Front-end", Arrays.asList("React", "JavaScript", "TypeScript"));
categories.put("Back-end", Arrays.asList("SpringBoot", "Java", "Node.js", "Django"));
Expand All @@ -66,20 +83,21 @@ private String categorizeStack(List<String> techStack) {
Map<String, List<String>> categorizedStacks = new HashMap<>();
List<String> uncategorized = new ArrayList<>();

for (String tech : techStack) {
for (TechStack stack : techStacks) {
boolean categorized = false;
for (Map.Entry<String, List<String>> entry : categories.entrySet()) {
if (entry.getValue().contains(tech)) {
categorizedStacks.computeIfAbsent(entry.getKey(), k -> new ArrayList<>()).add(tech);
if (entry.getValue().contains(stack.getName())) {
categorizedStacks.computeIfAbsent(entry.getKey(), k -> new ArrayList<>()).add("`" + stack.getName() + "`");
categorized = true;
break;
}
}
if (!categorized) {
uncategorized.add(tech);
uncategorized.add("`" + stack.getName() + "`");
}
}

// 표 생성
StringBuilder table = new StringBuilder("| **Category** | **Stack** |\n|:------------:|:----------:|\n");
categorizedStacks.forEach((category, stacks) -> {
table.append("| ").append(category).append(" | ").append(String.join(", ", stacks)).append(" |\n");
Expand All @@ -92,31 +110,48 @@ private String categorizeStack(List<String> techStack) {
return table.toString();
}

private String generateInstallationGuide(List<String> techStack) {
private String generateInstallationGuide(List<TechStack> techStacks) {
StringBuilder guide = new StringBuilder();
if (techStack.contains("React")) {
guide.append(" 1. 의존성을 설치합니다:\n");
guide.append(" ```bash\n");
guide.append(" npm install\n");
guide.append(" ```\n");
guide.append(" 2. 애플리케이션을 시작합니다:\n");
guide.append(" ```bash\n");
guide.append(" npm start\n");
guide.append(" ```\n");
} else if (techStack.contains("SpringBoot")) {
guide.append(" 1. 빌드 도구로 프로젝트를 실행합니다:\n");
guide.append(" ```bash\n");
guide.append(" ./gradlew bootRun\n");
guide.append(" ```\n");
} else if (techStack.contains("Docker")) {
guide.append(" 1. Docker 이미지를 빌드하고 실행합니다:\n");
guide.append(" ```bash\n");
guide.append(" docker build -t 프로젝트명 .\n");
guide.append(" docker run -p 8080:8080 프로젝트명\n");
guide.append(" ```\n");

// 기술 스택 기반 설치 가이드 생성
if (techStacks.stream().anyMatch(stack -> stack.getName().equalsIgnoreCase("React"))) {
guide.append("1. 의존성을 설치합니다:\n");
guide.append(" ```bash\n");
guide.append(" npm install\n");
guide.append(" ```\n");
guide.append("2. 애플리케이션을 시작합니다:\n");
guide.append(" ```bash\n");
guide.append(" npm start\n");
guide.append(" ```\n");
} else if (techStacks.stream().anyMatch(stack -> stack.getName().equalsIgnoreCase("SpringBoot"))) {
guide.append("1. 빌드 도구로 프로젝트를 실행합니다:\n");
guide.append(" ```bash\n");
guide.append(" ./gradlew bootRun\n");
guide.append(" ```\n");
} else if (techStacks.stream().anyMatch(stack -> stack.getName().equalsIgnoreCase("Docker"))) {
guide.append("1. Docker 이미지를 빌드하고 실행합니다:\n");
guide.append(" ```bash\n");
guide.append(" docker build -t 프로젝트명 .\n");
guide.append(" docker run -p 8080:8080 프로젝트명\n");
guide.append(" ```\n");
} else {
guide.append(" - 설치 방법 정보가 제공되지 않았습니다.\n");
guide.append("- 설치 방법 정보가 제공되지 않았습니다.\n");
}

return guide.toString();
}

private String generateTeamMemberSection(List<TeamMember> teamMembers) {
StringBuilder section = new StringBuilder();

section.append("| **Name** | **Position** |\n");
section.append("|:--------:|:------------:|\n");

// 팀원 데이터
for (TeamMember member : teamMembers) {
section.append("| **").append(member.getName()).append("** | `").append(member.getPosition()).append("` |\n");
}

return section.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo
tokenService.saveRefreshToken(user.getUserId(), jwtRefreshToken);

// 클라이언트로 리다이렉트
String redirectUrl = "http://localhost:3000/oauth2/success?accessToken=" + jwtAccessToken + "&refreshToken=" + jwtRefreshToken;
String redirectUrl = "https://autorepo.dcs-seochan99.com/oauth2/success?accessToken=" + jwtAccessToken + "&refreshToken=" + jwtRefreshToken;
response.sendRedirect(redirectUrl);
}
}

0 comments on commit 77665f5

Please sign in to comment.