@@ -6,64 +6,48 @@ import { useParams } from "next/navigation";
66import Chatlist from "@/components/Chatlist" ;
77import ChatMessages from "@/components/ChatMessages" ;
88import Image from "next/image" ;
9+ import { useChat } from "@/contexts/ChatContext" ;
10+ import { continueChatWebSocket } from "@/lib/websocket" ;
911
1012export default function ChatPage ( ) {
1113 const params = useParams ( ) ;
1214 const chattingId = params . chattingId ;
13-
14- const [ chatData , setChatData ] = useState ( {
15- chattingId : "" ,
16- ownerId : "" ,
17- title : "" ,
18- description : "" ,
19- chatList : [ ] ,
20- createdAt : 0 ,
21- modifiedAt : 0 ,
15+ const { getCurrentChat, updateChat, setCurrentChatId } = useChat ( ) ;
16+
17+ const [ formData , setFormData ] = useState ( {
18+ content : "" ,
2219 } ) ;
2320
24- const [ loading , setLoading ] = useState ( true ) ;
21+ // 실시간 스트리밍을 위한 로컬 상태
22+ const [ localChatList , setLocalChatList ] = useState ( [ ] ) ;
2523
24+ // chattingId가 바뀔 때마다 현재 채팅 설정
2625 useEffect ( ( ) => {
27- // localStorage에 lastchattingid 저장
28- localStorage . setItem ( "lastchattingid" , chattingId ) ;
26+ setCurrentChatId ( chattingId ) ;
27+ } , [ chattingId , setCurrentChatId ] ) ;
2928
30- // DB에서 채팅 데이터 조회 (실제 구현에서는 API 호출)
31- fetchChatData ( chattingId ) ;
32- } , [ chattingId ] ) ;
29+ // 현재 채팅 데이터 가져오기
30+ const chatData = getCurrentChat ( ) ;
3331
34- const fetchChatData = async ( id ) => {
35- try {
36- setLoading ( true ) ;
37-
38- // 실제 API 호출
39- const response = await fetch ( `/api/chat/${ id } ` ) ;
40-
41- if ( ! response . ok ) {
42- throw new Error ( "채팅을 찾을 수 없습니다" ) ;
43- }
44-
45- const data = await response . json ( ) ;
46- setChatData ( data ) ;
47- } catch ( error ) {
48- console . error ( "채팅 데이터 조회 실패:" , error ) ;
49- // 에러 시 빈 채팅으로 설정
50- setChatData ( {
51- chattingId : id ,
52- ownerId : "" ,
53- title : "채팅을 찾을 수 없습니다" ,
54- description : "" ,
55- chatList : [ ] ,
56- createdAt : 0 ,
57- modifiedAt : 0 ,
58- } ) ;
59- } finally {
60- setLoading ( false ) ;
32+ // Context 데이터가 변경되면 로컬 상태 동기화
33+ useEffect ( ( ) => {
34+ if ( chatData ?. chatList ) {
35+ setLocalChatList ( [ ...chatData . chatList ] ) ;
6136 }
62- } ;
37+ } , [ chatData ?. chatList ] ) ;
6338
64- const [ formData , setFormData ] = useState ( {
65- content : "" ,
66- } ) ;
39+ // 채팅 목록이 변경될 때마다 자동으로 스크롤
40+ useEffect ( ( ) => {
41+ const chatBox = document . getElementById ( 'chat-box' ) ;
42+ if ( chatBox ) {
43+ setTimeout ( ( ) => {
44+ chatBox . scrollTo ( {
45+ top : chatBox . scrollHeight ,
46+ behavior : 'smooth'
47+ } ) ;
48+ } , 100 ) ;
49+ }
50+ } , [ localChatList ] ) ;
6751
6852 const handleInputChange = ( e ) => {
6953 const { name, value } = e . target ;
@@ -80,10 +64,87 @@ export default function ChatPage() {
8064 } ;
8165
8266 const handleSendMessage = ( ) => {
83- if ( formData . content . trim ( ) === "" ) return ;
67+ if ( formData . content . trim ( ) === "" || ! chatData ) return ;
68+
69+ console . log ( "=== 메시지 전송 시작 ===" ) ;
70+
71+ const userChatElement = {
72+ sender : "USER" ,
73+ text : formData . content ,
74+ timestamp : Math . floor ( Date . now ( ) / 1000 ) ,
75+ model : "" ,
76+ use_estimate : 0 ,
77+ llm_estimate : 0 ,
78+ } ;
79+
80+ // 1. 유저 메시지를 Context에 즉시 저장
81+ const updatedChatListWithUser = [ ...( chatData . chatList || [ ] ) , userChatElement ] ;
82+ updateChat ( chattingId , {
83+ chatList : updatedChatListWithUser
84+ } ) ;
85+
86+ let currentAIMessage = null ; // 현재 AI 메시지 추적
87+
88+ function modelNameHandler ( modelName ) {
89+ console . log ( "AI 모델 시작:" , modelName ) ;
90+
91+ // AI 메시지 박스 생성 (로컬 상태에만)
92+ currentAIMessage = {
93+ sender : "AI" ,
94+ text : "" ,
95+ timestamp : Math . floor ( Date . now ( ) / 1000 ) ,
96+ model : modelName ,
97+ use_estimate : 0 ,
98+ llm_estimate : 0 ,
99+ } ;
100+
101+ setLocalChatList ( prev => [ ...prev , currentAIMessage ] ) ;
102+ }
84103
85- // TODO: 실제 메시지 전송 로직 구현
86- console . log ( "메시지 전송:" , formData . content ) ;
104+ function modelResponseHandler ( id , text ) {
105+ // 실시간 스트리밍 (로컬 상태만 업데이트)
106+ if ( currentAIMessage ) {
107+ currentAIMessage . text += text ;
108+ setLocalChatList ( prev => {
109+ const newList = [ ...prev ] ;
110+ const lastIndex = newList . length - 1 ;
111+ if ( newList [ lastIndex ] && newList [ lastIndex ] . sender === "AI" ) {
112+ newList [ lastIndex ] = { ...currentAIMessage } ;
113+ }
114+ return newList ;
115+ } ) ;
116+ }
117+ }
118+
119+ // WebSocket 연결 설정 (응답 완료 처리 추가)
120+ const socket = continueChatWebSocket (
121+ chattingId ,
122+ formData . content ,
123+ document . cookie . split ( '; ' ) . find ( row => row . startsWith ( 'jwtToken=' ) ) ?. split ( '=' ) [ 1 ] ,
124+ modelNameHandler ,
125+ modelResponseHandler
126+ ) ;
127+
128+ // WebSocket 메시지 이벤트 추가 처리
129+ const originalOnMessage = socket . onmessage ;
130+ socket . onmessage = ( event ) => {
131+ const data = JSON . parse ( event . data ) ;
132+
133+ // 기존 처리
134+ if ( originalOnMessage ) {
135+ originalOnMessage ( event ) ;
136+ }
137+
138+ // 응답 완료 시 Context에 저장
139+ if ( data . end === "end" && currentAIMessage ) {
140+ console . log ( "AI 응답 완료 - Context에 저장" ) ;
141+ const finalChatList = [ ...updatedChatListWithUser , currentAIMessage ] ;
142+ updateChat ( chattingId , {
143+ chatList : finalChatList ,
144+ modifiedAt : Date . now ( )
145+ } ) ;
146+ }
147+ } ;
87148
88149 setFormData ( { content : "" } ) ;
89150 const textarea = document . querySelector ( 'textarea[name="content"]' ) ;
@@ -98,12 +159,12 @@ export default function ChatPage() {
98159 }
99160 } ;
100161
101- if ( loading ) {
162+ if ( ! chatData ) {
102163 return (
103164 < div className = "flex flex-row h-screen" >
104165 < Chatlist />
105166 < div className = "flex-1 flex items-center justify-center" >
106- < div className = "text-white" > 로딩 중... </ div >
167+ < div className = "text-white" > 채팅을 찾을 수 없습니다 </ div >
107168 </ div >
108169 </ div >
109170 ) ;
@@ -119,7 +180,7 @@ export default function ChatPage() {
119180 id = "chat-box"
120181 className = "flex flex-col flex-1 overflow-y-auto min-h-0"
121182 >
122- < ChatMessages chatList = { chatData . chatList } />
183+ < ChatMessages chatList = { localChatList } />
123184 </ div >
124185 < div
125186 id = "input-box"
0 commit comments