测试:将ip地址都改为192.168.1.164

This commit is contained in:
xiao12feng8 2026-02-01 17:46:31 +08:00
parent e2765ecf00
commit 92386f4597
15 changed files with 43982 additions and 3038 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
归档/
xunifriend_RaeeC/runtime/log/202602/01.log

View File

@ -4,7 +4,7 @@ import re
import random
import oss2
from fastapi import APIRouter, Depends, HTTPException, Query
from fastapi import APIRouter, Depends, HTTPException, Query, Request
from pydantic import BaseModel, Field
from sqlalchemy import desc
from sqlalchemy.orm import Session
@ -474,7 +474,7 @@ def _pick_available_voice(db: Session, lover: Lover, user_row: User) -> VoiceLib
return candidate
def _upload_tts_to_oss(file_bytes: bytes, lover_id: int, message_id: int) -> str:
def _upload_tts_to_oss(file_bytes: bytes, lover_id: int, message_id: int, request: Request = None) -> str:
"""
上传 TTS 音频文件
优先使用 OSS如果未配置则保存到本地
@ -520,8 +520,16 @@ def _upload_tts_to_oss(file_bytes: bytes, lover_id: int, message_id: int) -> str
with open(file_path, "wb") as f:
f.write(file_bytes)
# 返回完整 URL使用环境变量配置的后端地址
backend_url = os.getenv("BACKEND_URL", "http://127.0.0.1:8000")
# 自动检测请求来源,生成正确的 URL
if request:
# 从请求头获取 Host
host = request.headers.get("host", "127.0.0.1:8000")
scheme = "https" if request.url.scheme == "https" else "http"
backend_url = f"{scheme}://{host}"
else:
# 降级使用环境变量
backend_url = os.getenv("BACKEND_URL", "http://127.0.0.1:8000")
return f"{backend_url.rstrip('/')}/tts/{lover_id}/{message_id}.mp3"
except Exception as exc:
raise HTTPException(status_code=500, detail=f"保存语音文件失败: {exc}") from exc
@ -653,6 +661,7 @@ def list_messages(
@router.post("/messages/tts/{message_id}", response_model=ApiResponse[TTSOut])
def generate_message_tts(
message_id: int,
request: Request,
db: Session = Depends(get_db),
user: AuthedUser = Depends(get_current_user),
):
@ -706,7 +715,7 @@ def generate_message_tts(
model=model,
voice=voice.voice_code,
)
url = _upload_tts_to_oss(audio_bytes, lover.id, msg.id)
url = _upload_tts_to_oss(audio_bytes, lover.id, msg.id, request)
except HTTPException as exc:
detail_text = str(exc.detail) if hasattr(exc, "detail") else str(exc)
fallback_done = False
@ -721,7 +730,7 @@ def generate_message_tts(
model=fallback_model,
voice=fallback_voice,
)
url = _upload_tts_to_oss(audio_bytes, lover.id, msg.id)
url = _upload_tts_to_oss(audio_bytes, lover.id, msg.id, request)
msg.tts_voice_id = None # 兜底音色不绑定库ID
msg.tts_model_id = fallback_model
fallback_done = True

BIN
public/tts/47/776.mp3 Normal file

Binary file not shown.

View File

@ -76,6 +76,8 @@
</template>
<script>
import { baseURL } from '@/utils/request.js'
export default {
data() {
return {
@ -262,7 +264,7 @@ export default {
},
computed: {
baseURL() {
return 'http://127.0.0.1:8080';
return baseURL;
}
}
}

View File

@ -275,6 +275,7 @@
SingGenerate,
SingGenerateTask
} from '@/utils/api.js'
import { baseURL, baseURLPy } from '@/utils/request.js'
import notHave from '@/components/not-have.vue';
import topSafety from '@/components/top-safety.vue';
import ai from '@/components/ai.vue';
@ -353,8 +354,8 @@
//
editModalVisible: false,
editingMessage: null,
baseURL: 'http://127.0.0.1:8080',
baseURLPy: 'http://127.0.0.1:8000',
baseURL: baseURL,
baseURLPy: baseURLPy,
//
messageSentTime: 0, //
}

View File

@ -56,6 +56,7 @@
<script>
import { LoverBasic } from '@/utils/api.js';
import { baseURLPy } from '@/utils/request.js';
export default {
data() {
@ -136,7 +137,11 @@ export default {
connectWebSocket() {
const token = uni.getStorageSync('token');
const wsUrl = `ws://127.0.0.1:8000/voice/call?token=${token}&ptt=true`;
// http:// ws://https:// wss://
const wsBaseUrl = baseURLPy.replace('http://', 'ws://').replace('https://', 'wss://');
const wsUrl = `${wsBaseUrl}/voice/call?token=${token}&ptt=true`;
console.log('WebSocket URL:', wsUrl);
this.websocket = uni.connectSocket({
url: wsUrl,

View File

@ -117,6 +117,7 @@ import {
ConfigVoicesAvailable,
LoverVoiceSimple
} from '@/utils/api.js'
import { baseURLPy } from '@/utils/request.js'
import notHave from '@/components/not-have.vue';
import topSafety from '@/components/top-safety.vue';
@ -145,7 +146,7 @@ export default {
cloning: false,
cloneStatus: '',
cloneVoiceId: '',
baseURLPy: 'http://127.0.0.1:8000',
baseURLPy: baseURLPy,
// 'file' 'url'
audioInputMode: 'url', // 使 URL
audioUrlInput: '', // URL

View File

@ -63,7 +63,7 @@
:duration="300"
:indicator-dots="false">
<!-- 首页内容 -->
<!-- 首页内容 (index 0) -->
<swiper-item>
<scroll-view class="swiper-scroll" scroll-y="true">
<view class="backA"></view>
@ -140,19 +140,33 @@
</scroll-view>
</swiper-item>
<!-- 聊天页面 -->
<!-- 聊天页面 (index 1) -->
<swiper-item>
<view class="swiper-content" @click="tochat">
<view class="feature-page">
<view class="feature-icon">💬</view>
<view class="feature-title">聊天</view>
<view class="feature-desc">与她开始对话</view>
<view class="feature-btn">进入聊天</view>
<scroll-view class="swiper-scroll" scroll-y="true">
<view class="chat-preview-container">
<view class="chat-preview-header">
<view class="chat-preview-title">💬 与她聊天 (Tab索引: {{currentTab}})</view>
<view class="chat-preview-btn" @click="tochat">进入完整聊天</view>
</view>
<!-- 聊天记录预览 -->
<view class="chat-preview-list">
<view class="chat-preview-tip">点击上方按钮进入完整聊天页面</view>
<view class="chat-preview-image">
<image
v-if="loverBasicList"
:src="loverBasicList.image_url || '/static/images/avatar.png'"
mode="aspectFill">
</image>
</view>
<view class="chat-preview-name">{{ loverBasicList.name || '你的恋人' }}</view>
<view class="chat-preview-desc">开始你们的对话吧~</view>
</view>
</view>
</view>
</scroll-view>
</swiper-item>
<!-- 唱歌页面 -->
<!-- 唱歌页面 (index 2) -->
<swiper-item>
<view class="swiper-content feature-page">
<view class="feature-icon">🎤</view>
@ -171,7 +185,7 @@
</view>
</swiper-item>
<!-- 跳舞页面 -->
<!-- 跳舞页面 (index 3) -->
<swiper-item>
<view class="swiper-content feature-page">
<view class="feature-icon">💃</view>
@ -188,19 +202,84 @@
</view>
</swiper-item>
<!-- 换服装页面 -->
<!-- 换服装页面 (index 4) -->
<swiper-item>
<view class="swiper-content" @click="toreplacement">
<view class="feature-page">
<view class="feature-icon">👗</view>
<view class="feature-title">换服装</view>
<view class="feature-desc">为她挑选不同的服装</view>
<view class="feature-btn">进入换装</view>
<scroll-view class="swiper-scroll" scroll-y="true">
<view class="outfit-container">
<view class="outfit-header">
<text class="outfit-title">👗 换装搭配</text>
<text class="outfit-count">剩余次数: {{ outfitData ? outfitData.clothes_num : 0 }}</text>
</view>
<view v-if="!outfitData" class="outfit-loading">
<text>加载中...</text>
</view>
<view v-else class="outfit-content">
<!-- 上衣 -->
<view class="outfit-section">
<view class="section-title-top">上衣</view>
<view class="outfit-grid-wrapper">
<view
v-for="(item, index) in outfitData.top"
:key="item.id"
@click="selectOutfitTop(item)"
class="outfit-item-wrapper">
<view class="outfit-grid-inner" :style="getOutfitBorderStyle(item.id, 'top')">
<image class="outfit-grid-img" :src="item.image_url" mode="aspectFill"></image>
<view v-if="item.is_lock && !item.is_free" class="outfit-grid-lock">🔒</view>
</view>
</view>
<view style="clear: both;"></view>
</view>
</view>
<!-- 下装 -->
<view class="outfit-section">
<view class="section-title-top">下装</view>
<view class="outfit-grid-wrapper">
<view
v-for="(item, index) in outfitData.bottom"
:key="item.id"
@click="selectOutfitBottom(item)"
class="outfit-item-wrapper">
<view class="outfit-grid-inner" :style="getOutfitBorderStyle(item.id, 'bottom')">
<image class="outfit-grid-img" :src="item.image_url" mode="aspectFill"></image>
<view v-if="item.is_lock && !item.is_free" class="outfit-grid-lock">🔒</view>
</view>
</view>
<view style="clear: both;"></view>
</view>
</view>
<!-- 连体服 -->
<view class="outfit-section">
<view class="section-title-top">连体服</view>
<view class="outfit-grid-wrapper">
<view
v-for="(item, index) in outfitData.dress"
:key="item.id"
@click="selectOutfitDress(item)"
class="outfit-item-wrapper">
<view class="outfit-grid-inner" :style="getOutfitBorderStyle(item.id, 'dress')">
<image class="outfit-grid-img" :src="item.image_url" mode="aspectFill"></image>
<view v-if="item.is_lock && !item.is_free" class="outfit-grid-lock">🔒</view>
</view>
</view>
<view style="clear: both;"></view>
</view>
</view>
<!-- 生成按钮 -->
<view class="outfit-generate-btn" @click="generateOutfit">
<text>生成换装</text>
</view>
</view>
</view>
</view>
</scroll-view>
</swiper-item>
<!-- 刷礼物页面 -->
<!-- 刷礼物页面 (index 5) -->
<swiper-item>
<view class="swiper-content" @click="togift">
<view class="feature-page">
@ -212,7 +291,7 @@
</view>
</swiper-item>
<!-- 商城页面 -->
<!-- 商城页面 (index 6) -->
<swiper-item>
<view class="swiper-content feature-page">
<view class="feature-icon">🛒</view>
@ -235,7 +314,7 @@
</view>
</swiper-item>
<!-- 短剧页面 -->
<!-- 短剧页面 (index 7) -->
<swiper-item>
<view class="swiper-content feature-page">
<view class="feature-icon">🎬</view>
@ -288,7 +367,9 @@
SingSongs,
SingGenerate,
SingGenerateTask,
DanceGenerate
DanceGenerate,
OutfitList,
OutfitChange
} from '@/utils/api.js'
import notHave from '@/components/not-have.vue';
import topSafety from '@/components/top-safety.vue';
@ -322,6 +403,12 @@
dancePrompt: '',
singSongsList: [],
songId: 0,
//
outfitData: null,
selectedTopId: null,
selectedBottomId: null,
selectedDressId: null,
outfitMode: null, // 1=, 2=+
statusBarHeight: uni.getWindowInfo().statusBarHeight,
currentStep: 0,
chartData: {},
@ -382,9 +469,27 @@
methods: {
// Tab
switchTab(index) {
console.log('点击 Tab切换到索引:', index, '对应 Tab:', this.tabs[index].name);
// "" tab1
if (index === 1) {
this.tochat();
return;
}
// "" tab4
if (index === 4) {
console.log('切换到换服装 tab准备加载数据');
//
setTimeout(() => {
this.loadOutfitData();
}, 300);
}
this.currentTab = index;
},
onSwiperChange(e) {
console.log('Swiper 滑动,当前索引:', e.detail.current, '对应 Tab:', this.tabs[e.detail.current].name);
this.currentTab = e.detail.current;
},
//
@ -433,6 +538,202 @@
}
});
},
//
loadOutfitData() {
console.log('开始加载换装数据,当前 outfitData:', this.outfitData);
if (this.outfitData) {
console.log('数据已存在,跳过加载');
return; //
}
console.log('显示加载提示...');
uni.showLoading({ title: '加载中...' });
console.log('调用 OutfitList API...');
OutfitList({}).then(res => {
console.log('OutfitList API 返回:', res);
uni.hideLoading();
if (res.code == 1) {
this.outfitData = res.data;
console.log('设置 outfitData 成功:', this.outfitData);
// 使
this.processOutfitData();
// 使
this.selectCurrentOutfit();
} else {
console.error('API 返回错误:', res.msg);
uni.showToast({ title: res.msg || '加载失败', icon: 'none' });
}
}).catch(err => {
console.error('OutfitList API 异常:', err);
uni.hideLoading();
uni.showToast({ title: '网络错误,请检查后端服务', icon: 'none' });
});
},
//
processOutfitData() {
if (!this.outfitData) return;
const { current_outfit, owned_outfit_ids } = this.outfitData;
//
this.outfitData.top.forEach(item => {
item.is_current = current_outfit.top_id === item.id;
item.is_lock = !owned_outfit_ids.includes(item.id);
});
//
this.outfitData.bottom.forEach(item => {
item.is_current = current_outfit.bottom_id === item.id;
item.is_lock = !owned_outfit_ids.includes(item.id);
});
//
this.outfitData.dress.forEach(item => {
item.is_current = current_outfit.dress_id === item.id;
item.is_lock = !owned_outfit_ids.includes(item.id);
});
},
// 使
selectCurrentOutfit() {
if (!this.outfitData || !this.outfitData.current_outfit) return;
const { current_outfit } = this.outfitData;
//
if (current_outfit.dress_id) {
this.outfitMode = 1;
this.selectedDressId = current_outfit.dress_id;
return;
}
//
if (current_outfit.top_id || current_outfit.bottom_id) {
this.outfitMode = 2;
this.selectedTopId = current_outfit.top_id;
this.selectedBottomId = current_outfit.bottom_id;
}
},
//
getOutfitBorderStyle(itemId, type) {
let isSelected = false;
if (type === 'top') {
isSelected = this.selectedTopId === itemId;
} else if (type === 'bottom') {
isSelected = this.selectedBottomId === itemId;
} else if (type === 'dress') {
isSelected = this.selectedDressId === itemId;
}
return {
border: isSelected ? '5rpx solid #ff0000' : '5rpx solid #ddd',
boxShadow: isSelected ? '0 4rpx 20rpx rgba(255, 0, 0, 0.4)' : '0 4rpx 16rpx rgba(0, 0, 0, 0.15)'
};
},
//
selectOutfitTop(item) {
console.log('点击上衣item.id:', item.id, '当前selectedTopId:', this.selectedTopId);
if (item.is_lock && !item.is_free) {
uni.showToast({ title: '该服装未解锁', icon: 'none' });
return;
}
if (this.outfitMode === 1 && this.selectedDressId) {
uni.showToast({ title: '连体服模式下不能选择上衣', icon: 'none' });
return;
}
this.outfitMode = 2;
this.selectedTopId = this.selectedTopId === item.id ? null : item.id;
console.log('选择后selectedTopId:', this.selectedTopId);
},
//
selectOutfitBottom(item) {
console.log('点击下装item.id:', item.id, '当前selectedBottomId:', this.selectedBottomId);
if (item.is_lock && !item.is_free) {
uni.showToast({ title: '该服装未解锁', icon: 'none' });
return;
}
if (this.outfitMode === 1 && this.selectedDressId) {
uni.showToast({ title: '连体服模式下不能选择下装', icon: 'none' });
return;
}
this.outfitMode = 2;
this.selectedBottomId = this.selectedBottomId === item.id ? null : item.id;
console.log('选择后selectedBottomId:', this.selectedBottomId);
},
//
selectOutfitDress(item) {
console.log('点击连体服item.id:', item.id, '当前selectedDressId:', this.selectedDressId);
if (item.is_lock && !item.is_free) {
uni.showToast({ title: '该服装未解锁', icon: 'none' });
return;
}
if (this.outfitMode === 2 && (this.selectedTopId || this.selectedBottomId)) {
uni.showToast({ title: '上衣下装模式下不能选择连体服', icon: 'none' });
return;
}
this.outfitMode = 1;
this.selectedDressId = this.selectedDressId === item.id ? null : item.id;
if (this.selectedDressId) {
this.selectedTopId = null;
this.selectedBottomId = null;
}
console.log('选择后selectedDressId:', this.selectedDressId);
},
//
generateOutfit() {
if (!this.outfitData || !this.outfitData.clothes_num) {
uni.showToast({ title: '换装次数不足', icon: 'none' });
return;
}
let params = {};
if (this.outfitMode === 1 && this.selectedDressId) {
params = { dress_item_id: this.selectedDressId, save_to_look: false };
} else if (this.outfitMode === 2 && (this.selectedTopId || this.selectedBottomId)) {
params = {
top_item_id: this.selectedTopId || '',
bottom_item_id: this.selectedBottomId || '',
save_to_look: false
};
} else {
uni.showToast({ title: '请先选择服装', icon: 'none' });
return;
}
uni.showLoading({ title: '生成中...' });
OutfitChange(params).then(res => {
uni.hideLoading();
if (res.code == 1) {
uni.showToast({ title: '换装成功', icon: 'success' });
//
this.outfitData = null;
this.loadOutfitData();
} else {
uni.showToast({ title: res.msg, icon: 'none' });
}
}).catch(() => {
uni.hideLoading();
});
},
//
getSingGenerateTask(task_id) {
const that = this;
@ -1395,4 +1696,256 @@
background: linear-gradient(135deg, #9F47FF 0%, #0053FA 100%);
height: 4rpx;
}
</style>
</style>
/* 聊天预览容器样式 */
.chat-preview-container {
width: 100%;
height: 100%;
padding: 40rpx;
box-sizing: border-box;
}
.chat-preview-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 40rpx;
padding-bottom: 20rpx;
border-bottom: 2rpx solid #f0f0f0;
}
.chat-preview-title {
font-size: 36rpx;
font-weight: bold;
color: #333;
}
.chat-preview-btn {
padding: 15rpx 30rpx;
background: linear-gradient(135deg, #9F47FF 0%, #0053FA 100%);
color: #fff;
border-radius: 30rpx;
font-size: 26rpx;
}
.chat-preview-list {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 60rpx 40rpx;
}
.chat-preview-tip {
font-size: 28rpx;
color: #999;
margin-bottom: 60rpx;
text-align: center;
}
.chat-preview-image {
width: 300rpx;
height: 300rpx;
border-radius: 50%;
overflow: hidden;
margin-bottom: 30rpx;
box-shadow: 0 8rpx 20rpx rgba(159, 71, 255, 0.2);
}
.chat-preview-image image {
width: 100%;
height: 100%;
}
.chat-preview-name {
font-size: 40rpx;
font-weight: bold;
color: #333;
margin-bottom: 15rpx;
}
.chat-preview-desc {
font-size: 28rpx;
color: #666;
}
/* 换装页面样式 - 和谐配色 */
.outfit-container {
width: 100%;
min-height: 100%;
padding: 30rpx;
background: linear-gradient(180deg, #f8f9fa 0%, #ffffff 100%);
box-sizing: border-box;
}
.outfit-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20rpx 0;
margin-bottom: 30rpx;
border-bottom: 1rpx solid #e8e8e8;
}
.outfit-title {
font-size: 36rpx;
font-weight: bold;
color: #333;
}
.outfit-count {
font-size: 26rpx;
color: #666;
padding: 8rpx 20rpx;
background: #f5f5f5;
border-radius: 20rpx;
}
.outfit-loading {
display: flex;
justify-content: center;
align-items: center;
padding: 100rpx 0;
color: #999;
font-size: 28rpx;
}
.outfit-content {
width: 100%;
padding-bottom: 40rpx;
}
.outfit-section {
margin-bottom: 50rpx;
background: #fff;
border-radius: 20rpx;
padding: 30rpx 20rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
}
.section-title {
font-size: 30rpx;
font-weight: 500;
color: #555;
margin-bottom: 25rpx;
padding-left: 10rpx;
border-left: 4rpx solid #8a7cff;
}
.section-title-top {
font-size: 70rpx !important;
font-weight: bold !important;
color: #000 !important;
text-align: center !important;
margin: 0 0 40rpx 0 !important;
padding: 20rpx 0 !important;
background: #f0f0f0 !important;
border-radius: 12rpx !important;
display: block !important;
width: 100% !important;
}
/* 网格容器 - 使用固定宽度 */
.outfit-grid-wrapper {
width: 100%;
overflow: hidden;
text-align: left;
}
.outfit-item-wrapper {
float: left;
width: 220rpx;
margin-right: 15rpx;
margin-bottom: 20rpx;
box-sizing: border-box;
}
.outfit-grid-inner {
position: relative;
width: 100%;
height: 280rpx;
border-radius: 12rpx;
overflow: hidden;
background: #fff;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.15);
transition: all 0.3s ease;
border: 5rpx solid #ddd;
box-sizing: border-box;
}
.outfit-grid-item-selected .outfit-grid-inner {
border: 5rpx solid #ff0000 !important;
box-shadow: 0 4rpx 20rpx rgba(255, 0, 0, 0.4) !important;
}
.outfit-grid-img {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: block;
object-fit: cover;
}
.outfit-check-mark {
position: absolute !important;
top: 8rpx !important;
left: 8rpx !important;
width: 40rpx !important;
height: 40rpx !important;
background: #8a7cff;
color: #fff;
font-size: 28rpx;
font-weight: bold;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
z-index: 10 !important;
pointer-events: none;
line-height: 1;
}
.outfit-grid-badge {
position: absolute;
top: 8rpx;
right: 8rpx;
padding: 8rpx 16rpx;
background: rgba(255, 0, 0, 0.9);
color: #fff;
font-size: 28rpx;
font-weight: bold;
border-radius: 12rpx;
z-index: 2;
}
.outfit-grid-lock {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 60rpx;
opacity: 0.8;
z-index: 3;
pointer-events: none;
}
.outfit-generate-btn {
margin: 20rpx 0;
padding: 28rpx 0;
background: linear-gradient(135deg, #8a7cff 0%, #6b5ce7 100%);
color: #fff;
text-align: center;
border-radius: 16rpx;
font-size: 32rpx;
font-weight: 500;
box-shadow: 0 8rpx 20rpx rgba(138, 124, 255, 0.3);
transition: all 0.3s ease;
}
.outfit-generate-btn:active {
transform: scale(0.98);
box-shadow: 0 4rpx 12rpx rgba(138, 124, 255, 0.3);
}

View File

@ -118,6 +118,7 @@
WxappGetPhone,
AppLoginWx
} from '@/utils/api.js'
import { baseURLPy } from '@/utils/request.js'
import {
isPhone,
getWxCode
@ -146,7 +147,7 @@
dataLogin: [],
selectStats: false,
inviteCode: '', //
baseURLPy: 'http://127.0.0.1:8000',
baseURLPy: baseURLPy,
}
},
computed: {

View File

@ -43,6 +43,8 @@
</template>
<script>
import { baseURLPy } from '@/utils/request.js'
export default {
data() {
return {
@ -50,7 +52,7 @@
inviteCount: 0,
inviteReward: 0,
qrCodeUrl: '',
baseURLPy: 'http://127.0.0.1:8000',
baseURLPy: baseURLPy,
}
},
onLoad() {

View File

@ -1,10 +1,10 @@
// 本地开发 - 电脑浏览器调试使用
export const baseURL = 'http://127.0.0.1:8080'
export const baseURLPy = 'http://127.0.0.1:8000'
// export const baseURL = 'http://127.0.0.1:8080'
// export const baseURLPy = 'http://127.0.0.1:8000'
// 开发环境 - 手机端调试使用局域网IP需要时取消注释
// export const baseURL = 'http://192.168.1.164:8080'
// export const baseURLPy = 'http://192.168.1.164:8000'
export const baseURL = 'http://192.168.1.164:8080'
export const baseURLPy = 'http://192.168.1.164:8000'
export const sid = 2

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,4 @@
# 主要功能
1. 将密码校验删除,因为无法生成模型,用最简单的方法来尝试这些内容。
- [ ] 增加tab栏但是还没有加上对应的功能
3. 增加聊天背景选择功能,会员可以自定义背景
@ -9,10 +10,15 @@
- [x] 克隆音色API填写然后给你测试
7. 二维码推广功能创建邀请码邀请新用户但是没有二维码生成API
# 次要接口对齐和UI完善
> 1. Tab栏中各内容对齐
> 2. 短剧、商城、音乐库对接
> 3. UI完善对齐筑梦岛
上线需调整
1. oss存储桶用来存放播放的音色
2. DashCope阿里云模型apisk-xxx 并启用下面模型
- qwen-plusAI对话聊天