Skip to content

Commit 4ef7c68

Browse files
committed
fix: ai auth
1 parent dbf5fb5 commit 4ef7c68

File tree

2 files changed

+60
-29
lines changed

2 files changed

+60
-29
lines changed

apps/web/src/games/demo-with-backend/components/AiChatUnified.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React from 'react';
22
import { callAiModel, callBackendAi, type ChatMessage } from '@services/AiService';
3+
import { useAuth } from '../hooks/useAuth';
34

45
const MODEL_OPTIONS = [
56
{ value: 'gemini-2.5-pro', label: 'Gemini 2.5 Pro', provider: 'google', inputPricePerMillionTokens: 1.25, outputPricePerMillionTokens: 10.00 },
@@ -28,6 +29,9 @@ const MODEL_OPTIONS = [
2829
];
2930

3031
export const AiChatUnified: React.FC = () => {
32+
const { user } = useAuth();
33+
const isLoggedIn = !!user;
34+
3135
const [useBackend, setUseBackend] = React.useState(true);
3236
const [apiUrl, setApiUrl] = React.useState('');
3337
const [apiKey, setApiKey] = React.useState('');
@@ -132,7 +136,7 @@ export const AiChatUnified: React.FC = () => {
132136
setError('');
133137
};
134138

135-
const canSend = useBackend || (apiUrl && apiKey);
139+
const canSend = (useBackend && isLoggedIn) || (!useBackend && apiUrl && apiKey);
136140

137141
return (
138142
<div className="bg-white border rounded-lg p-4 sm:p-6 space-y-4">
@@ -150,8 +154,9 @@ export const AiChatUnified: React.FC = () => {
150154
<div className="space-y-3">
151155
<div className="flex items-center gap-4">
152156
<label className="flex items-center gap-2 text-sm">
153-
<input type="radio" name="mode" checked={useBackend} onChange={() => setUseBackend(true)} />
154-
<span>使用后端代理</span>
157+
<input type="radio" name="mode" checked={useBackend} onChange={() => setUseBackend(true)} disabled={!isLoggedIn} />
158+
<span className={!isLoggedIn ? 'text-gray-400' : ''}>使用后端代理</span>
159+
{!isLoggedIn && <span className="text-xs text-amber-600">(需要登录)</span>}
155160
</label>
156161
<label className="flex items-center gap-2 text-sm">
157162
<input type="radio" name="mode" checked={!useBackend} onChange={() => setUseBackend(false)} />

packages/services/src/AiService.ts

Lines changed: 52 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -35,24 +35,37 @@ export async function callAiModel({ apiUrl, apiKey, model, messages, temperature
3535
return newMessage;
3636
}
3737
const newMessage = { role: 'assistant' as const, content: '', reasoning_content: '', timestamp: new Date().toISOString() };
38-
const reader = response.body?.getReader();
39-
if (!reader) return newMessage;
38+
if (!response.body) return newMessage;
39+
const reader = response.body.getReader();
4040
const decoder = new TextDecoder();
41+
let buffer = '';
4142
while (true) {
4243
const { done, value } = await reader.read();
4344
if (done) break;
44-
const chunk = decoder.decode(value);
45-
const lines = chunk.split('\n').filter(l => l.trim());
46-
for (const line of lines) {
47-
if (line === 'data: [DONE]') continue;
45+
if (!value) continue;
46+
buffer += decoder.decode(value, { stream: true });
47+
let idx;
48+
while ((idx = buffer.indexOf('\n')) >= 0) {
49+
const line = buffer.slice(0, idx).trim();
50+
buffer = buffer.slice(idx + 1);
51+
if (!line.startsWith('data:')) continue;
52+
const data = line.slice(5).trim();
53+
if (data === '[DONE]') break;
4854
try {
49-
const jsonStr = line.replace('data: ', '');
50-
if (!jsonStr.trim()) continue;
51-
const data = JSON.parse(jsonStr);
52-
if (data.choices?.[0]?.delta?.reasoning_content !== undefined) newMessage.reasoning_content += data.choices[0].delta.reasoning_content || '';
53-
if (data.choices?.[0]?.delta?.content !== undefined) newMessage.content += data.choices[0].delta.content || '';
54-
if (onChunk) onChunk(newMessage);
55-
} catch {}
55+
const json = JSON.parse(data);
56+
const delta = json?.choices?.[0]?.delta;
57+
if (delta?.reasoning_content) {
58+
newMessage.reasoning_content += delta.reasoning_content;
59+
}
60+
if (delta?.content) {
61+
newMessage.content += delta.content;
62+
}
63+
if (onChunk) {
64+
onChunk({ ...newMessage });
65+
}
66+
} catch (e) {
67+
console.error('Error parsing SSE chunk', e);
68+
}
5669
}
5770
}
5871
return newMessage;
@@ -96,24 +109,37 @@ export async function callBackendAi({ model, messages, signal, onChunk, stream =
96109
return newMessage;
97110
}
98111
const newMessage = { role: 'assistant' as const, content: '', reasoning_content: '', timestamp: new Date().toISOString() };
99-
const reader = response.body?.getReader();
100-
if (!reader) return newMessage;
112+
if (!response.body) return newMessage;
113+
const reader = response.body.getReader();
101114
const decoder = new TextDecoder();
115+
let buffer = '';
102116
while (true) {
103117
const { done, value } = await reader.read();
104118
if (done) break;
105-
const chunk = decoder.decode(value);
106-
const lines = chunk.split('\n').filter(l => l.trim());
107-
for (const line of lines) {
108-
if (line === 'data: [DONE]') continue;
119+
if (!value) continue;
120+
buffer += decoder.decode(value, { stream: true });
121+
let idx;
122+
while ((idx = buffer.indexOf('\n')) >= 0) {
123+
const line = buffer.slice(0, idx).trim();
124+
buffer = buffer.slice(idx + 1);
125+
if (!line.startsWith('data:')) continue;
126+
const data = line.slice(5).trim();
127+
if (data === '[DONE]') break;
109128
try {
110-
const jsonStr = line.replace('data: ', '');
111-
if (!jsonStr.trim()) continue;
112-
const data = JSON.parse(jsonStr);
113-
if (data.choices?.[0]?.delta?.reasoning_content !== undefined) newMessage.reasoning_content += data.choices[0].delta.reasoning_content || '';
114-
if (data.choices?.[0]?.delta?.content !== undefined) newMessage.content += data.choices[0].delta.content || '';
115-
if (onChunk) onChunk(newMessage);
116-
} catch {}
129+
const json = JSON.parse(data);
130+
const delta = json?.choices?.[0]?.delta;
131+
if (delta?.reasoning_content) {
132+
newMessage.reasoning_content += delta.reasoning_content;
133+
}
134+
if (delta?.content) {
135+
newMessage.content += delta.content;
136+
}
137+
if (onChunk) {
138+
onChunk({ ...newMessage });
139+
}
140+
} catch (e) {
141+
console.error('Error parsing SSE chunk', e);
142+
}
117143
}
118144
}
119145
return newMessage;

0 commit comments

Comments
 (0)