Fix tiktoken SSL/gevent conflict in tests: use fallback token counting
This commit is contained in:
parent
4cc7e61c8b
commit
9fb7047866
2 changed files with 68 additions and 3 deletions
19
models.py
19
models.py
|
|
@ -1,7 +1,13 @@
|
|||
from flask_sqlalchemy import SQLAlchemy
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import tiktoken
|
||||
import os
|
||||
try:
|
||||
import tiktoken
|
||||
TIKTOKEN_AVAILABLE = True
|
||||
except Exception:
|
||||
TIKTOKEN_AVAILABLE = False
|
||||
tiktoken = None
|
||||
|
||||
import json
|
||||
|
||||
|
|
@ -119,9 +125,16 @@ class Message(db.Model):
|
|||
if self.token_count is None:
|
||||
if self.is_base64_image():
|
||||
self.token_count = 0
|
||||
elif not TIKTOKEN_AVAILABLE or os.environ.get("TESTING"):
|
||||
# Fallback: estimate ~4 chars per token when tiktoken unavailable
|
||||
self.token_count = len(self.content) // 4 + 1
|
||||
else:
|
||||
encoding = tiktoken.encoding_for_model("gpt-4")
|
||||
self.token_count = len(encoding.encode(self.content))
|
||||
try:
|
||||
encoding = tiktoken.encoding_for_model("gpt-4")
|
||||
self.token_count = len(encoding.encode(self.content))
|
||||
except Exception:
|
||||
# Fallback on any tiktoken error (network, SSL, etc.)
|
||||
self.token_count = len(self.content) // 4 + 1
|
||||
return self.token_count
|
||||
|
||||
def is_base64_image(self):
|
||||
|
|
|
|||
|
|
@ -5,7 +5,59 @@ pytest configuration and fixtures for OpenCompletion testing
|
|||
Sets up common test environment variables and fixtures used across all tests.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
# =============================================================================
|
||||
# CRITICAL: Mock tiktoken BEFORE any other imports
|
||||
# tiktoken tries to download encoding files over HTTPS which conflicts
|
||||
# with gevent's monkey-patching of SSL, causing RecursionError
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class MockTiktokenEncoding:
|
||||
"""Mock tiktoken encoding that doesn't make network requests"""
|
||||
def encode(self, text):
|
||||
# Simple approximation: ~4 chars per token
|
||||
return list(range(len(text) // 4 + 1))
|
||||
|
||||
|
||||
class MockTiktoken:
|
||||
"""Mock tiktoken module"""
|
||||
_encoding = MockTiktokenEncoding()
|
||||
|
||||
@staticmethod
|
||||
def encoding_for_model(model_name):
|
||||
return MockTiktoken._encoding
|
||||
|
||||
@staticmethod
|
||||
def get_encoding(encoding_name):
|
||||
return MockTiktoken._encoding
|
||||
|
||||
|
||||
# Insert mock tiktoken into sys.modules BEFORE any imports
|
||||
if 'tiktoken' not in sys.modules:
|
||||
sys.modules['tiktoken'] = MockTiktoken()
|
||||
|
||||
|
||||
def pytest_configure(config):
|
||||
"""
|
||||
Called early in pytest startup, before test collection.
|
||||
Ensures tiktoken is mocked before any test imports happen.
|
||||
"""
|
||||
if 'tiktoken' not in sys.modules:
|
||||
sys.modules['tiktoken'] = MockTiktoken()
|
||||
else:
|
||||
# If tiktoken was already imported, patch its functions
|
||||
import tiktoken
|
||||
tiktoken.encoding_for_model = MockTiktoken.encoding_for_model
|
||||
tiktoken.get_encoding = MockTiktoken.get_encoding
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Now safe to do other imports
|
||||
# =============================================================================
|
||||
|
||||
import pytest
|
||||
import tempfile
|
||||
from unittest.mock import patch, MagicMock
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue