SOY NV AI commited on
Commit Β·
4b16f0b
1
Parent(s): 7f732cd
Fix: Resolve file path mismatch on live server by adding get_safe_path utility and safe_file_path property
Browse files- app/database.py +6 -0
- app/routes.py +10 -8
- app/services/style_analysis_service.py +6 -5
- app/utils/file_utils.py +34 -0
app/database.py
CHANGED
|
@@ -55,6 +55,12 @@ class UploadedFile(db.Model):
|
|
| 55 |
# κ΄κ³
|
| 56 |
parent_file = db.relationship('UploadedFile', remote_side=[id], backref='child_files')
|
| 57 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
def to_dict(self):
|
| 59 |
# μ²ν¬ κ°μ κ³μ°
|
| 60 |
chunk_count = len(self.chunks) if hasattr(self, 'chunks') else 0
|
|
|
|
| 55 |
# κ΄κ³
|
| 56 |
parent_file = db.relationship('UploadedFile', remote_side=[id], backref='child_files')
|
| 57 |
|
| 58 |
+
@property
|
| 59 |
+
def safe_file_path(self):
|
| 60 |
+
"""νκ²½ λ³νμ λμνλ μμ ν νμΌ κ²½λ‘ λ°ν"""
|
| 61 |
+
from app.utils.file_utils import get_safe_path
|
| 62 |
+
return get_safe_path(self.file_path)
|
| 63 |
+
|
| 64 |
def to_dict(self):
|
| 65 |
# μ²ν¬ κ°μ κ³μ°
|
| 66 |
chunk_count = len(self.chunks) if hasattr(self, 'chunks') else 0
|
app/routes.py
CHANGED
|
@@ -12770,8 +12770,9 @@ def create_file_parent_chunk(file_id):
|
|
| 12770 |
return jsonify({'error': 'Parent Chunkλ ν
μ€νΈ νμΌ(.txt, .md)μλ§ μμ±ν μ μμ΅λλ€.'}), 400
|
| 12771 |
|
| 12772 |
# νμΌ κ²½λ‘ νμΈ
|
| 12773 |
-
|
| 12774 |
-
|
|
|
|
| 12775 |
print(f"[Parent Chunk μμ±] μ€λ₯: {error_msg}")
|
| 12776 |
return jsonify({'error': error_msg}), 500
|
| 12777 |
|
|
@@ -12779,13 +12780,13 @@ def create_file_parent_chunk(file_id):
|
|
| 12779 |
try:
|
| 12780 |
encoding = 'utf-8'
|
| 12781 |
try:
|
| 12782 |
-
with open(
|
| 12783 |
content = f.read()
|
| 12784 |
except UnicodeDecodeError:
|
| 12785 |
-
with open(
|
| 12786 |
content = f.read()
|
| 12787 |
except FileNotFoundError:
|
| 12788 |
-
error_msg = f'νμΌμ μ°Ύμ μ μμ΅λλ€: {
|
| 12789 |
print(f"[Parent Chunk μμ±] μ€λ₯: {error_msg}")
|
| 12790 |
return jsonify({'error': error_msg}), 500
|
| 12791 |
except PermissionError:
|
|
@@ -12855,15 +12856,16 @@ def process_chunks(file_id):
|
|
| 12855 |
|
| 12856 |
# νμΌ λ΄μ© μ½κΈ°
|
| 12857 |
try:
|
|
|
|
| 12858 |
encoding = 'utf-8'
|
| 12859 |
try:
|
| 12860 |
-
with open(
|
| 12861 |
content = f.read()
|
| 12862 |
except UnicodeDecodeError:
|
| 12863 |
-
with open(
|
| 12864 |
content = f.read()
|
| 12865 |
except Exception as e:
|
| 12866 |
-
return jsonify({'error': f'νμΌμ μ½μ μ μμ΅λλ€: {str(e)}'}), 500
|
| 12867 |
|
| 12868 |
print(f"[λ¨κ³ 2: Chunk μμ±] νμΌ ID {file_id}μ λν Chunk μμ± μμ")
|
| 12869 |
chunk_count = create_chunks_for_file(file_id, content, skip_episode_analysis=True, skip_graph_extraction=True)
|
|
|
|
| 12770 |
return jsonify({'error': 'Parent Chunkλ ν
μ€νΈ νμΌ(.txt, .md)μλ§ μμ±ν μ μμ΅λλ€.'}), 400
|
| 12771 |
|
| 12772 |
# νμΌ κ²½λ‘ νμΈ
|
| 12773 |
+
safe_path = file.safe_file_path
|
| 12774 |
+
if not safe_path or not os.path.exists(safe_path):
|
| 12775 |
+
error_msg = f'νμΌμ μ°Ύμ μ μμ΅λλ€ (DBκ²½λ‘: {file.file_path}, μλκ²½λ‘: {safe_path})'
|
| 12776 |
print(f"[Parent Chunk μμ±] μ€λ₯: {error_msg}")
|
| 12777 |
return jsonify({'error': error_msg}), 500
|
| 12778 |
|
|
|
|
| 12780 |
try:
|
| 12781 |
encoding = 'utf-8'
|
| 12782 |
try:
|
| 12783 |
+
with open(safe_path, 'r', encoding=encoding) as f:
|
| 12784 |
content = f.read()
|
| 12785 |
except UnicodeDecodeError:
|
| 12786 |
+
with open(safe_path, 'r', encoding='cp949') as f:
|
| 12787 |
content = f.read()
|
| 12788 |
except FileNotFoundError:
|
| 12789 |
+
error_msg = f'νμΌμ μ°Ύμ μ μμ΅λλ€: {safe_path}'
|
| 12790 |
print(f"[Parent Chunk μμ±] μ€λ₯: {error_msg}")
|
| 12791 |
return jsonify({'error': error_msg}), 500
|
| 12792 |
except PermissionError:
|
|
|
|
| 12856 |
|
| 12857 |
# νμΌ λ΄μ© μ½κΈ°
|
| 12858 |
try:
|
| 12859 |
+
safe_path = file.safe_file_path
|
| 12860 |
encoding = 'utf-8'
|
| 12861 |
try:
|
| 12862 |
+
with open(safe_path, 'r', encoding=encoding) as f:
|
| 12863 |
content = f.read()
|
| 12864 |
except UnicodeDecodeError:
|
| 12865 |
+
with open(safe_path, 'r', encoding='cp949') as f:
|
| 12866 |
content = f.read()
|
| 12867 |
except Exception as e:
|
| 12868 |
+
return jsonify({'error': f'νμΌμ μ½μ μ μμ΅λλ€: {str(e)} (κ²½λ‘: {file.file_path})'}), 500
|
| 12869 |
|
| 12870 |
print(f"[λ¨κ³ 2: Chunk μμ±] νμΌ ID {file_id}μ λν Chunk μμ± μμ")
|
| 12871 |
chunk_count = create_chunks_for_file(file_id, content, skip_episode_analysis=True, skip_graph_extraction=True)
|
app/services/style_analysis_service.py
CHANGED
|
@@ -31,7 +31,7 @@ class StyleAnalysisService:
|
|
| 31 |
if not file_record:
|
| 32 |
raise ValueError(f"File {file_id} not found")
|
| 33 |
|
| 34 |
-
text_content = self._read_file_content(file_record.
|
| 35 |
# ν
μ€νΈκ° μμ΄λ DB μ‘°νλ μλν΄μΌ ν¨ (μ΄λ―Έ μ μ₯λ κ²½μ°)
|
| 36 |
|
| 37 |
if part == "bible":
|
|
@@ -58,14 +58,15 @@ class StyleAnalysisService:
|
|
| 58 |
|
| 59 |
def _read_file_content(self, file_path: str) -> str:
|
| 60 |
"""νμΌ μ½κΈ° λ° μ μ²λ¦¬"""
|
|
|
|
| 61 |
try:
|
| 62 |
-
|
| 63 |
-
file_path = os.path.join(os.getcwd(), file_path)
|
| 64 |
|
| 65 |
-
if not os.path.exists(
|
|
|
|
| 66 |
return ""
|
| 67 |
|
| 68 |
-
with open(
|
| 69 |
return f.read()
|
| 70 |
except Exception as e:
|
| 71 |
logger.error(f"Error reading file {file_path}: {e}")
|
|
|
|
| 31 |
if not file_record:
|
| 32 |
raise ValueError(f"File {file_id} not found")
|
| 33 |
|
| 34 |
+
text_content = self._read_file_content(file_record.safe_file_path)
|
| 35 |
# ν
μ€νΈκ° μμ΄λ DB μ‘°νλ μλν΄μΌ ν¨ (μ΄λ―Έ μ μ₯λ κ²½μ°)
|
| 36 |
|
| 37 |
if part == "bible":
|
|
|
|
| 58 |
|
| 59 |
def _read_file_content(self, file_path: str) -> str:
|
| 60 |
"""νμΌ μ½κΈ° λ° μ μ²λ¦¬"""
|
| 61 |
+
from app.utils.file_utils import get_safe_path
|
| 62 |
try:
|
| 63 |
+
safe_path = get_safe_path(file_path)
|
|
|
|
| 64 |
|
| 65 |
+
if not os.path.exists(safe_path):
|
| 66 |
+
logger.warning(f"File not found: {file_path} (Safe path tried: {safe_path})")
|
| 67 |
return ""
|
| 68 |
|
| 69 |
+
with open(safe_path, 'r', encoding='utf-8', errors='ignore') as f:
|
| 70 |
return f.read()
|
| 71 |
except Exception as e:
|
| 72 |
logger.error(f"Error reading file {file_path}: {e}")
|
app/utils/file_utils.py
CHANGED
|
@@ -2,6 +2,7 @@
|
|
| 2 |
νμΌ κ΄λ ¨ μ νΈλ¦¬ν° ν¨μ
|
| 3 |
"""
|
| 4 |
|
|
|
|
| 5 |
from pathlib import Path
|
| 6 |
from typing import Optional
|
| 7 |
from werkzeug.utils import secure_filename
|
|
@@ -12,6 +13,39 @@ from app.core.logger import get_logger
|
|
| 12 |
logger = get_logger(__name__)
|
| 13 |
|
| 14 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
def allowed_file(filename: str) -> bool:
|
| 16 |
"""
|
| 17 |
νμΌ νμ₯μκ° νμ©λ νμ₯μμΈμ§ νμΈ
|
|
|
|
| 2 |
νμΌ κ΄λ ¨ μ νΈλ¦¬ν° ν¨μ
|
| 3 |
"""
|
| 4 |
|
| 5 |
+
import os
|
| 6 |
from pathlib import Path
|
| 7 |
from typing import Optional
|
| 8 |
from werkzeug.utils import secure_filename
|
|
|
|
| 13 |
logger = get_logger(__name__)
|
| 14 |
|
| 15 |
|
| 16 |
+
def get_safe_path(stored_path: str) -> str:
|
| 17 |
+
"""
|
| 18 |
+
DBμ μ μ₯λ νμΌ κ²½λ‘κ° νμ¬ νκ²½μμ μ ν¨νμ§ μμ κ²½μ°,
|
| 19 |
+
νμ¬ UPLOAD_FOLDER κΈ°μ€μΌλ‘ 보μ λ κ²½λ‘λ₯Ό λ°νν©λλ€.
|
| 20 |
+
"""
|
| 21 |
+
if not stored_path:
|
| 22 |
+
return ""
|
| 23 |
+
|
| 24 |
+
# 1. μλ³Έ κ²½λ‘κ° μ‘΄μ¬νλ©΄ κ·Έλλ‘ λ°ν
|
| 25 |
+
if os.path.exists(stored_path):
|
| 26 |
+
return stored_path
|
| 27 |
+
|
| 28 |
+
# 2. νμΌλͺ
λ§ μΆμΆνμ¬ νμ¬ μ€μ λ UPLOAD_FOLDERμμ μ°ΎκΈ°
|
| 29 |
+
filename = os.path.basename(stored_path)
|
| 30 |
+
new_path = os.path.join(str(Config.UPLOAD_FOLDER), filename)
|
| 31 |
+
|
| 32 |
+
if os.path.exists(new_path):
|
| 33 |
+
return new_path
|
| 34 |
+
|
| 35 |
+
# 3. /app/uploads/ -> /data/uploads/ λ³ν μλ (HF/Railway μΌλ°μ μΈ μΌμ΄μ€)
|
| 36 |
+
if '/app/uploads/' in stored_path:
|
| 37 |
+
alt_path = stored_path.replace('/app/uploads/', str(Config.UPLOAD_FOLDER) + '/')
|
| 38 |
+
if os.path.exists(alt_path):
|
| 39 |
+
return alt_path
|
| 40 |
+
|
| 41 |
+
# 4. μλ κ²½λ‘ μλ
|
| 42 |
+
rel_path = os.path.join(os.getcwd(), stored_path)
|
| 43 |
+
if os.path.exists(rel_path):
|
| 44 |
+
return rel_path
|
| 45 |
+
|
| 46 |
+
return stored_path # μ°Ύμ§ λͺ»νλ©΄ μΌλ¨ μλ³Έ λ°ν (μλ¬ μ²λ¦¬λ νΈμΆλΆμμ)
|
| 47 |
+
|
| 48 |
+
|
| 49 |
def allowed_file(filename: str) -> bool:
|
| 50 |
"""
|
| 51 |
νμΌ νμ₯μκ° νμ©λ νμ₯μμΈμ§ νμΈ
|