Skip to content

Commit 3982a9f

Browse files
authored
Merge pull request #9 from Kate-M1125/feature/chat-api
add chat-api to chat function
2 parents 827d4c2 + 2bbc377 commit 3982a9f

7 files changed

Lines changed: 316 additions & 9 deletions

File tree

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,3 +160,7 @@ dist
160160
.yarn/install-state.gz
161161
.pnp.*
162162
1097d3adbfbe8745c7109358ddb3635d08fb7c47
163+
164+
# Documentation files (temporary setup guides)
165+
API_SETUP.md
166+
QUOTA_SOLUTION.md

eslint.config.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ export default [
4242
HTMLTextAreaElement: 'readonly',
4343
MouseEvent: 'readonly',
4444
Node: 'readonly',
45+
process: 'readonly',
46+
fetch: 'readonly',
47+
RequestInit: 'readonly',
48+
Response: 'readonly',
4549
},
4650
},
4751
plugins: {

src/MainLayout/NavBar/NavBar.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ const NavBar: React.FC = () => {
3232
};
3333

3434
const handleLogout = () => {
35-
// 这里可以添加登出逻辑
35+
// Add logout logic here
3636
// TODO: Implement logout logic
3737
};
3838

src/MainLayout/Sidebar/Sidebar.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ const Sidebar: React.FC = () => {
142142
</div>
143143
</div>
144144
)}
145-
{/* 搜索弹窗 */}
145+
{/* Search modal */}
146146
{showSearch && (
147147
<div className={styles.searchModalOverlay} onClick={() => setShowSearch(false)}>
148148
<div className={styles.searchModal} onClick={(e) => e.stopPropagation()}>

src/Pages/Chat/Chat.module.css

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,28 @@
5656
font-weight: 400;
5757
}
5858

59+
.apiWarning {
60+
display: flex;
61+
align-items: center;
62+
justify-content: center;
63+
gap: 8px;
64+
margin-top: 16px;
65+
padding: 12px 16px;
66+
background: #fef3c7;
67+
border: 1px solid #f59e0b;
68+
border-radius: 8px;
69+
color: #92400e;
70+
font-size: 0.875rem;
71+
max-width: 500px;
72+
margin-left: auto;
73+
margin-right: auto;
74+
}
75+
76+
.apiWarning svg {
77+
flex-shrink: 0;
78+
color: #f59e0b;
79+
}
80+
5981
.chatInputContainer {
6082
margin-bottom: 40px;
6183
}

src/Pages/Chat/index.tsx

Lines changed: 85 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import 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';
33
import styles from './Chat.module.css';
44
import { useChatStore, useCurrentMessages, Message } from '../../stores/chatStore';
55
import { useUserStore } from '../../stores/userStore';
6+
import openAIService from '../../services/openaiService';
67

78
const 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

Comments
 (0)