캐릭터 챗봇 #74
| @@ -280,82 +280,6 @@ | |||||||
|               </v-col> |               </v-col> | ||||||
|             </v-row> |             </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="11"> |  | ||||||
|                         <v-text-field |  | ||||||
|                           v-model="newRelationship" |  | ||||||
|                           label="새 인물 관계 추가 (최대 200자)" |  | ||||||
|                           outlined |  | ||||||
|                           dense |  | ||||||
|                           counter="200" |  | ||||||
|                           :rules="[v => v.length <= 200 || '최대 200자까지 입력 가능합니다']" |  | ||||||
|                           @keyup.enter="addRelationship" |  | ||||||
|                         /> |  | ||||||
|                       </v-col> |  | ||||||
|                       <v-col cols="1"> |  | ||||||
|                         <v-btn |  | ||||||
|                           color="primary" |  | ||||||
|                           class="mt-1" |  | ||||||
|                           block |  | ||||||
|                           :disabled="!newRelationship.trim() || relationships.length >= 10" |  | ||||||
|                           @click="addRelationship" |  | ||||||
|                         > |  | ||||||
|                           추가 |  | ||||||
|                         </v-btn> |  | ||||||
|                       </v-col> |  | ||||||
|                     </v-row> |  | ||||||
|                   </v-col> |  | ||||||
|                 </v-row> |  | ||||||
|  |  | ||||||
|                 <v-card |  | ||||||
|                   outlined |  | ||||||
|                   class="memory-container" |  | ||||||
|                 > |  | ||||||
|                   <v-list |  | ||||||
|                     v-if="relationships.length > 0" |  | ||||||
|                     class="memory-list" |  | ||||||
|                   > |  | ||||||
|                     <v-list-item |  | ||||||
|                       v-for="(relationship, index) in relationships" |  | ||||||
|                       :key="index" |  | ||||||
|                       class="memory-item" |  | ||||||
|                     > |  | ||||||
|                       <v-list-item-content> |  | ||||||
|                         <v-list-item-title class="memory-text"> |  | ||||||
|                           {{ relationship }} |  | ||||||
|                         </v-list-item-title> |  | ||||||
|                       </v-list-item-content> |  | ||||||
|                       <v-list-item-action> |  | ||||||
|                         <v-btn |  | ||||||
|                           small |  | ||||||
|                           color="error" |  | ||||||
|                           class="delete-btn" |  | ||||||
|                           @click="removeRelationship(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-row> | ||||||
| @@ -881,6 +805,154 @@ | |||||||
|               </v-col> |               </v-col> | ||||||
|             </v-row> |             </v-row> | ||||||
|  |  | ||||||
|  |             <!-- 인물 관계 --> | ||||||
|  |             <v-row> | ||||||
|  |               <v-col cols="12"> | ||||||
|  |                 <v-divider class="my-4" /> | ||||||
|  |                 <h3 class="mb-2"> | ||||||
|  |                   인물 관계 | ||||||
|  |                 </h3> | ||||||
|  |  | ||||||
|  |                 <v-row> | ||||||
|  |                   <v-col cols="12"> | ||||||
|  |                     <!-- 1행: 상대방 이름, 관계명 --> | ||||||
|  |                     <v-row> | ||||||
|  |                       <v-col cols="4"> | ||||||
|  |                         <v-text-field | ||||||
|  |                           v-model="newRelationship.personName" | ||||||
|  |                           label="상대방 이름 (최대 10자)" | ||||||
|  |                           outlined | ||||||
|  |                           dense | ||||||
|  |                           counter="10" | ||||||
|  |                           :rules="personNameRules" | ||||||
|  |                         /> | ||||||
|  |                       </v-col> | ||||||
|  |                       <v-col cols="8"> | ||||||
|  |                         <v-text-field | ||||||
|  |                           v-model="newRelationship.relationshipName" | ||||||
|  |                           label="관계명 (어머니, 아버지, 친구 등) (최대 20자)" | ||||||
|  |                           outlined | ||||||
|  |                           dense | ||||||
|  |                           counter="20" | ||||||
|  |                           :rules="relationshipNameRules" | ||||||
|  |                         /> | ||||||
|  |                       </v-col> | ||||||
|  |                     </v-row> | ||||||
|  |  | ||||||
|  |                     <!-- 2행: 관계 타입, 현재 상태, 중요도 --> | ||||||
|  |                     <v-row> | ||||||
|  |                       <v-col cols="5"> | ||||||
|  |                         <v-text-field | ||||||
|  |                           v-model="newRelationship.relationshipType" | ||||||
|  |                           label="관계 타입 (최대 10자)" | ||||||
|  |                           outlined | ||||||
|  |                           dense | ||||||
|  |                           counter="10" | ||||||
|  |                           :rules="relationshipTypeRules" | ||||||
|  |                         /> | ||||||
|  |                       </v-col> | ||||||
|  |                       <v-col cols="5"> | ||||||
|  |                         <v-text-field | ||||||
|  |                           v-model="newRelationship.currentStatus" | ||||||
|  |                           label="현재 상태 (최대 10자)" | ||||||
|  |                           outlined | ||||||
|  |                           dense | ||||||
|  |                           counter="10" | ||||||
|  |                           :rules="relationshipStatusRules" | ||||||
|  |                         /> | ||||||
|  |                       </v-col> | ||||||
|  |                       <v-col cols="2"> | ||||||
|  |                         <v-text-field | ||||||
|  |                           v-model.number="newRelationship.importance" | ||||||
|  |                           label="중요도 (1~10)" | ||||||
|  |                           outlined | ||||||
|  |                           dense | ||||||
|  |                           type="number" | ||||||
|  |                           min="1" | ||||||
|  |                           max="10" | ||||||
|  |                           :rules="relationshipImportanceRules" | ||||||
|  |                         /> | ||||||
|  |                       </v-col> | ||||||
|  |                     </v-row> | ||||||
|  |                   </v-col> | ||||||
|  |                 </v-row> | ||||||
|  |  | ||||||
|  |                 <v-row> | ||||||
|  |                   <v-col cols="11"> | ||||||
|  |                     <v-textarea | ||||||
|  |                       v-model="newRelationship.description" | ||||||
|  |                       label="관계 설명 (최대 500자)" | ||||||
|  |                       outlined | ||||||
|  |                       dense | ||||||
|  |                       auto-grow | ||||||
|  |                       rows="2" | ||||||
|  |                       counter="500" | ||||||
|  |                       :rules="relationshipDescriptionRules" | ||||||
|  |                       @keyup.enter="addRelationship" | ||||||
|  |                     /> | ||||||
|  |                   </v-col> | ||||||
|  |                   <v-col cols="1"> | ||||||
|  |                     <v-btn | ||||||
|  |                       color="primary" | ||||||
|  |                       class="mt-1" | ||||||
|  |                       block | ||||||
|  |                       :disabled="!newRelationship.personName || !newRelationship.relationshipName || !newRelationship.relationshipType || !newRelationship.currentStatus || !newRelationship.importance || relationships.length >= 10" | ||||||
|  |                       @click="addRelationship" | ||||||
|  |                     > | ||||||
|  |                       추가 | ||||||
|  |                     </v-btn> | ||||||
|  |                   </v-col> | ||||||
|  |                 </v-row> | ||||||
|  |  | ||||||
|  |                 <v-card | ||||||
|  |                   outlined | ||||||
|  |                   class="memory-container" | ||||||
|  |                 > | ||||||
|  |                   <v-list | ||||||
|  |                     v-if="relationships.length > 0" | ||||||
|  |                     class="memory-list" | ||||||
|  |                   > | ||||||
|  |                     <v-list-item | ||||||
|  |                       v-for="(relationship, index) in relationships" | ||||||
|  |                       :key="index" | ||||||
|  |                       class="memory-item" | ||||||
|  |                     > | ||||||
|  |                       <v-list-item-content> | ||||||
|  |                         <v-list-item-title class="memory-text font-weight-bold"> | ||||||
|  |                           {{ relationship.personName }} - {{ relationship.relationshipName }} | ||||||
|  |                         </v-list-item-title> | ||||||
|  |                         <v-list-item-subtitle class="memory-text mt-1"> | ||||||
|  |                           타입: {{ relationship.relationshipType }} | 상태: {{ relationship.currentStatus }} | 중요도: {{ relationship.importance }} | ||||||
|  |                         </v-list-item-subtitle> | ||||||
|  |                         <v-list-item-subtitle | ||||||
|  |                           v-if="relationship.description" | ||||||
|  |                           class="memory-text mt-1" | ||||||
|  |                         > | ||||||
|  |                           {{ relationship.description }} | ||||||
|  |                         </v-list-item-subtitle> | ||||||
|  |                       </v-list-item-content> | ||||||
|  |                       <v-list-item-action> | ||||||
|  |                         <v-btn | ||||||
|  |                           small | ||||||
|  |                           color="error" | ||||||
|  |                           class="delete-btn" | ||||||
|  |                           @click="removeRelationship(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-show="isEdit"> |             <v-row v-show="isEdit"> | ||||||
|               <v-col cols="12"> |               <v-col cols="12"> | ||||||
| @@ -936,7 +1008,14 @@ export default { | |||||||
|       newMemoryTitle: '', |       newMemoryTitle: '', | ||||||
|       newMemoryContent: '', |       newMemoryContent: '', | ||||||
|       newMemoryEmotion: '', |       newMemoryEmotion: '', | ||||||
|       newRelationship: '', |       newRelationship: { | ||||||
|  |         personName: '', | ||||||
|  |         relationshipName: '', | ||||||
|  |         description: '', | ||||||
|  |         importance: null, | ||||||
|  |         relationshipType: '', | ||||||
|  |         currentStatus: '' | ||||||
|  |       }, | ||||||
|       newHobby: '', |       newHobby: '', | ||||||
|       newValue: '', |       newValue: '', | ||||||
|       newGoal: '', |       newGoal: '', | ||||||
| @@ -1007,6 +1086,33 @@ export default { | |||||||
|       typeOptions: ['Clone', 'Character'], |       typeOptions: ['Clone', 'Character'], | ||||||
|       systemPromptRules: [ |       systemPromptRules: [ | ||||||
|         v => (this.isEdit ? true : (!!v && v.trim().length > 0) || '시스템 프롬프트를 입력하세요') |         v => (this.isEdit ? true : (!!v && v.trim().length > 0) || '시스템 프롬프트를 입력하세요') | ||||||
|  |       ], | ||||||
|  |       // 인물 관계 옵션 및 검증 규칙 | ||||||
|  |       relationshipTypeOptions: ['가족', '친구', '동료', '연인', '기타'], | ||||||
|  |       relationshipStatusOptions: ['생존', '사망', '불명'], | ||||||
|  |       personNameRules: [ | ||||||
|  |         v => (v === '' || v != null) || '상대방 이름을 입력하세요', | ||||||
|  |         v => (!v || (typeof v === 'string' && v.length <= 10)) || '최대 10자까지 입력 가능합니다', | ||||||
|  |         v => (!!v && v.trim().length > 0) || '상대방 이름을 입력하세요' | ||||||
|  |       ], | ||||||
|  |       relationshipNameRules: [ | ||||||
|  |         v => (!!v && v.trim().length > 0) || '관계명을 입력하세요', | ||||||
|  |         v => (typeof v === 'string' && v.length <= 20) || '최대 20자까지 입력 가능합니다' | ||||||
|  |       ], | ||||||
|  |       relationshipDescriptionRules: [ | ||||||
|  |         v => (!v || (typeof v === 'string' && v.length <= 500)) || '최대 500자까지 입력 가능합니다' | ||||||
|  |       ], | ||||||
|  |       relationshipImportanceRules: [ | ||||||
|  |         v => (v !== null && v !== '' && !isNaN(v)) || '중요도를 입력하세요', | ||||||
|  |         v => (parseInt(v) >= 1 && parseInt(v) <= 10) || '1~10 사이 숫자만 입력 가능합니다' | ||||||
|  |       ], | ||||||
|  |       relationshipTypeRules: [ | ||||||
|  |         v => (!!v && v.trim().length > 0) || '관계 타입을 입력하세요', | ||||||
|  |         v => (typeof v === 'string' && v.length <= 10) || '최대 10자까지 입력 가능합니다' | ||||||
|  |       ], | ||||||
|  |       relationshipStatusRules: [ | ||||||
|  |         v => (!!v && v.trim().length > 0) || '현재 상태를 입력하세요', | ||||||
|  |         v => (typeof v === 'string' && v.length <= 10) || '최대 10자까지 입력 가능합니다' | ||||||
|       ] |       ] | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
| @@ -1145,19 +1251,52 @@ export default { | |||||||
|     }, |     }, | ||||||
|  |  | ||||||
|     addRelationship() { |     addRelationship() { | ||||||
|       if (this.newRelationship.trim()) { |       const r = this.newRelationship; | ||||||
|         if (this.relationships.length >= 10) { |       // 필수값 검사 | ||||||
|           this.notifyError('인물 관계는 최대 10개까지 등록 가능합니다.'); |       if (!r.personName || !r.relationshipName || !r.relationshipType || !r.currentStatus || r.importance === null || r.importance === '') { | ||||||
|           return; |         this.notifyError('상대방 이름, 관계명, 관계 타입, 현재 상태, 중요도를 모두 입력하세요.'); | ||||||
|         } |         return; | ||||||
|  |  | ||||||
|         if (this.newRelationship.length > 200) { |  | ||||||
|           this.newRelationship = this.newRelationship.substring(0, 200); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         this.relationships.unshift(this.newRelationship.trim()); |  | ||||||
|         this.newRelationship = ''; |  | ||||||
|       } |       } | ||||||
|  |  | ||||||
|  |       if (this.relationships.length >= 10) { | ||||||
|  |         this.notifyError('인물 관계는 최대 10개까지 등록 가능합니다.'); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       // 길이 제한 적용 | ||||||
|  |       let personName = r.personName.trim().substring(0, 10); | ||||||
|  |       let relationshipName = r.relationshipName.trim().substring(0, 20); | ||||||
|  |       let description = (r.description || '').trim().substring(0, 500); | ||||||
|  |  | ||||||
|  |       // 중요도 범위 보정 | ||||||
|  |       let importance = parseInt(r.importance); | ||||||
|  |       if (isNaN(importance)) importance = 1; | ||||||
|  |       importance = Math.max(1, Math.min(10, importance)); | ||||||
|  |  | ||||||
|  |       // 타입/상태 길이 제한 적용 | ||||||
|  |       let relationshipType = (r.relationshipType || '').trim().substring(0, 10); | ||||||
|  |       let currentStatus = (r.currentStatus || '').trim().substring(0, 10); | ||||||
|  |  | ||||||
|  |       const relationshipObj = { | ||||||
|  |         personName, | ||||||
|  |         relationshipName, | ||||||
|  |         description, | ||||||
|  |         importance, | ||||||
|  |         relationshipType, | ||||||
|  |         currentStatus | ||||||
|  |       }; | ||||||
|  |  | ||||||
|  |       this.relationships.unshift(relationshipObj); | ||||||
|  |  | ||||||
|  |       // 입력 필드 초기화 | ||||||
|  |       this.newRelationship = { | ||||||
|  |         personName: '', | ||||||
|  |         relationshipName: '', | ||||||
|  |         description: '', | ||||||
|  |         importance: null, | ||||||
|  |         relationshipType: '', | ||||||
|  |         currentStatus: '' | ||||||
|  |       }; | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
|     removeRelationship(index) { |     removeRelationship(index) { | ||||||
| @@ -1371,7 +1510,7 @@ export default { | |||||||
|  |  | ||||||
|       // 배열 필드 비교 (깊은 비교) |       // 배열 필드 비교 (깊은 비교) | ||||||
|       const arrayFields = [ |       const arrayFields = [ | ||||||
|         'tags', 'hobbies', 'values', 'goals', 'relationships' |         'tags', 'hobbies', 'values', 'goals' | ||||||
|       ]; |       ]; | ||||||
|  |  | ||||||
|       arrayFields.forEach(field => { |       arrayFields.forEach(field => { | ||||||
| @@ -1387,7 +1526,7 @@ export default { | |||||||
|  |  | ||||||
|       // 복잡한 객체 배열 비교 |       // 복잡한 객체 배열 비교 | ||||||
|       const objectArrayFields = [ |       const objectArrayFields = [ | ||||||
|         'personalities', 'backgrounds', 'memories' |         'personalities', 'backgrounds', 'memories', 'relationships' | ||||||
|       ]; |       ]; | ||||||
|  |  | ||||||
|       objectArrayFields.forEach(field => { |       objectArrayFields.forEach(field => { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user