55
66namespace ProjectVG . Application . Services . Chat . Factories
77{
8- public class ChatLLMFormat : ILLMFormat < ChatPreprocessContext , ChatOutputFormatResult >
8+ public class ChatLLMFormat : ILLMFormat < ChatPreprocessContext , List < ChatMessageSegment > >
99 {
1010 public ChatLLMFormat ( )
1111 {
@@ -29,7 +29,6 @@ public string GetInstructions(ChatPreprocessContext input)
2929 {
3030 var sb = new StringBuilder ( ) ;
3131
32- // 메모리 컨텍스트 추가
3332 if ( input . MemoryContext ? . Any ( ) == true )
3433 {
3534 sb . AppendLine ( "관련 기억:" ) ;
@@ -40,7 +39,6 @@ public string GetInstructions(ChatPreprocessContext input)
4039 sb . AppendLine ( ) ;
4140 }
4241
43- // 대화 기록 추가
4442 var conversationHistory = input . ParseConversationHistory ( 5 ) ;
4543 if ( conversationHistory . Any ( ) )
4644 {
@@ -52,7 +50,6 @@ public string GetInstructions(ChatPreprocessContext input)
5250 sb . AppendLine ( ) ;
5351 }
5452
55- // 출력 포맷 지침 추가
5653 sb . AppendLine ( GetFormatInstructions ( ) ) ;
5754
5855 return sb . ToString ( ) ;
@@ -62,9 +59,9 @@ public string GetInstructions(ChatPreprocessContext input)
6259 public float Temperature => 0.7f ;
6360 public int MaxTokens => 1000 ;
6461
65- public ChatOutputFormatResult Parse ( string llmResponse , ChatPreprocessContext input )
62+ public List < ChatMessageSegment > Parse ( string llmResponse , ChatPreprocessContext input )
6663 {
67- return ParseChatResponse ( llmResponse , input . VoiceName ) ;
64+ return ParseChatResponseToSegments ( llmResponse , input . VoiceName ) ;
6865 }
6966
7067 public double CalculateCost ( int promptTokens , int completionTokens )
@@ -85,54 +82,63 @@ [neutral] 내가 그런다고 좋아할 것 같아? [shy] 하지만 츄 해준
8582" ;
8683 }
8784
88- private ChatOutputFormatResult ParseChatResponse ( string llmText , string ? voiceName = null )
85+ private List < ChatMessageSegment > ParseChatResponseToSegments ( string llmText , string ? voiceName = null )
8986 {
9087 if ( string . IsNullOrWhiteSpace ( llmText ) )
91- return new ChatOutputFormatResult ( ) ;
88+ return new List < ChatMessageSegment > ( ) ;
9289
9390 string response = llmText . Trim ( ) ;
94- var emotions = new List < string > ( ) ;
95- var texts = new List < string > ( ) ;
91+ var segments = new List < ChatMessageSegment > ( ) ;
92+ var seenTexts = new HashSet < string > ( StringComparer . OrdinalIgnoreCase ) ;
9693
97- // [감정] 답변 패턴 추출
9894 var matches = Regex . Matches ( response , @"\[(.*?)\]\s*([^\[]+)" ) ;
99-
100- // 보이스별 감정 매핑
101- Dictionary < string , string > ? emotionMap = null ;
102- if ( ! string . IsNullOrWhiteSpace ( voiceName ) )
103- {
104- var profile = VoiceCatalog . GetProfile ( voiceName ) ;
105- if ( profile != null && profile . EmotionMap != null )
106- emotionMap = profile . EmotionMap ;
107- }
95+ var emotionMap = GetEmotionMap ( voiceName ) ;
10896
10997 if ( matches . Count > 0 )
11098 {
111- foreach ( Match match in matches )
112- {
113- if ( match . Groups . Count >= 3 )
114- {
115- var originalEmotion = match . Groups [ 1 ] . Value . Trim ( ) ;
116- var mappedEmotion = emotionMap != null && emotionMap . ContainsKey ( originalEmotion )
117- ? emotionMap [ originalEmotion ]
118- : originalEmotion ;
119- emotions . Add ( mappedEmotion ) ;
120- texts . Add ( match . Groups [ 2 ] . Value . Trim ( ) ) ;
121- }
122- }
99+ ProcessMatches ( matches , emotionMap , segments , seenTexts ) ;
123100 }
124101 else
125102 {
126- emotions . Add ( "neutral" ) ;
127- texts . Add ( response ) ;
103+ var segment = ChatMessageSegment . CreateTextOnly ( response , 0 ) ;
104+ segment . Emotion = "neutral" ;
105+ segments . Add ( segment ) ;
128106 }
129107
130- return new ChatOutputFormatResult
108+ return segments ;
109+ }
110+
111+ private Dictionary < string , string > ? GetEmotionMap ( string ? voiceName )
112+ {
113+ if ( string . IsNullOrWhiteSpace ( voiceName ) )
114+ return null ;
115+
116+ var profile = VoiceCatalog . GetProfile ( voiceName ) ;
117+ return profile ? . EmotionMap ;
118+ }
119+
120+ private void ProcessMatches ( MatchCollection matches , Dictionary < string , string > ? emotionMap , List < ChatMessageSegment > segments , HashSet < string > seenTexts )
121+ {
122+ for ( int i = 0 ; i < matches . Count ; i ++ )
131123 {
132- Response = response ,
133- Emotion = emotions ,
134- Text = texts
135- } ;
124+ var match = matches [ i ] ;
125+ if ( match . Groups . Count >= 3 )
126+ {
127+ var originalEmotion = match . Groups [ 1 ] . Value . Trim ( ) ;
128+ var mappedEmotion = emotionMap != null && emotionMap . ContainsKey ( originalEmotion )
129+ ? emotionMap [ originalEmotion ]
130+ : originalEmotion ;
131+ var text = match . Groups [ 2 ] . Value . Trim ( ) ;
132+
133+ if ( ! seenTexts . Contains ( text ) )
134+ {
135+ seenTexts . Add ( text ) ;
136+ var segment = ChatMessageSegment . CreateTextOnly ( text , segments . Count ) ;
137+ segment . Emotion = mappedEmotion ;
138+ segments . Add ( segment ) ;
139+ }
140+ }
141+ }
136142 }
137143 }
138144}
0 commit comments