False45 commited on
Commit
0817d6a
·
1 Parent(s): 075ecd2

fix: use JSON encoded SSE chunks to preserve multi-line responses and prevent stream breaking on newline chunks

Browse files
src/api/v1/chat.py CHANGED
@@ -127,20 +127,21 @@ async def chat_stream(request: Request, payload: ChatRequest, uid: str = Depends
127
 
128
  gemini = GeminiService()
129
 
 
130
  async def generate():
131
  full_response = ""
132
  try:
133
  async for chunk in gemini.stream(payload.query, context=context, chat_history=chat_history):
134
  full_response += chunk
135
  # Format as SSE
136
- yield f"data: {chunk}\n\n"
137
 
138
  # Save full response to memory after streaming completes
139
  engine.memory.add_message("assistant", full_response)
140
  yield "data: [DONE]\n\n"
141
  except Exception as e:
142
  logger.error(f"Streaming error: {e}")
143
- yield f"data: ⚠️ Streaming error: {e}\n\n"
144
  yield "data: [DONE]\n\n"
145
 
146
  return StreamingResponse(generate(), media_type="text/event-stream")
 
127
 
128
  gemini = GeminiService()
129
 
130
+ import json
131
  async def generate():
132
  full_response = ""
133
  try:
134
  async for chunk in gemini.stream(payload.query, context=context, chat_history=chat_history):
135
  full_response += chunk
136
  # Format as SSE
137
+ yield f"data: {json.dumps({'content': chunk, 'type': 'token'})}\n\n"
138
 
139
  # Save full response to memory after streaming completes
140
  engine.memory.add_message("assistant", full_response)
141
  yield "data: [DONE]\n\n"
142
  except Exception as e:
143
  logger.error(f"Streaming error: {e}")
144
+ yield f"data: {json.dumps({'content': f'\\n\\n⚠️ Streaming error: {e}', 'type': 'token'})}\n\n"
145
  yield "data: [DONE]\n\n"
146
 
147
  return StreamingResponse(generate(), media_type="text/event-stream")
src/services/gemini_service.py CHANGED
@@ -163,9 +163,32 @@ class GeminiService:
163
  if chunk.text:
164
  yield chunk.text
165
  except Exception as e:
166
- logger.error(f"Streaming error: {e}")
167
- yield f"\n\n⚠️ Streaming error: {e}"
168
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
 
170
  class GeminiVisionService:
171
  """Gemini Vision for extracting math from images."""
 
163
  if chunk.text:
164
  yield chunk.text
165
  except Exception as e:
166
+ logger.error(f"Primary model {self.primary_model} streaming failed: {e}")
167
+ logger.info(f"Falling back to {self.fallback_model}...")
168
+ try:
169
+ response_stream = client.models.generate_content_stream(
170
+ model=self.fallback_model,
171
+ contents=prompt,
172
+ config=config
173
+ )
174
+ for chunk in response_stream:
175
+ if chunk.text:
176
+ yield chunk.text
177
+ except Exception as e2:
178
+ logger.error(f"Fallback model {self.fallback_model} streaming also failed: {e2}")
179
+ logger.info("Falling back to gemini-1.5-flash-8b...")
180
+ try:
181
+ response_stream = client.models.generate_content_stream(
182
+ model="gemini-1.5-flash-8b",
183
+ contents=prompt,
184
+ config=config
185
+ )
186
+ for chunk in response_stream:
187
+ if chunk.text:
188
+ yield chunk.text
189
+ except Exception as e3:
190
+ logger.error(f"All Gemini streaming models failed: {e3}")
191
+ yield f"\n\n⚠️ Streaming error: All Gemini models failed. You might be out of API quota."
192
 
193
  class GeminiVisionService:
194
  """Gemini Vision for extracting math from images."""