File size: 5,689 Bytes
09c17cd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#!/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