Skip to content

Commit 5ae206c

Browse files
committed
Minor fixes
1 parent dd3e2a3 commit 5ae206c

File tree

2 files changed

+103
-57
lines changed

2 files changed

+103
-57
lines changed

src/FreeGPT4_Server.py

Lines changed: 94 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,11 @@ def setup_password(self):
283283
logger.error(f"Failed to setup password: {e}")
284284
exit(1)
285285
# Routes and handlers
286+
@app.errorhandler(404)
287+
def handle_not_found(e):
288+
"""Handle 404 errors."""
289+
return jsonify({"error": "Not found"}), 404
290+
286291
@app.errorhandler(FreeGPTException)
287292
def handle_freegpt_exception(e):
288293
"""Handle FreeGPT exceptions."""
@@ -292,68 +297,88 @@ def handle_freegpt_exception(e):
292297
@app.errorhandler(Exception)
293298
def handle_general_exception(e):
294299
"""Handle general exceptions."""
300+
from werkzeug.exceptions import NotFound
301+
302+
# Don't log 404 errors as unexpected errors
303+
if isinstance(e, NotFound):
304+
return jsonify({"error": "Not found"}), 404
305+
295306
logger.error(f"Unexpected error: {e}", exc_info=True)
296307
return jsonify({"error": "Internal server error"}), 500
297308

298309
@app.route("/", methods=["GET", "POST"])
299-
async def index():
310+
def index():
300311
"""Main API endpoint for chat completion."""
312+
import asyncio
313+
314+
async def _async_index():
315+
try:
316+
# Get current settings
317+
settings = db_manager.get_settings()
318+
319+
# Extract question from request
320+
question = None
321+
if request.method == "GET":
322+
question = request.args.get(server_manager.args.keyword)
323+
else:
324+
# Handle file upload
325+
if 'file' in request.files:
326+
file = request.files['file']
327+
is_valid, error_msg = validate_file_upload(file, config.files.allowed_extensions)
328+
if not is_valid:
329+
raise FileUploadError(error_msg)
330+
331+
question = file.read().decode('utf-8')
332+
333+
if not question:
334+
return "<p id='response'>Please enter a question</p>"
335+
336+
# Sanitize input
337+
question = sanitize_input(question, 10000) # 10KB limit
338+
339+
# Verify token access
340+
token = request.args.get("token")
341+
username = auth_service.verify_token_access(
342+
token,
343+
server_manager.args.private_mode
344+
)
345+
346+
if server_manager.args.private_mode and not username:
347+
return "<p id='response'>Invalid token</p>"
348+
349+
if not username:
350+
username = "admin"
351+
352+
# Generate AI response
353+
response_text = await ai_service.generate_response(
354+
message=question,
355+
username=username,
356+
use_history=server_manager.args.enable_history,
357+
remove_sources=server_manager.args.remove_sources,
358+
use_proxies=server_manager.args.enable_proxies,
359+
cookie_file=server_manager.args.cookie_file
360+
)
361+
362+
logger.info(f"Generated response for user '{username}' ({len(response_text)} chars)")
363+
return response_text
364+
365+
except FreeGPTException as e:
366+
logger.error(f"API error: {e}")
367+
return f"<p id='response'>Error: {e}</p>"
368+
except Exception as e:
369+
logger.error(f"Unexpected API error: {e}", exc_info=True)
370+
return "<p id='response'>Internal server error</p>"
371+
372+
# Run the async function
301373
try:
302-
# Get current settings
303-
settings = db_manager.get_settings()
304-
305-
# Extract question from request
306-
question = None
307-
if request.method == "GET":
308-
question = request.args.get(server_manager.args.keyword)
309-
else:
310-
# Handle file upload
311-
if 'file' in request.files:
312-
file = request.files['file']
313-
is_valid, error_msg = validate_file_upload(file, config.files.allowed_extensions)
314-
if not is_valid:
315-
raise FileUploadError(error_msg)
316-
317-
question = file.read().decode('utf-8')
318-
319-
if not question:
320-
return "<p id='response'>Please enter a question</p>"
321-
322-
# Sanitize input
323-
question = sanitize_input(question, 10000) # 10KB limit
324-
325-
# Verify token access
326-
token = request.args.get("token")
327-
username = auth_service.verify_token_access(
328-
token,
329-
server_manager.args.private_mode
330-
)
331-
332-
if server_manager.args.private_mode and not username:
333-
return "<p id='response'>Invalid token</p>"
334-
335-
if not username:
336-
username = "admin"
337-
338-
# Generate AI response
339-
response_text = await ai_service.generate_response(
340-
message=question,
341-
username=username,
342-
use_history=server_manager.args.enable_history,
343-
remove_sources=server_manager.args.remove_sources,
344-
use_proxies=server_manager.args.enable_proxies,
345-
cookie_file=server_manager.args.cookie_file
346-
)
347-
348-
logger.info(f"Generated response for user '{username}' ({len(response_text)} chars)")
349-
return response_text
350-
351-
except FreeGPTException as e:
352-
logger.error(f"API error: {e}")
353-
return f"<p id='response'>Error: {e}</p>"
374+
loop = asyncio.new_event_loop()
375+
asyncio.set_event_loop(loop)
376+
return loop.run_until_complete(_async_index())
354377
except Exception as e:
355-
logger.error(f"Unexpected API error: {e}", exc_info=True)
356-
return "<p id='response'>Internal server error</p>"
378+
logger.error(f"Async execution error: {e}", exc_info=True)
379+
return f"<p id='response'>Error: AI API call failed: {e}</p>"
380+
finally:
381+
loop.close()
357382

358383
@app.route("/login", methods=["GET", "POST"])
359384
def login():
@@ -631,6 +656,20 @@ def generate_token():
631656
"""Generate a new token."""
632657
return generate_uuid()
633658

659+
@app.route("/favicon.ico")
660+
def favicon():
661+
"""Serve favicon."""
662+
try:
663+
from flask import send_from_directory
664+
return send_from_directory(
665+
str(Path(app.static_folder) / "img"),
666+
"favicon(Nicoladipa).png",
667+
mimetype='image/png'
668+
)
669+
except:
670+
# Return empty response if favicon not found
671+
return "", 204
672+
634673
def main():
635674
"""Main entry point."""
636675
try:

src/ai_service.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,8 +258,15 @@ async def _call_ai_api(
258258

259259
# Collect response
260260
response_text = ""
261-
async for chunk in response:
262-
response_text += str(chunk)
261+
262+
# Handle both string responses and async generators
263+
if hasattr(response, '__aiter__'):
264+
# It's an async generator
265+
async for chunk in response:
266+
response_text += str(chunk)
267+
else:
268+
# It's already a string
269+
response_text = str(response)
263270

264271
if not response_text:
265272
raise AIProviderError("Empty response from AI provider")

0 commit comments

Comments
 (0)