LLMView / package /path_manager.py
WatNeru's picture
Add FastAPI word tree server
09c17cd
#!/usr/bin/env python3
"""
パス管理モジュール
PyInstaller対応とサーバー起動の両方に対応
"""
import os
import sys
from pathlib import Path
from typing import Optional
class PathManager:
"""パス管理クラス(シングルトン)"""
_instance: Optional["PathManager"] = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance._initialized = False
return cls._instance
def __init__(self):
if self._initialized:
return
self._initialized = True
self._setup_paths()
def _setup_paths(self):
"""パス設定を初期化"""
# 実行環境の判定
if getattr(sys, 'frozen', False):
# PyInstallerでビルドされた場合
self.is_pyinstaller = True
self.base_path = Path(sys._MEIPASS)
self.package_path = self.base_path / 'package'
self.python_executable = sys.executable
else:
# 開発環境の場合
self.is_pyinstaller = False
self.base_path = Path(__file__).parent.parent
self.package_path = self.base_path / 'package'
self.python_executable = sys.executable
# モデルパス設定
self.model_path = self._get_model_path()
# ログ出力
print(f"[PATH] PyInstaller: {self.is_pyinstaller}")
print(f"[PATH] Base path: {self.base_path}")
print(f"[PATH] Package path: {self.package_path}")
print(f"[PATH] Model path: {self.model_path}")
def _get_model_path(self) -> str:
"""モデルファイルのパスを取得"""
# 環境変数から取得
env_model_path = os.getenv('LLM_MODEL_PATH')
if env_model_path and os.path.exists(env_model_path):
return env_model_path
# 配布物からの相対位置(優先)
try:
# 実行ファイルのあるディレクトリ(PyInstaller実行時は dist/.../tauri_python_server の場所)
executable_dir = Path(os.path.dirname(sys.executable)) if getattr(sys, 'frozen', False) else Path(__file__).parent.parent
candidate_relative_paths = [
# 配布レイアウト: <root>/models/<file> (exe が <root>/python/ にある想定)
(executable_dir.parent / 'models' / 'llama-3.2-3b-instruct-q4_k_m.gguf'),
# exe と同階層に models/
(executable_dir / 'models' / 'llama-3.2-3b-instruct-q4_k_m.gguf'),
# MEIPASS(展開一時ディレクトリ)配下
(Path(getattr(sys, '_MEIPASS', str(self.base_path))) / 'models' / 'llama-3.2-3b-instruct-q4_k_m.gguf'),
]
for rel in candidate_relative_paths:
rel_str = str(rel)
if os.path.exists(rel_str):
return rel_str
except Exception:
pass
# デフォルトパス
default_paths = [
os.path.expanduser("~/Documents/GitHub/LLMV_app_frontend/src-tauri/python/models/llama-3.2-3b-instruct-q4_k_m.gguf"),
os.path.expanduser("~/Documents/models/llama-3.2-3b-instruct-q4_k_m.gguf"),
os.path.expanduser("~/models/llama-3.2-3b-instruct-q4_k_m.gguf"),
"/opt/models/llama-3.2-3b-instruct-q4_k_m.gguf"
]
for path in default_paths:
if os.path.exists(path):
return path
# 見つからない場合は最初のデフォルトパスを返す
return default_paths[0]
def get_package_path(self) -> str:
"""パッケージパスを取得"""
return str(self.package_path)
def get_model_path(self) -> str:
"""モデルパスを取得"""
return self.model_path
def get_python_executable(self) -> str:
"""Python実行ファイルのパスを取得"""
return self.python_executable
def setup_sys_path(self):
"""sys.pathを設定"""
package_path_str = self.get_package_path()
# パッケージパスを追加
if package_path_str not in sys.path:
sys.path.insert(0, package_path_str)
# conda環境のパッケージパスも追加(開発環境のみ)
if not self.is_pyinstaller:
conda_package_path = '/Users/wataru/Documents/AppProject/LLMView_Server/package'
if os.path.exists(conda_package_path) and conda_package_path not in sys.path:
sys.path.insert(0, conda_package_path)
print(f"[PATH] sys.path configured: {len(sys.path)} paths")
def get_server_config(self) -> dict:
"""サーバー設定を取得"""
return {
'host': '127.0.0.1',
'port': 5000,
'debug': False,
'use_reloader': False,
'threaded': True
}
def get_pyinstaller_spec_path(self) -> str:
"""PyInstaller specファイルのパスを取得"""
return str(self.base_path / 'tauri_python_server.spec')
def get_dist_path(self) -> str:
"""ビルド出力ディレクトリのパスを取得"""
return str(self.base_path / 'dist')
def get_executable_name(self) -> str:
"""実行ファイル名を取得"""
return 'tauri_python_server'
# グローバルインスタンス
path_manager = PathManager()
def get_path_manager() -> PathManager:
"""PathManagerインスタンスを取得"""
return path_manager