Skip to content

Commit

Permalink
Merge pull request #54 from SproutMJ/develop
Browse files Browse the repository at this point in the history
수정사항 적용
  • Loading branch information
SproutMJ authored May 31, 2024
2 parents 0b34914 + 901dfea commit a280a41
Show file tree
Hide file tree
Showing 11 changed files with 151 additions and 21 deletions.
2 changes: 2 additions & 0 deletions backend/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ dependencies {
implementation 'org.hibernate.validator:hibernate-validator-cdi:6.2.0.Final'

implementation 'io.github.flashvayne:chatgpt-spring-boot-starter:1.0.4'

implementation 'org.jsoup:jsoup:1.15.3'
}

tasks.named('test') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ public enum ChatType {
menu,
ingredient,
recipe,
imageUrl,
link
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package hello.aimju.controller;

import hello.aimju.image.Crawling.Service.CrawlingService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;

@RestController
@RequiredArgsConstructor
@RequestMapping(value = "/api")
public class CrawlingController {

private final CrawlingService crawlingService;

@GetMapping("/menu-image/{query}")
public String fetchImage(@PathVariable("query") String query) {
try {
return crawlingService.fetchImageUrl(query);
} catch (IOException e) {
e.printStackTrace();
return "Error: Unable to fetch image";
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package hello.aimju.image.Crawling.Service;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

@Service
public class CrawlingService {

public String fetchImageUrl(String query) throws IOException {
// 쿼리 인코딩
String encodedQuery = URLEncoder.encode(query, StandardCharsets.UTF_8.toString());
System.out.println("Original query: " + query);
System.out.println("Encoded query: " + encodedQuery);

// URL 생성
String url = "https://www.10000recipe.com/recipe/list.html?q=" + encodedQuery;
System.out.println("URL: " + url);

// 페이지 가져오기
Document doc = Jsoup.connect(url)
.userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36")
.get();
System.out.println("Document fetched");

// 이미지 URL 추출
Element imgElement = doc.select("div.common_sp_thumb img").first();
if (imgElement != null) {
String imageUrl = imgElement.attr("src");
System.out.println("Image URL: " + imageUrl);
return imageUrl;
} else {
System.out.println("No image element found");
return null;
}
}
}
42 changes: 33 additions & 9 deletions frontend/src/app/boards/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@ type Board = {
export default function Board() {
const [currentPage, setCurrentPage] = useState(0);
const [totalPages, setTotalPages] = useState(0);
const [searchKeyword, setSearchKeyword] = useState(null);
const [boards, setBoards] = useState<Board[]>([]);
const {getState} = useUserStore;
const ownBoard = useBoardStore((state) => state.ownBoard);
const [searchKeyword, setSearchKeyword] = useState<string>('');

const getBoards = async (page = 0, searchKeyword = null)=>{
const getBoards = async (page = 0)=>{
try {
let response;
if(searchKeyword === null){
if(searchKeyword === ''){
response = await axios.get('/api/boards', {
params: {
page: page,
Expand Down Expand Up @@ -76,10 +76,10 @@ export default function Board() {
}
};

const getOwnBoards = async (page = 0, searchKeyword = null) => {
const getOwnBoards = async (page = 0) => {
try {
let response;
if (searchKeyword === null) {
if (searchKeyword === '') {
response = await axios.get('/api/boards/current-user', {
params: {
page: page,
Expand Down Expand Up @@ -119,26 +119,50 @@ export default function Board() {

const handlePrevPage = () => {
if (ownBoard === 1) {
getOwnBoards(currentPage - 1, searchKeyword);
getOwnBoards(currentPage - 1);
} else {
getBoards(currentPage - 1, searchKeyword);
getBoards(currentPage - 1);
}
setCurrentPage(currentPage - 1);
}

const handleNextPage = () => {
if (ownBoard === 1) {
getOwnBoards(currentPage + 1, searchKeyword);
getOwnBoards(currentPage + 1);
} else {
getBoards(currentPage + 1, searchKeyword);
getBoards(currentPage + 1);
}
setCurrentPage(currentPage + 1);
}

const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setSearchKeyword(e.target.value);
};

return (
<>
<Header></Header>
<main className="py-8">
<form onSubmit={(event)=>{
event.preventDefault()
if (ownBoard === 1) {
getOwnBoards();
} else {
getBoards();
}
}} className="mb-6 flex items-center justify-center">
<input
type="text"
value={searchKeyword}
onChange={handleSearchChange}
placeholder="검색어를 입력하세요"
className="border border-gray-300 rounded px-4 py-2 mr-2 flex-grow"
style={{ maxWidth: '300px', color: 'black' }}
/>
<Button type="submit" className="flex-shrink-0">
검색
</Button>
</form>
<div className="container mx-auto px-4">
<div className="grid grid-cols-1 gap-6">
{boards.map((board, index)=>(
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/app/boards/writing/[recipeId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ export default function PostWriting({ params }: { params: { recipeId: number } }
const [selectedRecipe, setSelectedRecipe] = useState<number | null>(null); // 선택된 레시피 ID

useEffect(() => {
if (params.recipeId !== 0) {
const recipeId = Number(params.recipeId);
if (recipeId !== 0) {
console.log(params.recipeId);
const fetchRecipeContent = async () => {
try {
const response = await axios.get(`/api/recipe/${params.recipeId}`);
Expand Down
24 changes: 15 additions & 9 deletions frontend/src/app/chatroom/[chatroomId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,17 @@ export default function ChatRoom({ params }: { params: { chatroomId: number } })
...message,
content: `<a href="${message.content}" target="_blank" rel="noopener noreferrer" style="text-decoration: underline; color: #007bff;">${menuString} 검색하기</a>`
};
} else if (message.chatType === "imageUrl") {
return {
...message,
content: `<img src="${message.content}" alt="Chat Image" className="rounded-lg" />`
};
} else {
return message;
}
});

setChatMessages(messagesWithLinks);

})
.catch(error => {
alert('비정상적인 접근입니다.');
Expand All @@ -86,22 +91,23 @@ export default function ChatRoom({ params }: { params: { chatroomId: number } })
<Card className="flex flex-col">
<CardContent className="flex-1 space-y-4">
{chatMessages.map((message, index) => (
<div key={index} className={`flex items-start space-x-4 ${message.isUser === 0 ? 'justify-end' : ''}`}>
<div key={index} className={`flex items-start space-x-4 ${message.isUser === 1 ? 'justify-end' : ''}`}>
{message.isUser !== 1 && (
<Avatar>
<AvatarImage alt="@maxleiter" src="/placeholder-avatar.jpg" />
<AvatarFallback>ML</AvatarFallback>
</Avatar>
)}
<div className="flex flex-col space-y-2">
<div className="rounded-lg bg-gray-100 p-4 dark:bg-gray-800" dangerouslySetInnerHTML={{ __html: message.content }} />
<div className="rounded-lg bg-gray-100 p-4 dark:bg-gray-800"
dangerouslySetInnerHTML={{ __html: message.content }}/>
</div>
{message.isUser === 1 && (
<Avatar>
<AvatarImage alt="@you" src="/placeholder-avatar.jpg" />
<AvatarFallback>YU</AvatarFallback>
</Avatar>
)}
{message.isUser !== 1 && (
<Avatar>
<AvatarImage alt="@maxleiter" src="/placeholder-avatar.jpg" />
<AvatarFallback>ML</AvatarFallback>
</Avatar>
)}
</div>
))}
<div className="flex justify-center mt-4 space-x-4">
Expand Down
Binary file removed frontend/src/app/favicon.ico
Binary file not shown.
Binary file added frontend/src/app/favicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 5 additions & 2 deletions frontend/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ import "./globals.css";
const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
title: "AI 명종원",
description: "당신의 재료로 레시피를 추천합니다.",
icons: {
icon: "/favicon.png",
},
};

export default function RootLayout({
Expand Down
25 changes: 25 additions & 0 deletions frontend/src/app/recommend/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ export default function Recommend() {
const [uploadButtonEnabled, setUploadButtonEnabled] = useState(true);
const [yesOrNoButtonEnabled, setYesOrNoButtonEnabled] = useState(true);
const [recipeButtonEnabled, setRecipeButtonEnabled] = useState(true);
const [imageUrl, setImageUrl] = useState('');


const router = useRouter();
const handleRoutingMain = () => {
Expand Down Expand Up @@ -103,6 +105,17 @@ export default function Recommend() {
menu: menu,
ingredients: middleIngredients.split(', '),
};

try {
const routingPoint = '/api/menu-image/' + menu
console.log(routingPoint)
const response = await axios.get(routingPoint); // menu 값 사용
const imageUrl = response.data;
setImageUrl(imageUrl);
console.log(imageUrl);
} catch (error) {
console.error('Error fetching image:', error);
}
try {
const response = await axios.post('/api/recommendation-recipe-str', request);
setRecipeString(response.data);
Expand Down Expand Up @@ -140,6 +153,9 @@ export default function Recommend() {
addChatMessage(`해당 재료로 만들 수 있는 음식은 다음과 같습니다.\n${menus}\n어떤 재료의 음식의 레시피를 보시겠습니까?`, 0, 'message');
addChatMessage(`${menu}`, 1, 'menu');
addChatMessage(`${menu}의 레시피는 다음과 같습니다.`, 0, 'message');
if (imageUrl !== null && imageUrl !== undefined) {
addChatMessage(imageUrl, 0, 'imageUrl');
}
addChatMessage(`${recipeString}`, 0, 'recipe');
addChatMessage(`${recipeLink}`, 0,'link');
}, [recipeLink]);
Expand Down Expand Up @@ -403,6 +419,15 @@ export default function Recommend() {
</Avatar>
<div className="flex flex-col space-y-2">
<div className="rounded-lg bg-gray-100 p-4 dark:bg-gray-800" style={{ whiteSpace: 'pre-line' }}>
{imageUrl && (
<div className="flex items-start space-x-4">
<div className="rounded-lg bg-gray-100 p-4 dark:bg-gray-800">
<div>
<img src={imageUrl} alt="My Image"/>
</div>
</div>
</div>
)}
<p>{menu}의 레시피는 다음과 같습니다.</p>
<p>{recipeString}</p>
</div>
Expand Down

0 comments on commit a280a41

Please sign in to comment.