修复主角回复聊天气泡问题,加入聊天轮数引用机制

This commit is contained in:
taiyi 2026-04-12 15:46:30 +08:00
parent 23e3e68fa9
commit 47fc227d59
5 changed files with 123 additions and 32 deletions

View File

@ -14,6 +14,7 @@ from utils.database import get_db
from utils.security import get_current_admin_user, get_current_user
from models.database import User, Pet, Background, ChatLog, UserWallet, UserBackgroundRelation, BackgroundPetConfig
from services.token_service import TokenService
from config.settings import get_chat_context_rounds, set_chat_context_rounds
logger = logging.getLogger(__name__)
admin_router = APIRouter()
@ -890,7 +891,8 @@ async def get_system_config(current_admin: Dict = Depends(get_current_admin_user
"default_model": "gpt-4",
"temperature": 0.7,
"max_tokens": 2000,
"top_p": 0.9
"top_p": 0.9,
"chat_context_rounds": get_chat_context_rounds()
},
"voice": {
"default_tts_provider": "volcengine",
@ -913,10 +915,30 @@ async def update_system_config(
):
"""Update system configuration (admin only)"""
logger.info(f"Admin {current_admin.get('id')} updating system config")
# TODO: 实现配置更新逻辑
ai_config = config_data.get("ai") if isinstance(config_data, dict) else None
if isinstance(ai_config, dict) and "chat_context_rounds" in ai_config:
rounds = ai_config.get("chat_context_rounds", 0)
try:
rounds = int(rounds)
except (TypeError, ValueError):
raise HTTPException(status_code=400, detail="chat_context_rounds 必须是整数")
if rounds < 0:
raise HTTPException(status_code=400, detail="chat_context_rounds 不能小于0")
if rounds > 50:
raise HTTPException(status_code=400, detail="chat_context_rounds 不能大于50")
set_chat_context_rounds(rounds)
return {
"success": True,
"message": "System configuration updated successfully"
"message": "System configuration updated successfully",
"data": {
"ai": {
"chat_context_rounds": get_chat_context_rounds()
}
}
}
@admin_router.patch("/users/{user_id}/status")

View File

@ -93,6 +93,20 @@ class Settings(BaseSettings):
DEFAULT_BACKGROUND_ID: int = int(os.getenv("DEFAULT_BACKGROUND_ID", "1"))
DEFAULT_DAILY_QUOTA: int = int(os.getenv("DEFAULT_DAILY_QUOTA", "20"))
# 聊天上下文轮数1轮=一组用户+AI0表示不带历史上下文
CHAT_CONTEXT_ROUNDS: int = int(os.getenv("CHAT_CONTEXT_ROUNDS", "0"))
settings = Settings()
# 运行时可动态更新(用于后台系统配置即时生效)
_runtime_chat_context_rounds = max(0, int(getattr(settings, "CHAT_CONTEXT_ROUNDS", 0) or 0))
def get_chat_context_rounds() -> int:
return max(0, int(_runtime_chat_context_rounds))
def set_chat_context_rounds(rounds: int) -> None:
global _runtime_chat_context_rounds
_runtime_chat_context_rounds = max(0, int(rounds))

View File

@ -14,6 +14,7 @@ import asyncio
from models.database import Pet, Background, BackgroundPetConfig, ChatLog
from services.doubao_service import doubao_service
from config.settings import get_chat_context_rounds
logger = logging.getLogger(__name__)
@ -52,18 +53,22 @@ async def send_message(db_session: AsyncSession, user_id: int, message: str, pet
if not background:
raise ValueError(f"Background with id {background_id} not found")
history_result = await db_session.execute(
sa_select(ChatLog).where(
ChatLog.user_id == user_id,
ChatLog.pet_id == pet_id,
ChatLog.bg_id == background_id
).order_by(ChatLog.created_at.desc()).limit(10)
)
history_logs = history_result.scalars().all()
history = [
{"is_user": True, "content": log.user_msg, "created_at": log.created_at}
for log in reversed(history_logs)
]
context_rounds = get_chat_context_rounds()
history = []
if context_rounds > 0:
history_result = await db_session.execute(
sa_select(ChatLog).where(
ChatLog.user_id == user_id,
ChatLog.pet_id == pet_id,
ChatLog.bg_id == background_id
).order_by(ChatLog.created_at.desc()).limit(context_rounds)
)
history_logs = history_result.scalars().all()
for log in reversed(history_logs):
if log.user_msg:
history.append({"is_user": True, "content": log.user_msg, "created_at": log.created_at})
if log.ai_msg:
history.append({"is_user": False, "content": log.ai_msg, "created_at": log.created_at})
messages = doubao_service.build_messages(
system_prompt=pet.global_prompt,
@ -233,18 +238,22 @@ async def send_message_stream(db_session: AsyncSession, user_id: int, message: s
yield f"错误找不到ID为{background_id}的背景"
return
history_result = await db_session.execute(
sa_select(ChatLog).where(
ChatLog.user_id == user_id,
ChatLog.pet_id == pet_id,
ChatLog.bg_id == background_id
).order_by(ChatLog.created_at.desc()).limit(10)
)
history_logs = history_result.scalars().all()
history = [
{"is_user": True, "content": log.user_msg, "created_at": log.created_at}
for log in reversed(history_logs)
]
context_rounds = get_chat_context_rounds()
history = []
if context_rounds > 0:
history_result = await db_session.execute(
sa_select(ChatLog).where(
ChatLog.user_id == user_id,
ChatLog.pet_id == pet_id,
ChatLog.bg_id == background_id
).order_by(ChatLog.created_at.desc()).limit(context_rounds)
)
history_logs = history_result.scalars().all()
for log in reversed(history_logs):
if log.user_msg:
history.append({"is_user": True, "content": log.user_msg, "created_at": log.created_at})
if log.ai_msg:
history.append({"is_user": False, "content": log.ai_msg, "created_at": log.created_at})
messages = doubao_service.build_messages(
system_prompt=pet.global_prompt,

View File

@ -141,7 +141,9 @@ export const adminAPI = {
savePet: (petData) => apiClient.post('/api/v1/admin/pets', petData),
getBackgroundPetBindings: (backgroundId) => apiClient.get(`/api/v1/admin/backgrounds/${backgroundId}/pet-bindings`),
saveBackgroundPetBindings: (backgroundId, bindings) => apiClient.post(`/api/v1/admin/backgrounds/${backgroundId}/pet-bindings`, { bindings }),
deleteBackgroundPetBinding: (backgroundId, bindingId) => apiClient.delete(`/api/v1/admin/backgrounds/${backgroundId}/pet-bindings/${bindingId}`)
deleteBackgroundPetBinding: (backgroundId, bindingId) => apiClient.delete(`/api/v1/admin/backgrounds/${backgroundId}/pet-bindings/${bindingId}`),
getSystemConfig: () => apiClient.get('/api/v1/admin/config'),
updateSystemConfig: (data) => apiClient.patch('/api/v1/admin/config', data)
}
export const adminApi = adminAPI

View File

@ -48,6 +48,23 @@
<el-divider>系统限制</el-divider>
<el-form-item label="连续对话上下文">
<el-switch v-model="policy.enable_chat_context" />
<span style="margin-left: 12px; color: #909399;">
关闭后每次聊天互相独立不携带上次对话
</span>
</el-form-item>
<el-form-item label="上下文轮数">
<el-input-number
v-model="policy.chat_context_rounds"
:min="0"
:max="50"
:disabled="!policy.enable_chat_context"
/>
<span style="margin-left: 12px; color: #909399;">1=用户+AI</span>
</el-form-item>
<el-form-item label="单次对话Token限制">
<el-input-number
v-model="policy.max_tokens_per_chat"
@ -101,9 +118,10 @@
</template>
<script>
import { ref, reactive, onMounted } from 'vue'
import { ref, reactive, onMounted, computed } from 'vue'
import { ElMessage } from 'element-plus'
import { Check, Refresh } from '@element-plus/icons-vue'
import { adminAPI } from '@/api/index'
export default {
name: 'DefaultPolicy',
@ -122,6 +140,8 @@ export default {
max_tokens_per_chat: 2000,
max_daily_chats: 20,
max_conversation_rounds: 20,
enable_chat_context: false,
chat_context_rounds: 0,
enable_content_moderation: true,
enable_keyword_filter: true
})
@ -134,12 +154,33 @@ export default {
ElMessage.info('选择主角功能开发中...')
}
const effectiveChatContextRounds = computed(() => {
return policy.enable_chat_context ? Number(policy.chat_context_rounds || 0) : 0
})
const loadPolicy = async () => {
try {
const res = await adminAPI.getSystemConfig()
const rounds = Number(res?.data?.data?.ai?.chat_context_rounds ?? 0)
policy.chat_context_rounds = Number.isNaN(rounds) ? 0 : Math.max(0, Math.min(50, rounds))
policy.enable_chat_context = policy.chat_context_rounds > 0
} catch (error) {
console.error('加载系统配置失败:', error)
}
}
const savePolicy = async () => {
try {
saving.value = true
await adminAPI.updateSystemConfig({
ai: {
chat_context_rounds: effectiveChatContextRounds.value
}
})
ElMessage.success('策略保存成功')
} catch (error) {
ElMessage.error('保存失败')
console.error('保存策略失败:', error)
ElMessage.error(error?.response?.data?.detail || '保存失败')
} finally {
saving.value = false
}
@ -154,19 +195,22 @@ export default {
max_tokens_per_chat: 2000,
max_daily_chats: 20,
max_conversation_rounds: 20,
enable_chat_context: false,
chat_context_rounds: 0,
enable_content_moderation: true,
enable_keyword_filter: true
})
ElMessage.success('已重置为默认策略')
}
onMounted(() => {
//
onMounted(async () => {
await loadPolicy()
})
return {
saving,
policy,
effectiveChatContextRounds,
selectBackground,
selectPet,
savePolicy,