11import React , { useState , useRef , useEffect } from 'react' ;
2- import { Send , Mic , Paperclip , Smile , Sparkles , Plus } from 'lucide-react' ;
2+ import { Send , Mic , Paperclip , Smile , Sparkles , Plus , AlertCircle } from 'lucide-react' ;
33import styles from './Chat.module.css' ;
44import { useChatStore , useCurrentMessages , Message } from '../../stores/chatStore' ;
55import { useUserStore } from '../../stores/userStore' ;
6+ import openAIService from '../../services/openaiService' ;
67
78const Chat : React . FC = ( ) => {
89 const [ inputValue , setInputValue ] = useState ( '' ) ;
@@ -14,7 +15,9 @@ const Chat: React.FC = () => {
1415
1516 // translation function
1617 const t = ( key : string ) => {
17- const translations : { [ key : string ] : { [ key : string ] : string } } = {
18+ const translations : {
19+ [ key : string ] : { [ key : string ] : string } ;
20+ } = {
1821 'en-US' : {
1922 'chat.placeholder' : 'Message ThinkML...' ,
2023 'chat.welcome.title' : 'ThinkML' ,
@@ -25,6 +28,11 @@ const Chat: React.FC = () => {
2528 'chat.welcome.suggestion3' : 'How to optimize website performance?' ,
2629 'chat.welcome.suggestion4' : 'Write a simple todo app' ,
2730 'nav.newChat' : 'New Chat' ,
31+ 'chat.error.api' : 'API Error' ,
32+ 'chat.error.noApiKey' :
33+ 'OpenAI API key not configured. Please set REACT_APP_OPENAI_API_KEY in your environment variables.' ,
34+ 'chat.error.network' : 'Network error. Please check your connection.' ,
35+ 'chat.error.unknown' : 'An unknown error occurred.' ,
2836 } ,
2937 'zh-CN' : {
3038 'chat.placeholder' : '发送消息给 ThinkML...' ,
@@ -36,6 +44,11 @@ const Chat: React.FC = () => {
3644 'chat.welcome.suggestion3' : '如何优化网站性能?' ,
3745 'chat.welcome.suggestion4' : '写一个简单的待办应用' ,
3846 'nav.newChat' : '新建聊天' ,
47+ 'chat.error.api' : 'API 错误' ,
48+ 'chat.error.noApiKey' :
49+ 'OpenAI API 密钥未配置。请在环境变量中设置 REACT_APP_OPENAI_API_KEY。' ,
50+ 'chat.error.network' : '网络错误。请检查您的连接。' ,
51+ 'chat.error.unknown' : '发生未知错误。' ,
3952 } ,
4053 'ja-JP' : {
4154 'chat.placeholder' : 'ThinkMLにメッセージを送信...' ,
@@ -47,6 +60,11 @@ const Chat: React.FC = () => {
4760 'chat.welcome.suggestion3' : 'ウェブサイトのパフォーマンスを最適化する方法は?' ,
4861 'chat.welcome.suggestion4' : 'シンプルなTodoアプリを作成して' ,
4962 'nav.newChat' : '新しいチャット' ,
63+ 'chat.error.api' : 'API エラー' ,
64+ 'chat.error.noApiKey' :
65+ 'OpenAI API キーが設定されていません。環境変数で REACT_APP_OPENAI_API_KEY を設定してください。' ,
66+ 'chat.error.network' : 'ネットワークエラー。接続を確認してください。' ,
67+ 'chat.error.unknown' : '不明なエラーが発生しました。' ,
5068 } ,
5169 } ;
5270
@@ -83,17 +101,66 @@ const Chat: React.FC = () => {
83101 setInputValue ( '' ) ;
84102 setLoading ( true ) ;
85103
86- // Simulate AI response
87- setTimeout ( ( ) => {
104+ try {
105+ // check api key
106+ if ( ! openAIService . isConfigured ( ) ) {
107+ throw new Error ( t ( 'chat.error.noApiKey' ) ) ;
108+ }
109+
110+ // api messages
111+ const apiMessages = messages . map ( ( msg ) => ( {
112+ role : msg . role as 'user' | 'assistant' ,
113+ content : msg . content ,
114+ } ) ) ;
115+
116+ // add current user message
117+ apiMessages . push ( {
118+ role : 'user' ,
119+ content : userMessage . content ,
120+ } ) ;
121+
122+ // call ChatGPT API
123+ const response = await openAIService . chatCompletion ( apiMessages , {
124+ model : 'gpt-3.5-turbo' ,
125+ maxTokens : 1000 ,
126+ temperature : 0.7 ,
127+ } ) ;
128+
88129 const assistantMessage : Message = {
89130 id : ( Date . now ( ) + 1 ) . toString ( ) ,
90- content : `I received your message: " ${ userMessage . content } ". This is a simulated response. In a real application, this would call an AI API.` ,
131+ content : response ,
91132 role : 'assistant' ,
92133 timestamp : new Date ( ) ,
93134 } ;
94135 addMessage ( assistantMessage ) ;
136+ } catch ( error ) {
137+ // eslint-disable-next-line no-console
138+ console . error ( 'Chat API Error:' , error ) ;
139+
140+ let errorMessage = t ( 'chat.error.unknown' ) ;
141+ if ( error instanceof Error ) {
142+ if ( error . message . includes ( 'API key' ) ) {
143+ errorMessage = t ( 'chat.error.noApiKey' ) ;
144+ } else if ( error . message . includes ( 'fetch' ) || error . message . includes ( 'network' ) ) {
145+ errorMessage = t ( 'chat.error.network' ) ;
146+ } else if ( error . message . includes ( 'quota' ) ) {
147+ errorMessage = 'API 配额已用完,已切换到模拟模式。请检查你的 OpenAI 账户余额。' ;
148+ } else {
149+ errorMessage = error . message ;
150+ }
151+ }
152+
153+ // add error message to chat
154+ const errorResponse : Message = {
155+ id : ( Date . now ( ) + 1 ) . toString ( ) ,
156+ content : `❌ ${ errorMessage } ` ,
157+ role : 'assistant' ,
158+ timestamp : new Date ( ) ,
159+ } ;
160+ addMessage ( errorResponse ) ;
161+ } finally {
95162 setLoading ( false ) ;
96- } , 1000 ) ;
163+ }
97164 } ;
98165
99166 const handleKeyPress = ( e : React . KeyboardEvent ) => {
@@ -104,13 +171,16 @@ const Chat: React.FC = () => {
104171 } ;
105172
106173 const handleNewChat = ( ) => {
107- // 由Sidebar控制新建会话
174+ // new chat by sidebar
108175 setInputValue ( '' ) ;
109176 setTimeout ( ( ) => {
110177 inputRef . current ?. focus ( ) ;
111178 } , 100 ) ;
112179 } ;
113180
181+ // check API configuration status
182+ const apiConfigStatus = openAIService . getConfigurationStatus ( ) ;
183+
114184 return (
115185 < div className = { styles . chatContainer } >
116186 { ! hasStartedChat ? (
@@ -123,6 +193,14 @@ const Chat: React.FC = () => {
123193 </ div >
124194 < h1 className = { styles . welcomeTitle } > { t ( 'chat.welcome.title' ) } </ h1 >
125195 < p className = { styles . welcomeSubtitle } > { t ( 'chat.welcome.subtitle' ) } </ p >
196+
197+ { /* API configuration status hint */ }
198+ { ! apiConfigStatus . configured && (
199+ < div className = { styles . apiWarning } >
200+ < AlertCircle size = { 16 } />
201+ < span > { apiConfigStatus . message } </ span >
202+ </ div >
203+ ) }
126204 </ div >
127205
128206 < div className = { styles . chatInputContainer } >
0 commit comments