Skip to content

Commit 16c7d9e

Browse files
authored
Merge pull request #171 from heshengtao/dev
Dev
2 parents bc3ff7e + fac3fd9 commit 16c7d9e

File tree

8 files changed

+334
-22
lines changed

8 files changed

+334
-22
lines changed

server.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,7 @@ async def tools_change_messages(request: ChatRequest, settings: dict):
540540
request.messages[0]['content'] += sticker_message
541541
else:
542542
request.messages.insert(0, {'role': 'system', 'content': sticker_message})
543-
request.messages[0]['content'] += "\n\n当你需要使用图片时,请将图片的URL放在markdown的图片标签中,例如:![图片名](图片URL)\n\n"
543+
request.messages[0]['content'] += "\n\n当你需要使用图片时,请将图片的URL放在markdown的图片标签中,例如:\n\n![图片名](图片URL)\n\n,图片markdown必须另起并且独占一行!"
544544
if settings['VRMConfig']['enabledExpressions']:
545545
Expression_messages = "\n\n你可以使用以下表情:<happy> <angry> <sad> <neutral> <surprised> <relaxed>\n\n你可以在句子开头插入表情符号以驱动人物的当前表情,注意!你需要将表情符号放到句子的开头,才能在说这句话的时候同步做表情,例如:<angry>我真的生气了。<surprised>哇!<happy>我好开心。\n\n一定要把表情符号跟要做表情的句子放在同一行,如果表情符号和要做表情的句子中间有换行符,表情也将不会生效,例如:\n\n<happy>\n我好开心。\n\n此时,表情符号将不会生效。"
546546
if request.messages and request.messages[0]['role'] == 'system':
@@ -4656,6 +4656,30 @@ async def delete_file_endpoint(request: Request):
46564656
except Exception as e:
46574657
return JSONResponse(content={"success": False, "message": str(e)})
46584658

4659+
class FileNames(BaseModel):
4660+
fileNames: List[str]
4661+
4662+
@app.delete("/delete_files")
4663+
async def delete_files_endpoint(req: FileNames):
4664+
success_files = []
4665+
errors = []
4666+
for name in req.fileNames:
4667+
path = os.path.join(UPLOAD_FILES_DIR, name)
4668+
try:
4669+
if os.path.exists(path):
4670+
os.remove(path)
4671+
success_files.append(name)
4672+
else:
4673+
errors.append(f"{name} not found")
4674+
except Exception as e:
4675+
errors.append(f"{name}: {str(e)}")
4676+
4677+
return JSONResponse(content={
4678+
"success": len(success_files) > 0, # 只要有成功就算成功
4679+
"successFiles": success_files,
4680+
"errors": errors
4681+
})
4682+
46594683
ALLOWED_AUDIO_EXTENSIONS = ['wav', 'mp3', 'ogg', 'flac', 'aac']
46604684

46614685
@app.post("/upload_gsv_ref_audio")

static/css/styles.css

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3174,3 +3174,43 @@ body {
31743174
display: flex; /* 水平排列按钮 */
31753175
margin: 0px;
31763176
}
3177+
3178+
.checkbox-no-label .el-checkbox__label {
3179+
display: none;
3180+
}
3181+
3182+
/* 工具栏整体 */
3183+
.toolbar {
3184+
display: flex;
3185+
align-items: center;
3186+
justify-content: space-between;
3187+
padding: 12px 16px;
3188+
background: #fafbfc;
3189+
border-radius: 8px;
3190+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
3191+
margin-bottom: 12px;
3192+
gap: 12px; /* flex 子项间距 */
3193+
}
3194+
3195+
/* 全选复选框文字样式 */
3196+
.select-all-checkbox .el-checkbox__label {
3197+
font-weight: 500;
3198+
color: #303133;
3199+
margin-left: 6px;
3200+
}
3201+
3202+
/* 批量删除按钮 */
3203+
.batch-del-btn {
3204+
border-radius: 20px; /* 胶囊形状 */
3205+
padding: 6px 14px;
3206+
font-weight: 500;
3207+
box-shadow: 0 2px 4px rgba(245, 108, 108, 0.2);
3208+
transition: transform 0.15s;
3209+
}
3210+
.batch-del-btn:not(:disabled):hover {
3211+
transform: scale(1.05);
3212+
}
3213+
.batch-del-btn:disabled {
3214+
box-shadow: none;
3215+
transform: none;
3216+
}

static/index.html

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5147,9 +5147,31 @@ <h3 class="kb-title">{{memory.name }}</h3>
51475147
<div class="suite-content">
51485148
<!-- 文本存储 -->
51495149
<div v-show="subMenu === 'text'" class="page text-container">
5150+
<!-- 顶部工具条 -->
5151+
<div class="toolbar">
5152+
<el-checkbox
5153+
v-model="allChecked"
5154+
:indeterminate="indeterminate"
5155+
@change="toggleAll">
5156+
{{ t('selectAll') }}
5157+
</el-checkbox>
5158+
<el-button
5159+
type="danger"
5160+
:disabled="selectedFiles.length === 0"
5161+
@click="batchDeleteFiles">
5162+
<i class="fa-solid fa-trash"></i>
5163+
{{ t('batchDelete') }}
5164+
</el-button>
5165+
</div>
51505166
<div class="text-list">
51515167
<!-- 文件列表 -->
51525168
<div class="file-item" v-for="(file, index) in textFiles" :key="index">
5169+
<!-- 复选框 -->
5170+
<el-checkbox
5171+
v-model="selectedFiles"
5172+
:label="file.unique_filename"
5173+
class="checkbox-no-label">
5174+
</el-checkbox>
51535175
<el-icon class="file-icon"><i class="fa-solid fa-file-lines"></i></el-icon>
51545176
<div class="file-info">
51555177
<span class="file-name">{{ file.original_filename }}</span>
@@ -5179,11 +5201,32 @@ <h3 class="kb-title">{{memory.name }}</h3>
51795201
</div>
51805202
<!-- 图片存储 -->
51815203
<div v-show="subMenu === 'image'" class="page image-container">
5204+
<!-- 新增顶部工具栏 -->
5205+
<div class="toolbar">
5206+
<el-checkbox
5207+
v-model="allImagesChecked"
5208+
:indeterminate="indeterminateImages"
5209+
@change="toggleAllImages">
5210+
{{ t('selectAll') }}
5211+
</el-checkbox>
5212+
<el-button
5213+
type="danger"
5214+
:disabled="selectedImages.length === 0"
5215+
@click="batchDeleteImages">
5216+
<i class="fa-solid fa-trash"></i>
5217+
{{ t('batchDelete') }}
5218+
</el-button>
5219+
</div>
51825220
<div class="image-grid">
51835221
<div class="image-item" v-for="(img, index) in imageFiles" :key="index">
51845222
<img :src="`${partyURL}/uploaded_files/${img.unique_filename}`" class="thumbnail"/>
51855223
<div class="image-overlay">
5186-
<span class="image-name">{{ img.name }}</span>
5224+
<!-- 复选框 -->
5225+
<el-checkbox
5226+
v-model="selectedImages"
5227+
:label="img.unique_filename"
5228+
class="checkbox-no-label">
5229+
</el-checkbox>
51875230
<div class="image-actions">
51885231
<!-- 复制链接按钮 -->
51895232
<el-button circle size="small" class="image-actions-btn" @click="copyLink(img.unique_filename)">
@@ -5227,6 +5270,22 @@ <h3 class="kb-title">{{memory.name }}</h3>
52275270
</div>
52285271
<!-- 视频存储 -->
52295272
<div v-show="subMenu === 'video'" class="page video-container">
5273+
<!-- 新增顶部工具栏 -->
5274+
<div class="toolbar">
5275+
<el-checkbox
5276+
v-model="allVideosChecked"
5277+
:indeterminate="indeterminateVideos"
5278+
@change="toggleAllVideos">
5279+
{{ t('selectAll') }}
5280+
</el-checkbox>
5281+
<el-button
5282+
type="danger"
5283+
:disabled="selectedVideos.length === 0"
5284+
@click="batchDeleteVideos">
5285+
<i class="fa-solid fa-trash"></i>
5286+
{{ t('batchDelete') }}
5287+
</el-button>
5288+
</div>
52305289
<div class="video-list">
52315290
<div class="video-item" v-for="(video, index) in videoFiles" :key="index">
52325291
<div class="video-wrapper">
@@ -5235,7 +5294,12 @@ <h3 class="kb-title">{{memory.name }}</h3>
52355294
<source :src="`${partyURL}/uploaded_files/${video.unique_filename}`" type="video/mp4">
52365295
Your browser does not support the video tag.
52375296
</video>
5238-
5297+
<!-- 复选框 -->
5298+
<el-checkbox
5299+
v-model="selectedVideos"
5300+
:label="video.unique_filename"
5301+
class="checkbox-no-label">
5302+
</el-checkbox>
52395303
<!-- 删除按钮定位在视频右上角 -->
52405304
<el-button class="delete-overlay-btn" type="danger" circle @click="deleteVideo(video)">
52415305
<i class="fa-solid fa-trash"></i>

static/js/locales.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -557,7 +557,7 @@ const translations = {
557557
'gsvPromptText': '参考音频文本',
558558
'gsvPromptTextPlaceholder': '请输入参考音频中对应的文本',
559559
'addRefAudio': '添加参考音色',
560-
'gsvNotice1': '1. 请点击上方文档链接,下载GSV-V4版本的整合包',
560+
'gsvNotice1': '1. 请点击上方文档链接,下载GSV-V4版本的整合包,推荐使用v2版本',
561561
'gsvNotice2': '2. 请在整合包项目路径下打开终端,执行` runtime/python.exe api_v2.py -a 127.0.0.1 -p 9880 -c GPT_SoVITS/configs/tts_infer.yaml `启动服务',
562562
'gsvServer': 'GSV服务器URL(可以输入多个,一行一个)',
563563
'gsvServerPlaceholder': '请输入GSV服务器URL',
@@ -729,6 +729,10 @@ key3`,
729729
'customTTSspeed': '自定义TTS语速',
730730
'gsvGsvAudioPath': '参考音频路径(如果上传了文件可不填)',
731731
'gsvGsvAudioPathPlaceholder': '请输入参考音频路径',
732+
'selectAll': '全选',
733+
'batchDelete': '批量删除',
734+
'batchDeleteSuccess': '批量删除成功',
735+
'batchDeleteFailed': '批量删除失败',
732736
},
733737
'en-US': {
734738
'chat': 'Chat',
@@ -1285,7 +1289,7 @@ key3`,
12851289
'gsvPromptText ':' Reference audio text',
12861290
'gsvPromptTextPlaceholder ':' Please enter the corresponding text in the reference audio',
12871291
'addRefAudio': 'Add reference sound',
1288-
'gsvNotice': '1. Please click the document link above to download the GSV-V4 integrated package',
1292+
'gsvNotice1': '1. Please click the document link above to download the GSV-V4 integrated package.It is recommended to use the v2 version',
12891293
'gsvNotice2': '2. Please open the terminal under the integration package project path, and execute ` runtime/python.exe api_v2.py -a 127.0.0.1 -p 9880 -c GPT_SoVITS/configs/tts_infer.yaml ` to start the service.',
12901294
'gsvServer': 'GSV Server URL(You can enter multiple items, one per line.)',
12911295
'gsvServerPlaceholder': 'Please enter the GSV Server URL',
@@ -1457,5 +1461,9 @@ Key3`,
14571461
'customTTSspeed': 'Custom TTS speed',
14581462
'gsvGsvAudioPath':'Refer to the audio path (if the file is uploaded, leave it blank)',
14591463
'gsvGsvAudioPathPlaceholder': 'Please enter the audio path',
1464+
'selectAll': 'Select All',
1465+
'batchDelete': 'Batch Delete',
1466+
'batchDeleteSuccess': 'Batch delete success',
1467+
'batchDeleteFailed': 'Batch delete fail',
14601468
}
14611469
};

static/js/renderer.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,45 @@ const app = Vue.createApp({
171171
},
172172
},
173173
computed: {
174+
allChecked: {
175+
get() {
176+
return this.textFiles.length > 0 && this.selectedFiles.length === this.textFiles.length;
177+
},
178+
set(val) {
179+
this.selectedFiles = val ? this.textFiles.map(f => f.unique_filename) : [];
180+
}
181+
},
182+
indeterminate() {
183+
return (
184+
this.selectedFiles.length > 0 &&
185+
this.selectedFiles.length < this.textFiles.length
186+
);
187+
},
188+
// 图片全选状态
189+
allImagesChecked: {
190+
get() {
191+
return this.imageFiles.length > 0 &&
192+
this.selectedImages.length === this.imageFiles.length
193+
},
194+
set(val) {
195+
this.selectedImages = val
196+
? this.imageFiles.map(i => i.unique_filename)
197+
: []
198+
}
199+
},
200+
201+
// 视频全选状态
202+
allVideosChecked: {
203+
get() {
204+
return this.videoFiles.length > 0 &&
205+
this.selectedVideos.length === this.videoFiles.length
206+
},
207+
set(val) {
208+
this.selectedVideos = val
209+
? this.videoFiles.map(v => v.unique_filename)
210+
: []
211+
}
212+
},
174213
sidebarStyle() {
175214
return {
176215
width: this.isMobile ?

static/js/vrm.js

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,9 @@ loader.crossOrigin = 'anonymous';
164164

165165
loader.register( ( parser ) => {
166166

167-
return new VRMLoaderPlugin( parser );
167+
return new VRMLoaderPlugin(parser,{
168+
lookAt: { type: 'bone' }
169+
});
168170

169171
} );
170172

@@ -913,9 +915,15 @@ async function getAnimationFiles() {
913915

914916
// 4. 如果没有任何选中,给个兜底
915917
if (urls.length === 0) {
916-
const fallback = `${window.location.protocol}//${window.location.host}/vrm/animations/akimbo.vrma`;
918+
const fallback =
919+
[
920+
`${window.location.protocol}//${window.location.host}/vrm/animations/akimbo.vrma`,
921+
`${window.location.protocol}//${window.location.host}/vrm/animations/play_fingers.vrma`,
922+
`${window.location.protocol}//${window.location.host}/vrm/animations/scratch_head.vrma`,
923+
`${window.location.protocol}//${window.location.host}/vrm/animations/stretch.vrma`
924+
];
917925
console.warn('没有选中任何动作,使用兜底动画');
918-
return [fallback];
926+
return fallback;
919927
}
920928

921929
console.log('本次要加载的 VRMA:', urls);
@@ -1492,12 +1500,24 @@ loader.load(
14921500
// calling these functions greatly improves the performance
14931501
VRMUtils.removeUnnecessaryVertices( gltf.scene );
14941502

1495-
gltf.scene.traverse( ( obj ) => {
1496-
if ( obj.isMesh ) {
1497-
obj.castShadow = true; // 产生阴影
1498-
obj.receiveShadow = true; // 自己也能被影子覆盖(看需求)
1503+
// 添加材质修复
1504+
gltf.scene.traverse((obj) => {
1505+
if (obj.isMesh && obj.material) {
1506+
// 解决透明材质黑边问题
1507+
if (obj.material.transparent) {
1508+
obj.material.alphaTest = 0.5;
1509+
obj.material.depthWrite = false;
1510+
obj.material.needsUpdate = true;
14991511
}
1500-
} );
1512+
1513+
// 确保正确混合模式
1514+
obj.material.blending = THREE.NormalBlending;
1515+
obj.material.premultipliedAlpha = true;
1516+
1517+
// 设置渲染顺序
1518+
obj.renderOrder = obj.material.transparent ? 1 : 0;
1519+
}
1520+
});
15011521

15021522
VRMUtils.combineSkeletons( gltf.scene );
15031523
VRMUtils.combineMorphs( vrm );
@@ -1716,6 +1736,9 @@ function animate() {
17161736
if (currentVrm) {
17171737
// 只需要更新 VRM 和 Mixer
17181738
currentVrm.update(deltaTime);
1739+
if (currentVrm.lookAt) {
1740+
currentVrm.lookAt.update(deltaTime);
1741+
}
17191742
}
17201743

17211744
if (currentMixer) {
@@ -2451,12 +2474,24 @@ async function switchToModel(index) {
24512474
VRMUtils.rotateVRM0(vrm); // 旋转 VRM 使其面向正前方
24522475
// 优化性能
24532476
VRMUtils.removeUnnecessaryVertices(gltf.scene);
2454-
gltf.scene.traverse( ( obj ) => {
2455-
if ( obj.isMesh ) {
2456-
obj.castShadow = true; // 产生阴影
2457-
obj.receiveShadow = true; // 自己也能被影子覆盖(看需求)
2477+
// 添加材质修复
2478+
gltf.scene.traverse((obj) => {
2479+
if (obj.isMesh && obj.material) {
2480+
// 解决透明材质黑边问题
2481+
if (obj.material.transparent) {
2482+
obj.material.alphaTest = 0.5;
2483+
obj.material.depthWrite = false;
2484+
obj.material.needsUpdate = true;
24582485
}
2459-
} );
2486+
2487+
// 确保正确混合模式
2488+
obj.material.blending = THREE.NormalBlending;
2489+
obj.material.premultipliedAlpha = true;
2490+
2491+
// 设置渲染顺序
2492+
obj.renderOrder = obj.material.transparent ? 1 : 0;
2493+
}
2494+
});
24602495

24612496
VRMUtils.combineSkeletons(gltf.scene);
24622497
VRMUtils.combineMorphs(vrm);

static/js/vue_data.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -470,10 +470,7 @@ let vue_data = {
470470
'<sad>',
471471
'<neutral>',
472472
'<surprised>',
473-
'<relaxed>',
474-
'<blink>',
475-
'<blinkLeft>',
476-
'<blinkRight>'],
473+
'<relaxed>'],
477474
newGsvAudio: {
478475
name: '',
479476
path: '',
@@ -1001,6 +998,13 @@ let vue_data = {
1001998
textFiles: [],
1002999
imageFiles: [],
10031000
videoFiles: [],
1001+
selectedFiles: [], // 存 unique_filename
1002+
selectedImages: [],
1003+
allImagesChecked: false,
1004+
indeterminateImages: false,
1005+
selectedVideos: [],
1006+
allVideosChecked: false,
1007+
indeterminateVideos: false,
10041008
subMenu: '', // 新增子菜单状态
10051009
isWorldviewSettingsExpanded: true,
10061010
isRandomSettingsExpanded: true,

0 commit comments

Comments
 (0)