캐릭터 챗봇 #74

Merged
klaus merged 33 commits from test into main 2025-09-10 06:26:03 +00:00
1 changed files with 230 additions and 91 deletions
Showing only changes of commit 806af4aba0 - Show all commits

View File

@ -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 => {