캐릭터 챗봇 #74
| @@ -163,7 +163,7 @@ | ||||
|                 <div | ||||
|                   class="caption grey--text text--darken-1 custom-caption" | ||||
|                 > | ||||
|                   태그를 입력하고 엔터 또는 스페이스바를 누르면 추가됩니다. (50자 이내, 최대 20개, 띄어쓰기 불가) | ||||
|                   태그를 입력하고 엔터를 누르면 추가됩니다. (50자 이내, 최대 20개) | ||||
|                 </div> | ||||
|               </v-col> | ||||
|             </v-row> | ||||
| @@ -178,31 +178,6 @@ | ||||
|               </v-col> | ||||
|             </v-row> | ||||
|  | ||||
|             <!-- 세계관 (배경이야기) --> | ||||
|             <v-row> | ||||
|               <v-col cols="12"> | ||||
|                 <v-textarea | ||||
|                   v-model="character.worldView" | ||||
|                   label="세계관 (배경이야기)" | ||||
|                   outlined | ||||
|                   auto-grow | ||||
|                   rows="4" | ||||
|                 /> | ||||
|               </v-col> | ||||
|             </v-row> | ||||
|  | ||||
|             <!-- 성격 특성 --> | ||||
|             <v-row> | ||||
|               <v-col cols="12"> | ||||
|                 <v-textarea | ||||
|                   v-model="character.personality" | ||||
|                   label="성격 특성" | ||||
|                   outlined | ||||
|                   auto-grow | ||||
|                   rows="4" | ||||
|                 /> | ||||
|               </v-col> | ||||
|             </v-row> | ||||
|  | ||||
|             <!-- 말투/특징적 표현 --> | ||||
|             <v-row> | ||||
| @@ -575,6 +550,191 @@ | ||||
|               </v-col> | ||||
|             </v-row> | ||||
|  | ||||
|  | ||||
|             <!-- 세계관 (배경이야기) --> | ||||
|             <v-row> | ||||
|               <v-col cols="12"> | ||||
|                 <v-divider class="my-4" /> | ||||
|                 <h3 class="mb-2"> | ||||
|                   세계관 (배경이야기) | ||||
|                 </h3> | ||||
|  | ||||
|                 <v-row> | ||||
|                   <v-col cols="12"> | ||||
|                     <v-row> | ||||
|                       <v-col cols="5"> | ||||
|                         <v-text-field | ||||
|                           v-model="newBackgroundTopic" | ||||
|                           label="주제 (최대 100자)" | ||||
|                           outlined | ||||
|                           dense | ||||
|                           counter="100" | ||||
|                           :rules="[v => v.length <= 100 || '최대 100자까지 입력 가능합니다']" | ||||
|                           @keyup.enter="addBackground" | ||||
|                         /> | ||||
|                       </v-col> | ||||
|                       <v-col cols="6"> | ||||
|                         <v-textarea | ||||
|                           v-model="newBackgroundDescription" | ||||
|                           label="배경 설명 (최대 1000자)" | ||||
|                           outlined | ||||
|                           dense | ||||
|                           auto-grow | ||||
|                           rows="2" | ||||
|                           counter="1000" | ||||
|                           :rules="[v => v.length <= 1000 || '최대 1000자까지 입력 가능합니다']" | ||||
|                         /> | ||||
|                       </v-col> | ||||
|                       <v-col cols="1"> | ||||
|                         <v-btn | ||||
|                           color="primary" | ||||
|                           class="mt-1" | ||||
|                           block | ||||
|                           :disabled="!newBackgroundTopic.trim() || !newBackgroundDescription.trim() || backgrounds.length >= 10" | ||||
|                           @click="addBackground" | ||||
|                         > | ||||
|                           추가 | ||||
|                         </v-btn> | ||||
|                       </v-col> | ||||
|                     </v-row> | ||||
|                   </v-col> | ||||
|                 </v-row> | ||||
|  | ||||
|                 <v-card | ||||
|                   outlined | ||||
|                   class="memory-container" | ||||
|                 > | ||||
|                   <v-list | ||||
|                     v-if="backgrounds.length > 0" | ||||
|                     class="memory-list" | ||||
|                   > | ||||
|                     <v-list-item | ||||
|                       v-for="(background, index) in backgrounds" | ||||
|                       :key="index" | ||||
|                       class="memory-item" | ||||
|                     > | ||||
|                       <v-list-item-content> | ||||
|                         <v-list-item-title class="memory-text font-weight-bold"> | ||||
|                           {{ background.topic }} | ||||
|                         </v-list-item-title> | ||||
|                         <v-list-item-subtitle class="memory-text mt-1"> | ||||
|                           {{ background.description }} | ||||
|                         </v-list-item-subtitle> | ||||
|                       </v-list-item-content> | ||||
|                       <v-list-item-action> | ||||
|                         <v-btn | ||||
|                           small | ||||
|                           color="error" | ||||
|                           class="delete-btn" | ||||
|                           @click="removeBackground(index)" | ||||
|                         > | ||||
|                           삭제 | ||||
|                         </v-btn> | ||||
|                       </v-list-item-action> | ||||
|                     </v-list-item> | ||||
|                   </v-list> | ||||
|                   <v-card-text | ||||
|                     v-else | ||||
|                     class="text-center grey--text" | ||||
|                   > | ||||
|                     세계관 정보가 없습니다. 위 입력창에서 세계관 정보를 추가해주세요. (최대 10개) | ||||
|                   </v-card-text> | ||||
|                 </v-card> | ||||
|               </v-col> | ||||
|             </v-row> | ||||
|  | ||||
|             <!-- 성격 특성 --> | ||||
|             <v-row> | ||||
|               <v-col cols="12"> | ||||
|                 <v-divider class="my-4" /> | ||||
|                 <h3 class="mb-2"> | ||||
|                   성격 특성 | ||||
|                 </h3> | ||||
|  | ||||
|                 <v-row> | ||||
|                   <v-col cols="12"> | ||||
|                     <v-row> | ||||
|                       <v-col cols="5"> | ||||
|                         <v-text-field | ||||
|                           v-model="newPersonalityTrait" | ||||
|                           label="특성 제목 (최대 100자)" | ||||
|                           outlined | ||||
|                           dense | ||||
|                           counter="100" | ||||
|                           :rules="[v => v.length <= 100 || '최대 100자까지 입력 가능합니다']" | ||||
|                           @keyup.enter="addPersonality" | ||||
|                         /> | ||||
|                       </v-col> | ||||
|                       <v-col cols="6"> | ||||
|                         <v-textarea | ||||
|                           v-model="newPersonalityDescription" | ||||
|                           label="특성 설명 (최대 500자)" | ||||
|                           outlined | ||||
|                           dense | ||||
|                           auto-grow | ||||
|                           rows="2" | ||||
|                           counter="500" | ||||
|                           :rules="[v => v.length <= 500 || '최대 500자까지 입력 가능합니다']" | ||||
|                         /> | ||||
|                       </v-col> | ||||
|                       <v-col cols="1"> | ||||
|                         <v-btn | ||||
|                           color="primary" | ||||
|                           class="mt-1" | ||||
|                           block | ||||
|                           :disabled="!newPersonalityTrait.trim() || !newPersonalityDescription.trim() || personalities.length >= 10" | ||||
|                           @click="addPersonality" | ||||
|                         > | ||||
|                           추가 | ||||
|                         </v-btn> | ||||
|                       </v-col> | ||||
|                     </v-row> | ||||
|                   </v-col> | ||||
|                 </v-row> | ||||
|  | ||||
|                 <v-card | ||||
|                   outlined | ||||
|                   class="memory-container" | ||||
|                 > | ||||
|                   <v-list | ||||
|                     v-if="personalities.length > 0" | ||||
|                     class="memory-list" | ||||
|                   > | ||||
|                     <v-list-item | ||||
|                       v-for="(personality, index) in personalities" | ||||
|                       :key="index" | ||||
|                       class="memory-item" | ||||
|                     > | ||||
|                       <v-list-item-content> | ||||
|                         <v-list-item-title class="memory-text font-weight-bold"> | ||||
|                           {{ personality.trait }} | ||||
|                         </v-list-item-title> | ||||
|                         <v-list-item-subtitle class="memory-text mt-1"> | ||||
|                           {{ personality.description }} | ||||
|                         </v-list-item-subtitle> | ||||
|                       </v-list-item-content> | ||||
|                       <v-list-item-action> | ||||
|                         <v-btn | ||||
|                           small | ||||
|                           color="error" | ||||
|                           class="delete-btn" | ||||
|                           @click="removePersonality(index)" | ||||
|                         > | ||||
|                           삭제 | ||||
|                         </v-btn> | ||||
|                       </v-list-item-action> | ||||
|                     </v-list-item> | ||||
|                   </v-list> | ||||
|                   <v-card-text | ||||
|                     v-else | ||||
|                     class="text-center grey--text" | ||||
|                   > | ||||
|                     성격 특성이 없습니다. 위 입력창에서 성격 특성을 추가해주세요. (최대 10개) | ||||
|                   </v-card-text> | ||||
|                 </v-card> | ||||
|               </v-col> | ||||
|             </v-row> | ||||
|  | ||||
|             <!-- 기억/메모리 --> | ||||
|             <v-row> | ||||
|               <v-col cols="12"> | ||||
| @@ -586,12 +746,36 @@ | ||||
|                 <v-row> | ||||
|                   <v-col cols="12"> | ||||
|                     <v-row> | ||||
|                       <v-col cols="11"> | ||||
|                       <v-col cols="4"> | ||||
|                         <v-text-field | ||||
|                           v-model="newMemory" | ||||
|                           label="새 기억 추가" | ||||
|                           v-model="newMemoryTitle" | ||||
|                           label="제목 (최대 100자)" | ||||
|                           outlined | ||||
|                           dense | ||||
|                           counter="100" | ||||
|                           :rules="[v => v.length <= 100 || '최대 100자까지 입력 가능합니다']" | ||||
|                         /> | ||||
|                       </v-col> | ||||
|                       <v-col cols="4"> | ||||
|                         <v-textarea | ||||
|                           v-model="newMemoryContent" | ||||
|                           label="기억 내용 (최대 1000자)" | ||||
|                           outlined | ||||
|                           dense | ||||
|                           auto-grow | ||||
|                           rows="2" | ||||
|                           counter="1000" | ||||
|                           :rules="[v => v.length <= 1000 || '최대 1000자까지 입력 가능합니다']" | ||||
|                         /> | ||||
|                       </v-col> | ||||
|                       <v-col cols="3"> | ||||
|                         <v-text-field | ||||
|                           v-model="newMemoryEmotion" | ||||
|                           label="감정 (최대 50자)" | ||||
|                           outlined | ||||
|                           dense | ||||
|                           counter="50" | ||||
|                           :rules="[v => v.length <= 50 || '최대 50자까지 입력 가능합니다']" | ||||
|                           @keyup.enter="addMemory" | ||||
|                         /> | ||||
|                       </v-col> | ||||
| @@ -600,7 +784,7 @@ | ||||
|                           color="primary" | ||||
|                           class="mt-1" | ||||
|                           block | ||||
|                           :disabled="!newMemory.trim()" | ||||
|                           :disabled="!newMemoryTitle.trim() || !newMemoryContent.trim() || memories.length >= 20" | ||||
|                           @click="addMemory" | ||||
|                         > | ||||
|                           추가 | ||||
| @@ -624,9 +808,18 @@ | ||||
|                       class="memory-item" | ||||
|                     > | ||||
|                       <v-list-item-content> | ||||
|                         <v-list-item-title class="memory-text"> | ||||
|                           {{ memory }} | ||||
|                         <v-list-item-title class="memory-text font-weight-bold"> | ||||
|                           {{ memory.title }} | ||||
|                         </v-list-item-title> | ||||
|                         <v-list-item-subtitle class="memory-text mt-1"> | ||||
|                           {{ memory.content }} | ||||
|                         </v-list-item-subtitle> | ||||
|                         <v-list-item-subtitle | ||||
|                           v-if="memory.emotion" | ||||
|                           class="memory-text mt-1 font-italic" | ||||
|                         > | ||||
|                           감정: {{ memory.emotion }} | ||||
|                         </v-list-item-subtitle> | ||||
|                       </v-list-item-content> | ||||
|                       <v-list-item-action> | ||||
|                         <v-btn | ||||
| @@ -644,7 +837,7 @@ | ||||
|                     v-else | ||||
|                     class="text-center grey--text" | ||||
|                   > | ||||
|                     기억이 없습니다. 위 입력창에서 기억을 추가해주세요. | ||||
|                     기억이 없습니다. 위 입력창에서 기억을 추가해주세요. (최대 20개) | ||||
|                   </v-card-text> | ||||
|                 </v-card> | ||||
|               </v-col> | ||||
| @@ -702,17 +895,25 @@ export default { | ||||
|       isFormValid: false, | ||||
|       isEdit: false, | ||||
|       previewImage: null, | ||||
|       newMemory: '', | ||||
|       newMemoryTitle: '', | ||||
|       newMemoryContent: '', | ||||
|       newMemoryEmotion: '', | ||||
|       newRelationship: '', | ||||
|       newHobby: '', | ||||
|       newValue: '', | ||||
|       newGoal: '', | ||||
|       newPersonalityTrait: '', | ||||
|       newPersonalityDescription: '', | ||||
|       newBackgroundTopic: '', | ||||
|       newBackgroundDescription: '', | ||||
|       tags: [], | ||||
|       memories: [], | ||||
|       relationships: [], | ||||
|       hobbies: [], | ||||
|       values: [], | ||||
|       goals: [], | ||||
|       personalities: [], | ||||
|       backgrounds: [], | ||||
|       character: { | ||||
|         id: null, | ||||
|         name: '', | ||||
| @@ -841,9 +1042,40 @@ export default { | ||||
|     }, | ||||
|  | ||||
|     addMemory() { | ||||
|       if (this.newMemory.trim()) { | ||||
|         this.memories.unshift(this.newMemory.trim()); | ||||
|         this.newMemory = ''; | ||||
|       if (this.newMemoryTitle.trim() && this.newMemoryContent.trim()) { | ||||
|         if (this.memories.length >= 20) { | ||||
|           this.notifyError('기억은 최대 20개까지 등록 가능합니다.'); | ||||
|           return; | ||||
|         } | ||||
|  | ||||
|         // 글자수 제한 적용 | ||||
|         let title = this.newMemoryTitle.trim(); | ||||
|         let content = this.newMemoryContent.trim(); | ||||
|         let emotion = this.newMemoryEmotion.trim(); | ||||
|  | ||||
|         if (title.length > 100) { | ||||
|           title = title.substring(0, 100); | ||||
|         } | ||||
|  | ||||
|         if (content.length > 1000) { | ||||
|           content = content.substring(0, 1000); | ||||
|         } | ||||
|  | ||||
|         if (emotion.length > 50) { | ||||
|           emotion = emotion.substring(0, 50); | ||||
|         } | ||||
|  | ||||
|         // 새 기억 객체 생성 및 추가 | ||||
|         this.memories.unshift({ | ||||
|           title, | ||||
|           content, | ||||
|           emotion | ||||
|         }); | ||||
|  | ||||
|         // 입력 필드 초기화 | ||||
|         this.newMemoryTitle = ''; | ||||
|         this.newMemoryContent = ''; | ||||
|         this.newMemoryEmotion = ''; | ||||
|       } | ||||
|     }, | ||||
|  | ||||
| @@ -931,6 +1163,76 @@ export default { | ||||
|       this.goals.splice(index, 1); | ||||
|     }, | ||||
|  | ||||
|     addPersonality() { | ||||
|       if (this.newPersonalityTrait.trim() && this.newPersonalityDescription.trim()) { | ||||
|         if (this.personalities.length >= 10) { | ||||
|           this.notifyError('성격 특성은 최대 10개까지 등록 가능합니다.'); | ||||
|           return; | ||||
|         } | ||||
|  | ||||
|         // 글자수 제한 적용 | ||||
|         let trait = this.newPersonalityTrait.trim(); | ||||
|         let description = this.newPersonalityDescription.trim(); | ||||
|  | ||||
|         if (trait.length > 100) { | ||||
|           trait = trait.substring(0, 100); | ||||
|         } | ||||
|  | ||||
|         if (description.length > 500) { | ||||
|           description = description.substring(0, 500); | ||||
|         } | ||||
|  | ||||
|         // 새 성격 특성 객체 생성 및 추가 | ||||
|         this.personalities.unshift({ | ||||
|           trait, | ||||
|           description | ||||
|         }); | ||||
|  | ||||
|         // 입력 필드 초기화 | ||||
|         this.newPersonalityTrait = ''; | ||||
|         this.newPersonalityDescription = ''; | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     removePersonality(index) { | ||||
|       this.personalities.splice(index, 1); | ||||
|     }, | ||||
|  | ||||
|     addBackground() { | ||||
|       if (this.newBackgroundTopic.trim() && this.newBackgroundDescription.trim()) { | ||||
|         if (this.backgrounds.length >= 10) { | ||||
|           this.notifyError('세계관 정보는 최대 10개까지 등록 가능합니다.'); | ||||
|           return; | ||||
|         } | ||||
|  | ||||
|         // 글자수 제한 적용 | ||||
|         let topic = this.newBackgroundTopic.trim(); | ||||
|         let description = this.newBackgroundDescription.trim(); | ||||
|  | ||||
|         if (topic.length > 100) { | ||||
|           topic = topic.substring(0, 100); | ||||
|         } | ||||
|  | ||||
|         if (description.length > 1000) { | ||||
|           description = description.substring(0, 1000); | ||||
|         } | ||||
|  | ||||
|         // 새 세계관 객체 생성 및 추가 | ||||
|         this.backgrounds.unshift({ | ||||
|           topic, | ||||
|           description | ||||
|         }); | ||||
|  | ||||
|         // 입력 필드 초기화 | ||||
|         this.newBackgroundTopic = ''; | ||||
|         this.newBackgroundDescription = ''; | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     removeBackground(index) { | ||||
|       this.backgrounds.splice(index, 1); | ||||
|     }, | ||||
|  | ||||
|     async loadCharacter(id) { | ||||
|       this.isLoading = true; | ||||
|       try { | ||||
| @@ -947,13 +1249,15 @@ export default { | ||||
|             image: null        // 파일 입력은 초기화 | ||||
|           }; | ||||
|  | ||||
|           // 태그, 메모리, 인물관계, 취미, 가치관, 목표 설정 | ||||
|           // 태그, 메모리, 인물관계, 취미, 가치관, 목표, 성격 특성, 세계관 설정 | ||||
|           this.tags = data.tags || []; | ||||
|           this.memories = data.memories || []; | ||||
|           this.relationships = data.relationships || []; | ||||
|           this.hobbies = data.hobbies || []; | ||||
|           this.values = data.values || []; | ||||
|           this.goals = data.goals || []; | ||||
|           this.personalities = data.personalities || []; | ||||
|           this.backgrounds = data.backgrounds || []; | ||||
|         } else { | ||||
|           this.notifyError('캐릭터 정보를 불러올 수 없습니다.'); | ||||
|         } | ||||
| @@ -976,13 +1280,15 @@ export default { | ||||
|       this.isLoading = true; | ||||
|  | ||||
|       try { | ||||
|         // 태그, 메모리, 인물관계, 취미, 가치관, 목표 데이터 설정 | ||||
|         // 태그, 메모리, 인물관계, 취미, 가치관, 목표, 성격 특성, 세계관 데이터 설정 | ||||
|         this.character.tags = this.tags.filter(tag => tag && typeof tag === 'string' && tag.trim()); | ||||
|         this.character.memories = [...this.memories]; | ||||
|         this.character.relationships = [...this.relationships]; | ||||
|         this.character.hobbies = [...this.hobbies]; | ||||
|         this.character.values = [...this.values]; | ||||
|         this.character.goals = [...this.goals]; | ||||
|         this.character.personalities = [...this.personalities]; | ||||
|         this.character.backgrounds = [...this.backgrounds]; | ||||
|  | ||||
|         let response; | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user