1
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
import {type Dispatch, type SetStateAction,useState} from 'react';
|
||||
import { type Dispatch, type SetStateAction, useState } from 'react';
|
||||
|
||||
import {
|
||||
generateCharacterPanelChatSuggestions,
|
||||
generateCharacterPanelChatSummary,
|
||||
streamCharacterPanelChatReply,
|
||||
} from '../../services/aiService';
|
||||
import type {StoryGenerationContext} from '../../services/aiTypes';
|
||||
import type { StoryGenerationContext } from '../../services/aiTypes';
|
||||
import type {
|
||||
Character,
|
||||
CharacterChatRecord,
|
||||
@@ -47,12 +47,17 @@ export interface CharacterChatUi {
|
||||
sendDraft: () => void;
|
||||
}
|
||||
|
||||
export function getCharacterChatRecord(state: GameState, characterId: string): CharacterChatRecord {
|
||||
return state.characterChats[characterId] ?? {
|
||||
history: [],
|
||||
summary: '',
|
||||
updatedAt: null,
|
||||
};
|
||||
export function getCharacterChatRecord(
|
||||
state: GameState,
|
||||
characterId: string,
|
||||
): CharacterChatRecord {
|
||||
return (
|
||||
state.characterChats[characterId] ?? {
|
||||
history: [],
|
||||
summary: '',
|
||||
updatedAt: null,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function trimCharacterChatHistory(history: CharacterChatTurn[]) {
|
||||
@@ -66,7 +71,10 @@ export function buildLocalCharacterChatSummary(
|
||||
) {
|
||||
const latestTurns = history
|
||||
.slice(-4)
|
||||
.map(turn => `${turn.speaker === 'player' ? '玩家' : character.name}: ${turn.text}`)
|
||||
.map(
|
||||
(turn) =>
|
||||
`${turn.speaker === 'player' ? '玩家' : character.name}: ${turn.text}`,
|
||||
)
|
||||
.join(' ');
|
||||
|
||||
const currentSummary = latestTurns
|
||||
@@ -111,7 +119,9 @@ type CharacterChatTargetStatus = {
|
||||
affinity?: number | null;
|
||||
};
|
||||
|
||||
function buildTargetStatus(target: CharacterChatTarget): CharacterChatTargetStatus {
|
||||
function buildTargetStatus(
|
||||
target: CharacterChatTarget,
|
||||
): CharacterChatTargetStatus {
|
||||
return {
|
||||
roleLabel: target.roleLabel,
|
||||
hp: target.hp,
|
||||
@@ -129,9 +139,13 @@ export function useCharacterChatFlow({
|
||||
}: {
|
||||
gameState: GameState;
|
||||
setGameState: Dispatch<SetStateAction<GameState>>;
|
||||
buildStoryContextFromState: (state: GameState) => StoryGenerationContext;
|
||||
buildStoryContextFromState: (
|
||||
state: GameState,
|
||||
extras?: { currentStory?: null },
|
||||
) => StoryGenerationContext;
|
||||
}) {
|
||||
const [characterChatModal, setCharacterChatModal] = useState<CharacterChatModalState | null>(null);
|
||||
const [characterChatModal, setCharacterChatModal] =
|
||||
useState<CharacterChatModalState | null>(null);
|
||||
|
||||
const loadCharacterChatSuggestions = async (
|
||||
target: CharacterChatTarget,
|
||||
@@ -139,7 +153,7 @@ export function useCharacterChatFlow({
|
||||
summary: string,
|
||||
) => {
|
||||
if (!gameState.worldType || !gameState.playerCharacter) {
|
||||
setCharacterChatModal(current =>
|
||||
setCharacterChatModal((current) =>
|
||||
current && current.target.character.id === target.character.id
|
||||
? {
|
||||
...current,
|
||||
@@ -151,7 +165,7 @@ export function useCharacterChatFlow({
|
||||
return;
|
||||
}
|
||||
|
||||
setCharacterChatModal(current =>
|
||||
setCharacterChatModal((current) =>
|
||||
current && current.target.character.id === target.character.id
|
||||
? {
|
||||
...current,
|
||||
@@ -172,7 +186,7 @@ export function useCharacterChatFlow({
|
||||
buildTargetStatus(target),
|
||||
);
|
||||
|
||||
setCharacterChatModal(current =>
|
||||
setCharacterChatModal((current) =>
|
||||
current && current.target.character.id === target.character.id
|
||||
? {
|
||||
...current,
|
||||
@@ -183,7 +197,7 @@ export function useCharacterChatFlow({
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Failed to generate character chat suggestions:', error);
|
||||
setCharacterChatModal(current =>
|
||||
setCharacterChatModal((current) =>
|
||||
current && current.target.character.id === target.character.id
|
||||
? {
|
||||
...current,
|
||||
@@ -213,7 +227,11 @@ export function useCharacterChatFlow({
|
||||
};
|
||||
|
||||
const sendCharacterChatDraft = async () => {
|
||||
if (!characterChatModal || !gameState.worldType || !gameState.playerCharacter) {
|
||||
if (
|
||||
!characterChatModal ||
|
||||
!gameState.worldType ||
|
||||
!gameState.playerCharacter
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -223,7 +241,10 @@ export function useCharacterChatFlow({
|
||||
}
|
||||
|
||||
const target = characterChatModal.target;
|
||||
const existingRecord = getCharacterChatRecord(gameState, target.character.id);
|
||||
const existingRecord = getCharacterChatRecord(
|
||||
gameState,
|
||||
target.character.id,
|
||||
);
|
||||
const baseMessages = trimCharacterChatHistory(characterChatModal.messages);
|
||||
const nextMessages = trimCharacterChatHistory([
|
||||
...baseMessages,
|
||||
@@ -233,12 +254,12 @@ export function useCharacterChatFlow({
|
||||
},
|
||||
]);
|
||||
|
||||
setCharacterChatModal(current =>
|
||||
setCharacterChatModal((current) =>
|
||||
current && current.target.character.id === target.character.id
|
||||
? {
|
||||
...current,
|
||||
draft: '',
|
||||
messages: [...nextMessages, {speaker: 'character', text: ''}],
|
||||
messages: [...nextMessages, { speaker: 'character', text: '' }],
|
||||
suggestions: [],
|
||||
isSending: true,
|
||||
isLoadingSuggestions: true,
|
||||
@@ -261,12 +282,12 @@ export function useCharacterChatFlow({
|
||||
draft,
|
||||
buildTargetStatus(target),
|
||||
{
|
||||
onUpdate: text => {
|
||||
setCharacterChatModal(current =>
|
||||
onUpdate: (text) => {
|
||||
setCharacterChatModal((current) =>
|
||||
current && current.target.character.id === target.character.id
|
||||
? {
|
||||
...current,
|
||||
messages: [...nextMessages, {speaker: 'character', text}],
|
||||
messages: [...nextMessages, { speaker: 'character', text }],
|
||||
}
|
||||
: current,
|
||||
);
|
||||
@@ -275,7 +296,7 @@ export function useCharacterChatFlow({
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Failed to stream character panel chat reply:', error);
|
||||
setCharacterChatModal(current =>
|
||||
setCharacterChatModal((current) =>
|
||||
current && current.target.character.id === target.character.id
|
||||
? {
|
||||
...current,
|
||||
@@ -283,10 +304,12 @@ export function useCharacterChatFlow({
|
||||
messages: baseMessages,
|
||||
isSending: false,
|
||||
isLoadingSuggestions: false,
|
||||
error: error instanceof Error ? error.message : '未知智能生成错误',
|
||||
suggestions: current.suggestions.length > 0
|
||||
? current.suggestions
|
||||
: buildLocalCharacterChatSuggestions(target.character),
|
||||
error:
|
||||
error instanceof Error ? error.message : '未知智能生成错误',
|
||||
suggestions:
|
||||
current.suggestions.length > 0
|
||||
? current.suggestions
|
||||
: buildLocalCharacterChatSuggestions(target.character),
|
||||
}
|
||||
: current,
|
||||
);
|
||||
@@ -315,7 +338,11 @@ export function useCharacterChatFlow({
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Failed to summarize character chat:', error);
|
||||
nextSummary = buildLocalCharacterChatSummary(target.character, finalMessages, existingRecord.summary);
|
||||
nextSummary = buildLocalCharacterChatSummary(
|
||||
target.character,
|
||||
finalMessages,
|
||||
existingRecord.summary,
|
||||
);
|
||||
}
|
||||
|
||||
const nextRecord: CharacterChatRecord = {
|
||||
@@ -324,10 +351,10 @@ export function useCharacterChatFlow({
|
||||
updatedAt: new Date().toISOString(),
|
||||
};
|
||||
|
||||
setGameState(current =>
|
||||
setGameState((current) =>
|
||||
buildCharacterChatRecordUpdate(current, target.character.id, nextRecord),
|
||||
);
|
||||
setCharacterChatModal(current =>
|
||||
setCharacterChatModal((current) =>
|
||||
current && current.target.character.id === target.character.id
|
||||
? {
|
||||
...current,
|
||||
@@ -346,8 +373,14 @@ export function useCharacterChatFlow({
|
||||
modal: characterChatModal,
|
||||
openChat: openCharacterChat,
|
||||
closeChat: () => setCharacterChatModal(null),
|
||||
setDraft: (value: string) => setCharacterChatModal(current => (current ? {...current, draft: value} : current)),
|
||||
useSuggestion: (value: string) => setCharacterChatModal(current => (current ? {...current, draft: value} : current)),
|
||||
setDraft: (value: string) =>
|
||||
setCharacterChatModal((current) =>
|
||||
current ? { ...current, draft: value } : current,
|
||||
),
|
||||
useSuggestion: (value: string) =>
|
||||
setCharacterChatModal((current) =>
|
||||
current ? { ...current, draft: value } : current,
|
||||
),
|
||||
refreshSuggestions: () => {
|
||||
if (!characterChatModal) {
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user