Skip to content

Commit 39426da

Browse files
authored
Merge pull request #13 from LlmKira/dev-20250304
🔧 fix(model): enhance Windows model loading with robust path handling
2 parents 4fffd3a + d9703da commit 39426da

File tree

4 files changed

+95
-24
lines changed

4 files changed

+95
-24
lines changed

.github/workflows/python_test.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ on:
66
branches:
77
- main
88
- dev
9-
- develop
10-
- '**-develop'
9+
- 'dev-**'
1110

1211
jobs:
1312
Testing:
@@ -27,6 +26,7 @@ jobs:
2726
- name: Install dependencies
2827
run: |
2928
pdm install --no-lock -G testing
30-
- name: Run Tests
29+
30+
- name: Run Regular Tests
3131
run: |
3232
pdm run -v pytest tests

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "fast-langdetect"
3-
version = "0.3.0"
3+
version = "0.3.1"
44
description = "Quickly detect text language and segment language"
55
authors = [
66
{ name = "sudoskys", email = "coldlando@hotmail.com" },

src/fast_langdetect/infer.py

Lines changed: 51 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -130,30 +130,61 @@ def load_with_download(self, model_path: Path, proxy: Optional[str] = None) -> A
130130
return self.load_local(model_path)
131131

132132
def _load_windows_compatible(self, model_path: Path) -> Any:
133-
"""Handle Windows path compatibility issues."""
134-
if re.match(r'^[A-Za-z0-9_/\\:.]*$', str(model_path)):
135-
return fasttext.load_model(str(model_path))
133+
"""
134+
Handle Windows path compatibility issues when loading FastText models.
136135
137-
# Create a temporary file to handle special characters in the path
138-
with tempfile.NamedTemporaryFile(delete=False) as tmp:
139-
tmp_path = tmp.name
140-
shutil.copy2(model_path, tmp_path)
136+
Attempts multiple strategies in order:
137+
1. Direct loading if path contains only safe characters
138+
2. Loading via relative path if possible
139+
3. Copying to temporary file as last resort
141140
141+
:param model_path: Path to the model file
142+
:return: Loaded FastText model
143+
:raises DetectError: If all loading strategies fail
144+
"""
145+
model_path_str = str(model_path.resolve())
146+
147+
# Try to load model directly
142148
try:
143-
model = fasttext.load_model(tmp_path)
144-
return model
149+
return fasttext.load_model(model_path_str)
150+
except Exception as e:
151+
logger.debug(f"fast-langdetect: Load model failed: {e}")
152+
153+
# Try to load model using relative path
154+
try:
155+
cwd = Path.cwd()
156+
rel_path = os.path.relpath(model_path, cwd)
157+
return fasttext.load_model(rel_path)
158+
except Exception as e:
159+
logger.debug(f"fast-langdetect: Failed to load model using relative path: {e}")
160+
161+
# Use temporary file as last resort
162+
logger.debug(f"fast-langdetect: Using temporary file to load model: {model_path}")
163+
tmp_path = None
164+
try:
165+
# Use NamedTemporaryFile to create a temporary file
166+
tmp_fd, tmp_path = tempfile.mkstemp(suffix='.bin')
167+
os.close(tmp_fd) # Close file descriptor
168+
169+
# Copy model file to temporary location
170+
shutil.copy2(model_path, tmp_path)
171+
return fasttext.load_model(tmp_path)
172+
except Exception as e:
173+
raise DetectError(f"Failed to load model using temporary file: {e}")
145174
finally:
146-
try:
147-
os.unlink(tmp_path)
148-
except (OSError, PermissionError) as e:
149-
logger.warning(f"fast-langdetect: Failed to delete temporary file {tmp_path}: {e}")
150-
# Schedule file for deletion on next reboot on Windows
151-
if platform.system() == "Windows":
152-
try:
153-
import _winapi
154-
_winapi.MoveFileEx(tmp_path, None, _winapi.MOVEFILE_DELAY_UNTIL_REBOOT)
155-
except (ImportError, AttributeError, OSError) as we:
156-
logger.warning(f"fast-langdetect: Failed to schedule file deletion: {we}")
175+
# Clean up temporary file
176+
if tmp_path and os.path.exists(tmp_path):
177+
try:
178+
os.unlink(tmp_path)
179+
except (OSError, PermissionError) as e:
180+
logger.warning(f"fast-langdetect: Failed to delete temporary file {tmp_path}: {e}")
181+
# Plan to delete on next reboot on Windows
182+
if platform.system() == "Windows":
183+
try:
184+
import _winapi
185+
_winapi.MoveFileEx(tmp_path, None, _winapi.MOVEFILE_DELAY_UNTIL_REBOOT)
186+
except (ImportError, AttributeError, OSError) as we:
187+
logger.warning(f"fast-langdetect: Failed to schedule file deletion: {we}")
157188

158189
def _load_unix(self, model_path: Path) -> Any:
159190
"""Load model on Unix-like systems."""

tests/test_chinese_path.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import os
2+
import tempfile
3+
import shutil
4+
import platform
5+
from pathlib import Path
6+
import pytest
7+
from fast_langdetect.infer import LangDetectConfig, LangDetector
8+
9+
@pytest.mark.skipif(platform.system() != "Windows", reason="Windows path test")
10+
def test_model_loading_with_chinese_path():
11+
# 创建包含中文字符的临时目录
12+
temp_dir = Path(tempfile.gettempdir()) / "测试_模型_路径"
13+
os.makedirs(temp_dir, exist_ok=True)
14+
15+
try:
16+
# 使用项目中已有的模型文件
17+
# 查找项目根目录
18+
project_root = Path(__file__).parent.parent
19+
model_path = project_root / "src" / "fast_langdetect" / "resources" / "lid.176.ftz"
20+
21+
if not model_path.exists():
22+
pytest.skip(f"Model file does not exist: {model_path}")
23+
24+
# 复制模型文件到中文路径
25+
chinese_model_path = temp_dir / "测试模型.ftz"
26+
shutil.copy2(model_path, chinese_model_path)
27+
28+
# 正确使用自定义模型路径
29+
config = LangDetectConfig(
30+
custom_model_path=str(chinese_model_path),
31+
allow_fallback=False
32+
)
33+
detector = LangDetector(config)
34+
result = detector.detect("This is a test")
35+
36+
assert "lang" in result
37+
assert "score" in result
38+
finally:
39+
# 清理
40+
shutil.rmtree(temp_dir, ignore_errors=True)

0 commit comments

Comments
 (0)