읽기 설정
마지막으로, 저희가 입력한 2D 파일을 바탕으로 3D AI 디자인을 생성할 때가 되었습니다.
그래서 저희는 lib 내에서 그렇게 처리할 수 있고, 실제로 그 안에 새로운 파일을 만들고 싶습니다. 그 파일의 이름은...
ai.action.ts 파일은 2D 평면도를 이용해서 3D 디자인을 생성하는 내용만 담고 있을 거예요.
PewterDocs 안으로 다시 들어가 보면 pewter.ai.textToImage 함수가 있다는 것을 알 수 있습니다.
프롬프트를 기반으로 AI를 사용하여 이미지를 생성하는 거예요. 이미 내장되어 있죠. 프롬프트와 몇 가지 옵션만 전달하면 돼요.
입력 이미지를 자세히 살펴보시면, 이미지-이미지 생성 과정에서 base64로 인코딩된 이미지 입력이 필요하다는 것을 알 수 있습니다.
이미지를 호스팅했으니, 이제 AI 모델에 전달하기 전에 base64로 변환해야 합니다.
그렇게 하기 위해서는 URL을 입력받아 AI를 사용하여 Base64 문자열로 변환하는 새로운 함수를 만들 수 있습니다.
저니에게 또 다른 좋은 기회가 주어지네요. 라이브러리 AI에서 fetch라는 이름의 TypeScript 함수를 작성하도록 지시할 수 있겠습니다.
URL 문자열을 받아 promise 문자열을 반환하는 action TS입니다. 먼저 fetch를 사용하여 이미지를 가져온 후, 오류를 발생시킵니다.
응답에 실패할 경우 오류가 발생할 수 있습니다.
그럼, 아래 텍스트를 자연스러운 한국어로 번역해 드리겠습니다. (헤여체로요.) 그리고 응답을 블롭으로 변환한 다음, 새로운...
파일 리더를 사용하여 Blob을 데이터 URL로 읽고, 성공적으로 결과를 반환하거나 오류 발생 시 거부하는 Promise에 대해 설명드리겠습니다. 어떻게 작동하는지 살펴보겠습니다.
이 코드는 AI 액션에서 데이터를 가져오는 URL 내에 구현되어야 합니다. 저희는 해당 URL을 가져옵니다.
응답이 없을 경우, 오류를 발생시키기만 하면 됩니다. 하지만 응답이 있다면, 이미지의 블롭 버전을 불러와 파일로 읽은 후 반환해 주시면 됩니다.
이것만으로도 저희는 'export const generate 3D view'라는 새로운 함수를 만들 수 있을 텐데요, 이 함수에서 추출했던 파일을 사용할 겁니다.
이것은 비동기 함수가 될 것이며, 생성된 3D 뷰 파라미터 유형의 소스 이미지를 입력으로 받아 새로운 함수 블록을 반환하게 됩니다. 여기에서 데이터 URL을 가져올 수 있으며, 이는 다음과 같을 것입니다.
소스 이미지의 시작이 이런 데이터 문자열로 이루어진 경우라면, 그냥 반환해도 괜찮습니다.
원본 이미지가 없는 경우, 데이터 URL로 가져온 후 전달할 수 있습니다. 그렇게 하면 데이터 파일 형식으로 이미지를 확보할 수 있습니다.
그러면 이 Base64 데이터를 분리해서 필요한 것만 추출할 수 있습니다. 데이터 URL을 쉼표로 분리하고, 두 번째 부분만 가져오고, 상수 MIME 타입을 정의하겠습니다.
그렇게 하면 필요한 부분만 추출할 수 있습니다. 데이터 URL을 쉼표로 분리해서 두 번째 부분을 가져오고, MIME 타입 상수를 설정합니다.
데이터 URL을 다루는데, 점(.)으로 분리한 후, 세미콜론(;)으로 다시 분리할 계획입니다. 세미콜론으로 분리했을 때 나오는 첫 번째 부분을 가져온 다음, 콜론(:)으로 또 다시 분리하여 두 번째 부분을 추출할 예정입니다.
이것은 이미지의 유형을 알려주는 역할을 할 것입니다. 만약 MIME 타입이나 base64 데이터 중 어느 것 하나라도 없다면, 즉 MIME 타입이 없거나 base64 데이터가 없는 경우를 말씀드리는 것입니다.
그렇다면, 저희는 '잘못된 소스 이미지 페이로드'와 같은 내용의 오류를 발생시키는 것이 적절할 것 같습니다.
하지만 이 소스 이미지를 적절하게 추출했다면, await pewter.ai.text2image를 호출하여 응답을 생성할 수 있습니다.
여기서 봤던 그 함수입니다. 물론 pewter를 가져와야 하는데, hey pewter slash pewter.js에서 가져온 것입니다.
그리고 나서 여기에 보시는 것과 동일한 옵션들을 전달할 수 있습니다.
물론, 먼저 제공자를 선택해야 합니다. 이 경우에는 여러 제공자 중에서 gemini가 가장 잘 작동하는 것 같았습니다. 그리고 모델을 선택할 수 있는데, 이 경우에는 gemini 2.5 플래시 이미지 미리보기로 선택하겠습니다.
입력 이미지인 base64 데이터도 전달해야 하고, 입력 이미지 유형도 전달해야 합니다. 이렇게 생겼고, 이렇게 될 겁니다.
방금 추출했던 타입으로 설정할 수 있습니다. 비율도 함께 전달할 수 있는데, 이 경우에는 너비 124, 높이 124로 설정할 수 있습니다.
이렇게 생겼습니다. 이제 텍스트-이미지 변환 과정에서 오류가 발생하지 않아야 합니다. 필요한 모든 정보들을 전달했기 때문입니다.
그런데 이 경우에는 제가 이걸 잘못 썼어요. 실제로는 txt to img 이렇게 되는 거에요.
그리고 필요한 첫 번째 파라미터는 여기에서 확인할 수도 있는데, 프롬프트이고 그 다음에 옵션이 되는 거에요.
방을 만들 때 사용하고 있는 프롬프트는 저희 상수(constants)에서 가져온 것입니다. 이제 명령(command) 모드를 실행하여 클릭하시면 현재 사용 중인 프롬프트를 정확히 확인하실 수 있습니다. 바로 이 프롬프트입니다.
이전에 살펴본 내용과 관련하여, 이 프롬프트를 더 발전시켜 더 나은 결과를 얻을 수도 있습니다. 하지만 텍스트 입력란 아래에 여전히 빨간색 물결선이 표시되는 것을 볼 수 있는데, 이는 데이터 형식이 일치하지 않음을 의미합니다.
입력 이미지가 문자열 배열로 받아지고 있다고 말하고 있는데, 그냥 문자열 하나여야 한다고 합니다.
그게 의미하는 건, 여기에서 제대로 분리하지 않았다는 뜻이고, 제가 이 부분을 분리 밖으로 빼지 않고 안에 넣었기 때문입니다.
그렇게 하면 이제 올바른 base64 데이터가 제대로 얻어질 겁니다.
네, 좋습니다. 이제 응답에서 받은 원본 이미지 URL을 HTML 이미지 요소의 src 속성으로 가져올 수 있겠네요.
만약 존재하지 않는다면, null 값으로 설정할 수도 있습니다.
그렇다면 원본 이미지 URL에 접근할 수 없는 경우에는 오류를 발생시키지 않고, 렌더링된 이미지 세트를 null로, 렌더링된 경로를 undefined로 반환하는 방법을 사용할 수 있습니다.
만약 원본 이미지 URL을 가지고 있다면, 'const renderedImage는 raw image URL.startsWith'라고 말하면서 실제로 그것을 반환할 수 있습니다.
만약 데이터가 이와 같은 형태로 시작한다면, 그럴 경우 이 원본 이미지 URL을 그대로 반환해도 괜찮을 것 같습니다.
아니면 fetch를 데이터 URL로 기다렸다가 여기 이 raw 이미지 URL을 전달할 수도 있습니다. 어쨌든 렌더링된 이미지를 제대로 반환하고 있습니다.
이제 렌더링된 이미지와 렌더링된 경로로 구성된 객체를 반환할 수 있습니다. 당분간 경로는 정의되지 않은 상태로 두겠습니다.
이제 시각화기 내에서 generate3dView 함수를 호출하여 생성된 결과를 표시할 수 있습니다.
자, app routes visualizer 폴더로 들어가 보겠습니다. 그리고 React router에서 제공하는 navigate 함수도 여기 위에 location과 함께 가져다 써서 필요하면 홈으로 다시 돌아갈 수 있도록 해 볼게요.
그리고 hasInitialGenerated라는 단일 ref를 만들어야 합니다. 이 ref는 useRef를 사용하여 초기에는 false로 설정될 것입니다.
그렇게 하면 추가적인 사용 상태를 더할 수 있을 겁니다. 사용 상태 스니펫을 처리하고, 그리고 '처리 중' 상태로 설정하는 과정이 될 것입니다.
물론 시작 값은 false로 설정해야 하고, React에서 useState를 가져와서 사용해야 합니다. 그리고 현재 이미지에 대해서도 동일한 작업을 수행하기 위해 current image라는 새로운 useState 스니펫을 만들 수 있습니다.
그리고 현재 이미지를 설정하는데, 이 이미지는 홈 페이지에서 프로젝트를 업로드할 때 상태를 통해 접근할 수 있는 초기 렌더링으로 설정할 수 있습니다.
초기 렌더링은 여기서 들어오게 됩니다.
아직 없을 경우에는 null로 설정할 수 있습니다. 그러면 이 상태는 문자열 상태이거나 null일 수 있습니다.
혹시 뒤로 돌아가고 싶을 경우, 이 핸들 백 기능으로 간단히 홈페이지로 돌아갈 수 있습니다.
그리고 가장 중요한 기능은 '런 제너레이션(run generation)'이라는 이름으로 불릴 것이며, 이는 비동기 함수가 될 예정입니다.
초기 이미지에 접근할 수 있는지 확인하게 될 거예요. 접근할 수 없다면, 그냥 종료하게 될 겁니다.
하지만, 그렇다면 3D 뷰를 생성해 볼 수 있습니다. 자, try 블록 안에서 is processing을 true로 설정하겠습니다.
인공지능 생성에는 시간이 소요되므로, 로딩 화면과 같은 무언가를 표시할 수 있도록 하겠습니다.
그리고 나서 저희는 생성된 3D 뷰 함수, 즉 방금 전에 이 AI 파일에서 만들었던 generate3dview 함수에서 그 결과를 추출해 보려고 할 것입니다. 그리고 그 함수에 원본 이미지 세트를 전달할 수 있습니다.
여기 초기 이미지로 전달해 줍니다. 그리고 결과 렌더링 이미지 값을 다시 받으면, 여기에서 결과 렌더링 이미지를 현재 이미지 상태로 설정할 수 있습니다.
결과 렌더링 이미지를 여기에서 현재 이미지 상태로 설정할 수 있습니다.
네, 이미지 확보되면 데이터베이스 내 프로젝트 정보도 렌더링된 이미지와 함께 업데이트해야 합니다. 생각해보시면, 키-값 쌍 데이터베이스 내 프로젝트 정보는 데이터만 가지고 있으니까요.
초기 프로젝트 이름, ID, 그리고 초기 층도에 대해서도 알아봐야 합니다. 하지만 지금 이 새로운 이미지가 있으므로 업데이트해야 할 것이고, 당장은 여기 새로운 try-catch 블록을 생성해 보겠습니다.
오류가 발생했습니다. 간단히 console.error로 '생성 실패'라고 출력한 후, 실제 오류 내용을 표시할 수 있습니다. 또한, 실패 시 처리를 'false'로 설정하기 위해 finally 블록을 사용할 수도 있습니다.
성공했는지 실패했는지 확인하고, 바로 아래에 변경 사항을 추적하기 위한 새로운 유즈 이펙트를 만들겠습니다. 즉, 초기 이미지만 가지고 있든 초기 렌더링이 완료되었든 상관없이, 저희는...
현재 상태가 어떤지 알고 있습니다. 따라서 초기 이미지가 없고 초기 생성된 점도 없을 경우, 현재는 사실이 아닙니다. 이 경우, 해당 use effect에서 빠져나갈 것입니다.
다른 방법으로는, 초기 렌더링을 진행한 후에 현재 이미지를 바로 상태에 설정하여 표시할 수 있습니다. 그리고 이 참조를 업데이트하면서 초기 생성이 완료되었음을 나타낼 수 있습니다.
true로 설정하고 여기서 빠져나올 겁니다. 밖에서 has initial generated를 true로 설정하고 생성 과정을 실행할 수도 있습니다. 이 반환에서 promise가 실제로 사용되지 않는다는 의미입니다.
그리고 적어도 지금은, 그게 크게 중요하지 않기 때문입니다. 우리가 해야 했던 것은 3D 뷰를 만들어서 상태에 설정하는 것뿐이었습니다.
반환 값은 필요 없습니다. 이제 시각화 도구를 표시하기 시작할 수 있어요. 그리고, 이 프로젝트 이름을 상단에서 제거할게요.
이제 시각화 컴포넌트로 다시 돌아가서 시각화 쪽으로 가보겠습니다. 그리고 여기 있는 기존 ID 중 하나를 선택할 거예요.
지금 어플리케이션이 작동을 멈추는 것 같아요. 왜 그런지 알아봅시다. 콘솔을 열어보니 내용이 비어 있는 것 같습니다.
아마 다른 시각화 도구를 한번 살펴봐야 할 것 같아요. 661로 끝나는 건 말고. 662를 한번 해볼까요? 아니, 이 것도 비어 있네요.
마지막 하나는 어떻게 되나요? 6.112입니다.
이것도 안에 아무것도 렌더링되지 않네요. 오류는 없는데, 'test'라고만 말씀하시면 'test' 키워드가 바로 여기에서 보일 거예요. 그러면 정상 작동하는 거니까, 이 부분은 제거하도록 하겠습니다.
그리고 시각화 클래스를 가진 div만 유지하도록 해 봅시다. 그리고 적절하게 들여쓰기를 할게요. 초기와 업데이트된 생성을 표시할 겁니다.
먼저, 이 안에 네브게이션을 추가할 수 있습니다. 이 네브게이션은 top bar라는 클래스 이름을 가질 겁니다. 그리고, 여기 초기 이미지는 제거할게요. 새로 개발 중인 UI로 시작하니까요.
이 탑 바 안에서 저희 브랜딩을 보여줄 디브를 렌더링할 거예요. 그리고 아마도 홈페이지나 내비바 컴포넌트 안에서 이미 사용했을 거예요.
여기서 이 박스와 아래에 있는 'Roomify'라고 쓰여진 스팬에 접근하고 싶습니다. 그리고 이걸 이 div 안에 붙여넣을 수 있습니다. 이 div는 'brand'라는 클래스 이름을 갖게 됩니다.
그리고 그 안에 로고가 있는 박스와, 'name'이라는 클래스 이름을 가진 span 태그로 'Roomify'라고 표시합니다. 그런 다음, 이 div 바로 아래, 브랜드 아래에 버튼을 표시할 수 있습니다.
저희가 재사용 가능한 버튼 컴포넌트가 있습니다. 그 버튼은 고스트 스타일로, 작은 크기로 설정되어 있고, 클릭 시에는 단순히 뒤로 가기 기능을 수행하도록 처리할 예정입니다.
그래서 저희는 다시 돌아갈 수 있습니다. 그리고 저는 'exit'라는 클래스 이름을 부여하고, 그 안에 lucid react에서 가져온 x 아이콘을 클래스와 함께 표시할 수 있습니다.
아이콘 이름과 함께 '편집기 종료'라고 표시될 것입니다. 자, 이제 이렇게 나타날 거예요. 이것은 추가적인 내용입니다.
홈페이지 상단에 팝업이 나타나도록 설정하여 언제든지 팝업을 닫고 다시 홈페이지로 돌아갈 수 있습니다. 이제 탐색 표시줄 아래로 내려가 다른 섹션을 렌더링하겠습니다. 이 섹션은 클래스 이름을 가질 것입니다.
내용 안에 panel 클래스 이름을 가진 또 다른 div가 포함될 것입니다.
안에 패널 메타가 있을 거예요, 하지만 이것은 실제로 패널 헤더 안에 들어가게 됩니다.
여기서 프로젝트라고 적힌 P 태그를 가질 수도 있습니다.
그리고 이 모든 것들은 패널 클래스를 가진 div 안에 들어가게 됩니다. 그래서 패널이 있고, 그 안에 패널 헤더가 있죠.
나중에 패널 동작들도 진행할 예정입니다.
네, 잘 됐습니다. 이제 프로젝트를 가지고 있습니다. 임시로 제목이 없는 프로젝트에 대한 가짜 데이터를 렌더링 할 수 있습니다. 나중에 수정하면 됩니다.
그리고 note라는 클래스 이름을 가진 PTAG도 있는데, 이걸 당신이 만들었다고 표시할 거예요.
그리고 나서 이 div 아래로 내려가서 패널 액션에 대한 또 다른 div를 렌더링할 수 있을 거예요. 패널 헤더 안에 계속 있을 거고요.
패널 동작이라는 클래스 이름을 부여하신 다음, 그 안에 다음과 같은 모양의 버튼을 표시해 주시면 됩니다.
사이즈는 S로 할 예정입니다. 당분간은 클릭 이벤트는 비워두고, 클래스 이름은 'export'로 지정하겠습니다.
현재 이미지 데이터가 없을 경우 비활성화될 예정이며, 그 안에서 다운로드 아이콘을 표시하고 바로 아래에 또 다른 것을 표시할 수 있습니다.
이 버튼은 작은 크기를 가지며, 공유 아이콘 2개를 포함할 것입니다. 당분간은 클릭 이벤트는 비워두겠습니다. 나중에 함께 기능을 구현할 예정이니까요. 그리고요.
지금 공유 텍스트를 표시하고, 이 버튼 아래로 두 개의 div를 배치할 수 있습니다. 그리고 그 div들은 패널 헤더 아래에 위치하며, 지금까지 가지고 있는 이미지를 표시할 수 있는 공간이 됩니다.
렌더-에어리어라는 클래스 이름을 가진 div 요소를 렌더링한 다음, 처리 중일 경우에...
만약 그렇다면, isProcessing 클래스 이름을 적용하고, 그렇지 않다면 클래스를 아무것도 주지 않겠습니다. 그리고 현재 이미지가 존재한다면, 그럴 경우 이미지 컴포넌트를 렌더링하게 될 겁니다.
현재 이미지의 소스, 그리고 AI 렌더링이라는 대체 텍스트, 그리고 render-img 클래스 이름을 가진 이미지입니다.
하지만 현재 이미지가 없다면, 초기 이미지 같은 것을 표시할 거예요.
이제 렌더링할 div 요소를 만들고 닫은 다음, 클래스 이름을 'render placeholder'로 지정하겠습니다.
그것은 저희가 초기 이미지에 접근할 수 있는지 확인하는 과정입니다. 접근 가능하다면, 초기 이미지의 소스를 나타내는 이미지 태그와 '원래'라는 대체 텍스트를 표시할 것입니다.
렌더링 대체 클래스 이름은 'render-fallback'입니다.
현재는 아직 아무것도 보이지 않으실 겁니다. 왜냐하면 이 프로젝트에서는 AI 이미지를 아직 생성하지 않았기 때문입니다. 그리고 바로 아래, 이 div 아래와 이미지 확인하는 부분 아래에는 'isProcessing' 부분을 표시하고 싶습니다.
만약 현재 이 AI 이미지를 처리하고 있다면, 이 경우 덧씌워질 수 있는 일종의 오버레이를 렌더링하고 싶습니다.
네, 여기 이 div를 닫고 render-overlay라는 클래스 이름을 부여하고, rendering-card라는 클래스 이름을 가진 또 다른 div를 만들겠습니다.
그리고 그 안에 리프레시-ccv 아이콘이 있는데, 이 아이콘은 스피너 클래스 이름을 갖게 됩니다. 그 안에서 우리는 타이틀 클래스 이름을 갖는 스팬을 렌더링할 수 있습니다.
그리고 렌더링 점 점 점이라고 표시될 거예요.
그리고 이 스팬을 아래에 복제해서, 자막이라고 변경할게요.
3D 시각화가 생성되는 내용이 표시될 거예요. 네, 좋습니다. 이제 홈페이지로 돌아가서 새로운 층도면을 업로드하면서 처음부터 모든 것을 테스트해 봐야겠네요.
저기요, generate3DView 함수가 있다는 걸 잊지 마세요. 이 함수는 기존 이미지를 가져올 겁니다. 저희가 Pewter에 입력한 프롬프트를 가져와서 선택한 모델에 대입해서 3D 층간도를 출력할 거예요.
자 한번 해보죠. 마지막으로 이 이미지를 업로드하기 위해 전체 화면으로 브라우저를 열어볼 가치가 있다고 생각해요. 그리고 3D 시각화를 렌더링하거나 생성하는 것을 볼 수 있을 거예요.
와, 정말 멋진데요. 이렇게 멋진 프로젝트를 만드신 거군요! 배경에 흐릿하게 보이는 이미지도 눈에 띄고, 혹시 저기 한번 살펴보시겠어요?
이것이 최종 결과물입니다. 이전 결과물은 지루한 2D 이미지였지만, 이제 AI가 가구까지 포함한 완벽한 평면도를 생성했습니다. 누군가 이 가구들을 구매해서 배치하면 바로 사용할 수 있을 것입니다.
침대는 여기 있고, 붙박이장과 협탁 두 개가 있습니다. 부엌에는 가스레인지, 싱크대, 냉장고가 있으며, 여기에는 식탁도 놓여 있습니다. 지금은 처음 모습이 어떻게 생겼는지 아마 잊어버리셨을 겁니다. 그리고 여기서는 그 모습을 보여드리지 않습니다.
걱정 마세요. 나중에 전후 보기 기능을 구현할 예정이니, 마우스를 드래그해서 실시간으로 차이점을 확인하실 수 있을 겁니다.
하지만 그렇다는 점을 염두에 두고, 믿기 어렵겠지만, 이것이 전부입니다. 저희는 텍스트나 이미지를 AI 모델에 입력했더니 최종 렌더링된 이미지를 얻었지만, 그 과정에서 저희는
제미니, 오픈에이아이, 또는 어떠한 데이터베이스나 인증 솔루션을 실제로 생성한 적이 없기 때문에, 이 경우에는 피터가 저희의 완전한 백엔드를 대체하여 인증 기능을 수행하고 있습니다.
AI 제공업체들이 키-값 저장 방식, 그리고 다양한 API들을 모두 하나의 도구에서 사용할 수 있도록 데이터베이스를 제공합니다. 이 도구는 신용카드 정보 입력 없이 이용하실 수 있으며, 앞으로도 그러할 것입니다.
코드를 작성하시면 작동합니다. 그것은 사용자분들께도 도움이 됩니다.
자, 이제 이 이미지를 마우스 오른쪽 버튼으로 클릭하여 새 탭으로 열어보시면, 실제 배포된 URL이 아니라는 것을 알 수 있습니다. 데이터 블롭 형태로, 'data:'라는 텍스트로 시작하고, 그 뒤에 base64로 인코딩된 이미지 데이터가 포함되어 있습니다.
그러면 페이지를 새로 고치시면 사라지게 됩니다.
다시 재구성될 예정입니다. 따라서 다음 강의에서는 이 AI가 생성한 이미지를 주석(pewter) 사이트의 서브도메인에 호스팅하고, 이 프로젝트 정보를 키-값 데이터베이스에도 저장해야 합니다.
다음 수업에서 다루도록 하겠습니다만, 우선 이 새로운 기능, 즉 3D 디자인을 생성하는 부분에 대해서는 지금 바로 풀 리퀘스트를 진행해 보겠습니다.
예상치 못하게 이전 지점에 그대로 남아있게 되었네요. 이곳이 이미지를 호스팅할 지점이 될 예정인데, 괜찮습니다.
사실 저희가 지금도 그걸 작업하고 있는 중이에요. 이 새로운 이미지를 호스팅하는 것도 원하고 있답니다.
그럼 이제 git add dot git commit dash m generate 3d design을 실행하고, git push도 실행해 볼게요.
자, 이제 다시 깃허브로 돌아와서 보니 최근에 풀 리퀘스트가 열렸네요. 한번 살펴볼까요? 이번에는 이 AI 코드를 사용했으니, 최적화가 잘 되어 있고 제대로 작동하는지 확인해야 할 것 같습니다.
다행히 코드래빗을 통해 확인해 볼 수 있어서 감사합니다. 코드래빗은 검토 및 확인 라이선스를 보유하고 있습니다.
이번 강의에서는 드디어 새로운 AI 기반 3D 시각화 기능을 추가했습니다. 작동 방식은 사용자가 시각화 컴포넌트를 확인하고, useEffect 훅이 이를 확인한 다음, 3D 뷰를 생성하는 것입니다.
저희는 pewter.ai의 textToImage 기능과 대화하여 이미지를 생성받고, 생성된 이미지를 수정하여 사용자에게 보여주는 방식으로 진행합니다.
이번에는 큰 변경 사항은 많지 않습니다. Junie를 이용해서 만들었기 때문에, Junie가 tasks.md 페이지를 생성했는데, CodeRabbit에서 GitHub에 올리지 말라고 제안했고요. 저도 그 의견에 동의합니다.
그리고 여기 약간의 탐색 관련 문제가 있는데, 시각화 도구 내에 영구 저장 기능을 구현하면서 나중에 이 부분을 수정할 예정입니다. 이러한 점을 고려하면, 이번 PR은 병합해도 괜찮을 것 같습니다.
네, 그렇게 진행해 보겠습니다. 그리고 저희 코드가 오류가 없다는 것을 인지하고 있으므로, 다음 기능인 Pewter에 AI가 생성한 이미지를 호스팅하고 데이터베이스에 저장하는 기능을 진행할 수 있겠습니다.