dajeong
08-12
240812 정다정 단어 입력 그림AI 프롬포트 구현
@434d1c186a0351189e11659584c6f5b90ffdd20c
+++ client/resources/img/jumpingRabbit.gif
Binary file is not shown |
+++ client/views/component/TextToImage.vue
... | ... | @@ -0,0 +1,244 @@ |
1 | +<template> | |
2 | + <div class="flex justify-center align-center" style="margin-top : 30px"> | |
3 | + <div class="content title-box aibox"> | |
4 | + <p class="title mt25 title-bg">모르는 단어를 물어봐~!</p> | |
5 | + <div class="propmt-container"> | |
6 | + <div class="input-conatiner"> | |
7 | + <input v-model="word" @keyup.enter="startProgress(word)"/> | |
8 | + <button @click="startProgress(word)"> <p> 생성하기 </p> </button> | |
9 | + </div> | |
10 | + <div class="progress-container"> | |
11 | + <div class="progress-bar" :style="{ width: progressWidth + '%' }">{{ Math.floor(progressWidth) }}%</div> | |
12 | + | |
13 | + <!-- 로딩 이미지 --> | |
14 | + <div v-if="progressWidth < 100 && progressWidth > 1" class="loading-container"> | |
15 | + <img src="../../resources/img/jumpingRabbit.gif" alt="Loading" class="loading-gif"/> | |
16 | + <p> 잠깐만 기다려봐~ </p> | |
17 | + </div> | |
18 | + | |
19 | + </div> | |
20 | + <div v-if="visibleWord" class="result-container"> | |
21 | + <img :src="imageSrc"/> | |
22 | + <div class="word-container"> | |
23 | + <h2> {{ inputWord }} </h2> | |
24 | + </div> | |
25 | + </div> | |
26 | + </div> | |
27 | + </div> | |
28 | + </div> | |
29 | + | |
30 | +</template> | |
31 | + | |
32 | +<script> | |
33 | +import axios from 'axios'; | |
34 | + | |
35 | +export default { | |
36 | + data() { | |
37 | + return { | |
38 | + progressWidth: 0, | |
39 | + inputWord : "", | |
40 | + | |
41 | + // 하드 코딩 -> 수정 필요 : API | |
42 | + word : "", | |
43 | + imageSrc : "", | |
44 | + imageData: null, // 서버에서 받아온 이미지 데이터 저장 | |
45 | + | |
46 | + visibleWord : false, | |
47 | + }; | |
48 | + }, | |
49 | + mounted() { | |
50 | + | |
51 | + }, | |
52 | + methods: { | |
53 | + // 상태 진행 바(progress bar) | |
54 | + startProgress(word) { | |
55 | + if (this.progressWidth == 100) { | |
56 | + this.resetProgress(); | |
57 | + } | |
58 | + | |
59 | + if (this.progressWidth > 0) return; // 이미 진행 중이면 중복 실행 방지 | |
60 | + | |
61 | + this.setWord(word); | |
62 | + | |
63 | + const interval = 300; // 30ms | |
64 | + const totalDuration = 3000; // 총 시간 : 10초 | |
65 | + const steps = totalDuration / interval; | |
66 | + const increment = 100 / steps; | |
67 | + | |
68 | + const progressInterval = setInterval(() => { | |
69 | + this.progressWidth += increment; | |
70 | + if (this.progressWidth >= 100) { | |
71 | + this.progressWidth = 100; | |
72 | + clearInterval(progressInterval); | |
73 | + this.visibleWord = true; | |
74 | + | |
75 | + // 진행이 완료된 후에 이미지 데이터 렌더링 | |
76 | + if (this.imageData) { | |
77 | + this.imageSrc = this.imageUrl; | |
78 | + } | |
79 | + } | |
80 | + }, interval); | |
81 | + | |
82 | + this.getAiImage(); | |
83 | + }, | |
84 | + setWord(word) { | |
85 | + if (this.progressWidth > 0 && this.progressWidth < 100) return; // progressWidth가 0 또는 100이 아니면 실행 중지 | |
86 | + this.inputWord = word; | |
87 | + this.visibleWord = false; | |
88 | + }, | |
89 | + | |
90 | + resetProgress() { | |
91 | + this.progressWidth = 0; | |
92 | + this.visibleWord = false; | |
93 | + this.imageSrc = ""; // 이미지 URL 초기화 | |
94 | + this.imageData = null; // 이미지 데이터 초기화 | |
95 | + }, | |
96 | + | |
97 | + // 이미지 API | |
98 | + async getAiImage(){ | |
99 | + const url = "http://takensoftai.iptime.org:20200/generate_json"; | |
100 | + // console.log(`word : ${this.word}`); | |
101 | + try { | |
102 | + const response = await axios({ | |
103 | + url: url, | |
104 | + method: "post", | |
105 | + headers: { | |
106 | + "Content-Type": "application/json; charset=UTF-8", | |
107 | + }, | |
108 | + responseType: 'arraybuffer', | |
109 | + data: { | |
110 | + text: this.word | |
111 | + }, | |
112 | + }); | |
113 | + | |
114 | + // console.log(`응답 : ${response}`); | |
115 | + | |
116 | + // 바이너리 데이터 -> Blob으로 변환 | |
117 | + const blob = new Blob([response.data], { type: 'image/png' }); | |
118 | + | |
119 | + // Blob에서 객체 URL 생성 | |
120 | + const imageUrl = URL.createObjectURL(blob); | |
121 | + | |
122 | + // 이미지 URL 설정 | |
123 | + this.imageSrc = imageUrl; | |
124 | + } catch (err) { | |
125 | + console.log(err); | |
126 | + } | |
127 | + } | |
128 | + } | |
129 | +} | |
130 | +</script> | |
131 | + | |
132 | +<style> | |
133 | +.propmt-container{ | |
134 | + padding: 0px 50px 30px 50px; | |
135 | +} | |
136 | +/* 입력 컨테이너 */ | |
137 | +.input-conatiner{ | |
138 | + display: flex; | |
139 | + align-items: center; | |
140 | + gap: 30px; | |
141 | + height: 50px; | |
142 | +} | |
143 | +.input-conatiner input{ | |
144 | + width: 90%; | |
145 | + height: 100%; | |
146 | + padding: 10px 30px; | |
147 | + border: none; | |
148 | + border-radius: 10px; | |
149 | + box-shadow: rgba(99, 99, 99, 0.2) 0px 2px 8px 0px; | |
150 | + outline: none; | |
151 | + font-size : 28px; | |
152 | +} | |
153 | +.input-conatiner button{ | |
154 | + width: 15%; | |
155 | + height: 100%; | |
156 | + border: none; | |
157 | + border-radius: 10px; | |
158 | + cursor: pointer; | |
159 | + background-color: #ffba08; | |
160 | + display: flex; | |
161 | + justify-content: center; | |
162 | + align-items: center; | |
163 | +} | |
164 | + | |
165 | +.input-conatiner button p{ | |
166 | + font-size : 28px; | |
167 | +} | |
168 | + | |
169 | +/* 진행 상태바 */ | |
170 | +.progress-container { | |
171 | + width: 100%; | |
172 | + background-color: #ffffff; | |
173 | + border-radius: 5px; | |
174 | + overflow: hidden; | |
175 | + margin-top: 20px; | |
176 | + display : flex; | |
177 | + flex-direction: column; | |
178 | + gap :30px; | |
179 | +} | |
180 | + | |
181 | +.progress-bar { | |
182 | + height: 30px; | |
183 | + width: 0; | |
184 | + background-color: #4caf50; | |
185 | + text-align: center; | |
186 | + line-height: 30px; | |
187 | + color: white; | |
188 | + border : none; | |
189 | + border-radius: 5px; | |
190 | + transition: width 0.3s; | |
191 | + font-size : 20px; | |
192 | +} | |
193 | + | |
194 | +/* 로딩 gif */ | |
195 | +.loading-container{ | |
196 | + display : flex; | |
197 | + flex-direction: column; | |
198 | + align-items: center; | |
199 | + gap: 30px; | |
200 | + text-align: center; | |
201 | + margin-top : 30px; | |
202 | + padding-bottom : 40px; | |
203 | +} | |
204 | +.loading-gif{ | |
205 | + width: 25%; | |
206 | + border-radius: 500px; | |
207 | +} | |
208 | +.loading-container p { | |
209 | + font-size : 25px; | |
210 | +} | |
211 | + | |
212 | +/* 결과 container */ | |
213 | +.result-container{ | |
214 | + margin-top: 30px; | |
215 | + display: flex; | |
216 | + flex-direction: column; | |
217 | + align-items: center; | |
218 | + gap: 30px; | |
219 | +} | |
220 | +.result-container img{ | |
221 | + width : 30%; | |
222 | +} | |
223 | +.word-container{ | |
224 | + width: 30%; | |
225 | + text-align: center; | |
226 | + padding: 20px 0px; | |
227 | + border: 3px solid #4caf50; | |
228 | + border-radius: 8px; | |
229 | + display: flex; | |
230 | + flex-direction: column; | |
231 | + gap: 15px; | |
232 | +} | |
233 | +.word-container h2 { | |
234 | + font-size : 28px; | |
235 | +} | |
236 | + | |
237 | +.aibox{ | |
238 | + display: flex; | |
239 | + flex-direction: column; | |
240 | + justify-content: center; | |
241 | + height: auto; | |
242 | + padding: 30px 0px; | |
243 | +} | |
244 | +</style> |
Add a comment
Delete comment
Once you delete this comment, you won't be able to recover it. Are you sure you want to delete this comment?