dvc890 commited on
Commit
604195d
·
verified ·
1 Parent(s): 002a147

Upload 47 files

Browse files
Files changed (2) hide show
  1. pages/AIAssistant.tsx +8 -8
  2. server.js +9 -8
pages/AIAssistant.tsx CHANGED
@@ -461,6 +461,14 @@ export const AIAssistant: React.FC = () => {
461
  </ReactMarkdown>
462
  </div>
463
 
 
 
 
 
 
 
 
 
464
  {msg.audio && (
465
  <button onClick={() => playPCMAudio(msg.audio!)} className="mt-2 flex items-center gap-2 text-xs bg-blue-50 text-blue-600 px-3 py-1.5 rounded-full hover:bg-blue-100 border border-blue-100 transition-colors w-fit">
466
  <Volume2 size={14}/> 播放语音
@@ -469,14 +477,6 @@ export const AIAssistant: React.FC = () => {
469
  </div>
470
  </div>
471
  ))}
472
- {isProcessing && messages[messages.length - 1]?.role === 'user' && (
473
- <div className="flex gap-3">
474
- <div className="w-10 h-10 rounded-full bg-blue-100 text-blue-600 flex items-center justify-center">
475
- <Loader2 className="animate-spin" size={20}/>
476
- </div>
477
- <div className="text-sm text-gray-400 self-center">AI 正在思考...</div>
478
- </div>
479
- )}
480
  <div ref={messagesEndRef} />
481
  </div>
482
 
 
461
  </ReactMarkdown>
462
  </div>
463
 
464
+ {/* Loading State INSIDE Bubble */}
465
+ {msg.role === 'model' && !msg.text && isProcessing && (
466
+ <div className="flex items-center gap-2 text-gray-400 py-1">
467
+ <Loader2 className="animate-spin" size={14}/>
468
+ <span className="text-xs">思考中...</span>
469
+ </div>
470
+ )}
471
+
472
  {msg.audio && (
473
  <button onClick={() => playPCMAudio(msg.audio!)} className="mt-2 flex items-center gap-2 text-xs bg-blue-50 text-blue-600 px-3 py-1.5 rounded-full hover:bg-blue-100 border border-blue-100 transition-colors w-fit">
474
  <Volume2 size={14}/> 播放语音
 
477
  </div>
478
  </div>
479
  ))}
 
 
 
 
 
 
 
 
480
  <div ref={messagesEndRef} />
481
  </div>
482
 
server.js CHANGED
@@ -216,7 +216,8 @@ function isQuotaError(e) {
216
  msg.includes('Quota') ||
217
  msg.includes('overloaded') ||
218
  msg.includes('RESOURCE_EXHAUSTED') ||
219
- msg.includes('Rate limit');
 
220
  }
221
 
222
  // --- INDIVIDUAL PROVIDER CALLERS ---
@@ -237,6 +238,7 @@ async function callGeminiProvider(aiModelObj, baseParams) {
237
  lastError = e;
238
  console.error(`⚠️ [AI Debug] Gemini ${modelName} Error:`, e.status, e.message);
239
  if (isQuotaError(e)) {
 
240
  console.warn(`⚠️ [AI Debug] Gemini ${modelName} exhausted. Trying next internal model...`);
241
  continue;
242
  }
@@ -342,8 +344,9 @@ async function streamGemini(aiModelObj, baseParams, res) {
342
  console.error(`❌ [AI Debug] Gemini Stream Error (${modelName}):`, e.status, e.message);
343
 
344
  if (isQuotaError(e)) {
345
- console.warn(`Stream Gemini ${modelName} quota exhausted. Switching...`);
346
- continue; // Try next internal model
 
347
  }
348
  throw e; // Non-quota error, fail fast
349
  }
@@ -375,6 +378,7 @@ async function streamGemma(aiModelObj, baseParams, res) {
375
  } catch (e) {
376
  lastError = e;
377
  console.warn(`Stream Gemma ${modelName} failed: ${e.message}`);
 
378
  }
379
  }
380
  throw lastError || new Error("Gemma streaming failed");
@@ -415,11 +419,8 @@ async function streamOpenRouter(baseParams, res) {
415
  } catch (e) {
416
  lastError = e;
417
  console.warn(`[AI Debug] Stream OpenRouter ${modelName} failed`, e.message);
418
- if (isQuotaError(e)) {
419
- // If Rate Limit, break loop to allow fallback to next PROVIDER immediately
420
- // instead of trying all OpenRouter models which share quota
421
- throw e;
422
- }
423
  }
424
  }
425
  throw lastError || new Error("All OpenRouter streams failed");
 
216
  msg.includes('Quota') ||
217
  msg.includes('overloaded') ||
218
  msg.includes('RESOURCE_EXHAUSTED') ||
219
+ msg.includes('Rate limit') ||
220
+ msg.includes('credits');
221
  }
222
 
223
  // --- INDIVIDUAL PROVIDER CALLERS ---
 
238
  lastError = e;
239
  console.error(`⚠️ [AI Debug] Gemini ${modelName} Error:`, e.status, e.message);
240
  if (isQuotaError(e)) {
241
+ // IMPORTANT: Continue to next internal model, do not throw yet
242
  console.warn(`⚠️ [AI Debug] Gemini ${modelName} exhausted. Trying next internal model...`);
243
  continue;
244
  }
 
344
  console.error(`❌ [AI Debug] Gemini Stream Error (${modelName}):`, e.status, e.message);
345
 
346
  if (isQuotaError(e)) {
347
+ // IMPORTANT: Continue to next internal model
348
+ console.warn(`[AI Debug] Stream Gemini ${modelName} quota exhausted. Switching to next internal model...`);
349
+ continue;
350
  }
351
  throw e; // Non-quota error, fail fast
352
  }
 
378
  } catch (e) {
379
  lastError = e;
380
  console.warn(`Stream Gemma ${modelName} failed: ${e.message}`);
381
+ // Continue to next gemma model
382
  }
383
  }
384
  throw lastError || new Error("Gemma streaming failed");
 
419
  } catch (e) {
420
  lastError = e;
421
  console.warn(`[AI Debug] Stream OpenRouter ${modelName} failed`, e.message);
422
+ // CRITICAL FIX: Do NOT throw here. Continue loop to try next OpenRouter model.
423
+ // Only throw if loop finishes.
 
 
 
424
  }
425
  }
426
  throw lastError || new Error("All OpenRouter streams failed");