OpenRAG 0.5.0.dev34__py3-none-any.whl → 0.5.0.dev36__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
api/langflow_files.py CHANGED
@@ -1,43 +1,43 @@
1
1
  import json
2
2
  import os
3
3
  import tempfile
4
- from typing import List, Optional
5
4
 
6
5
  from fastapi import Depends, File, Form, UploadFile
7
- from pydantic import BaseModel
8
6
  from fastapi.responses import JSONResponse
7
+ from pydantic import BaseModel
9
8
 
10
9
  from dependencies import (
10
+ get_current_user,
11
11
  get_langflow_file_service,
12
+ get_optional_user,
12
13
  get_session_manager,
13
14
  get_task_service,
14
- get_current_user,
15
- get_optional_user,
16
15
  )
17
16
  from session_manager import User
17
+ from utils.file_utils import langflow_safe_filename_and_mimetype
18
18
  from utils.logging_config import get_logger
19
19
 
20
20
  logger = get_logger(__name__)
21
21
 
22
22
 
23
23
  class RunIngestionBody(BaseModel):
24
- file_paths: List[str] = []
25
- file_ids: Optional[List[str]] = None
26
- file_metadata: Optional[List[dict]] = None
27
- session_id: Optional[str] = None
28
- tweaks: Optional[dict] = None
29
- settings: Optional[dict] = None
24
+ file_paths: list[str] = []
25
+ file_ids: list[str] | None = None
26
+ file_metadata: list[dict] | None = None
27
+ session_id: str | None = None
28
+ tweaks: dict | None = None
29
+ settings: dict | None = None
30
30
 
31
31
 
32
32
  class DeleteFilesBody(BaseModel):
33
- file_ids: List[str]
33
+ file_ids: list[str]
34
34
 
35
35
 
36
36
  async def upload_user_file(
37
37
  file: UploadFile = File(...),
38
38
  langflow_file_service=Depends(get_langflow_file_service),
39
39
  session_manager=Depends(get_session_manager),
40
- user: Optional[User] = Depends(get_optional_user),
40
+ user: User | None = Depends(get_optional_user),
41
41
  ):
42
42
  """Upload a file to Langflow's Files API"""
43
43
  try:
@@ -45,11 +45,11 @@ async def upload_user_file(
45
45
  logger.debug("Processing file", filename=file.filename, size=file.size)
46
46
 
47
47
  content = await file.read()
48
- file_tuple = (
49
- file.filename,
50
- content,
51
- file.content_type or "application/octet-stream",
48
+ # Langflow's docling chokes on text/plain — rename .txt -> .md.
49
+ upload_filename, upload_mimetype = langflow_safe_filename_and_mimetype(
50
+ file.filename, file.content_type
52
51
  )
52
+ file_tuple = (upload_filename, content, upload_mimetype)
53
53
 
54
54
  jwt_token = user.jwt_token if user else session_manager.get_effective_jwt_token(None, None)
55
55
 
@@ -60,6 +60,7 @@ async def upload_user_file(
60
60
  except Exception as e:
61
61
  logger.error("upload_user_file endpoint failed", error_type=type(e).__name__, error=str(e))
62
62
  import traceback
63
+
63
64
  logger.error("Full traceback", traceback=traceback.format_exc())
64
65
  return JSONResponse({"error": str(e)}, status_code=500)
65
66
 
@@ -111,6 +112,7 @@ async def run_ingestion(
111
112
 
112
113
  if jwt_token:
113
114
  from auth_context import set_auth_context
115
+
114
116
  set_auth_context(user.user_id, jwt_token)
115
117
 
116
118
  try:
@@ -132,9 +134,9 @@ async def run_ingestion(
132
134
 
133
135
  async def upload_and_ingest_user_file(
134
136
  file: UploadFile = File(...),
135
- session_id: Optional[str] = Form(None),
136
- settings_json: Optional[str] = Form(None, alias="settings"),
137
- tweaks_json: Optional[str] = Form(None, alias="tweaks"),
137
+ session_id: str | None = Form(None),
138
+ settings_json: str | None = Form(None, alias="settings"),
139
+ tweaks_json: str | None = Form(None, alias="tweaks"),
138
140
  delete_after_ingest: str = Form("true"),
139
141
  langflow_file_service=Depends(get_langflow_file_service),
140
142
  session_manager=Depends(get_session_manager),
@@ -193,6 +195,7 @@ async def upload_and_ingest_user_file(
193
195
  )
194
196
  except Exception:
195
197
  from utils.file_utils import safe_unlink
198
+
196
199
  safe_unlink(temp_path)
197
200
  raise
198
201
 
@@ -221,4 +224,4 @@ async def delete_user_files(
221
224
  "errors": errors,
222
225
  },
223
226
  status_code=status,
224
- )
227
+ )
@@ -3,11 +3,15 @@ from typing import Any, Dict, List, Optional
3
3
  # Create custom processor for connector files using Langflow
4
4
  from models.processors import LangflowConnectorFileProcessor
5
5
  from services.langflow_file_service import LangflowFileService
6
+ from utils.file_utils import (
7
+ clean_connector_filename,
8
+ get_file_extension,
9
+ langflow_safe_filename_and_mimetype,
10
+ )
6
11
  from utils.logging_config import get_logger
7
12
 
8
13
  from .base import BaseConnector, ConnectorDocument
9
14
  from .connection_manager import ConnectionManager
10
- from utils.file_utils import get_file_extension, clean_connector_filename
11
15
 
12
16
  logger = get_logger(__name__)
13
17
 
@@ -73,11 +77,15 @@ class LangflowConnectorService:
73
77
 
74
78
  # Clean filename and ensure we don't add a double extension
75
79
  processed_filename = clean_connector_filename(document.filename, document.mimetype)
80
+ # Langflow's docling chokes on text/plain — rename .txt -> .md.
81
+ processed_filename, processed_mimetype = langflow_safe_filename_and_mimetype(
82
+ processed_filename, document.mimetype
83
+ )
76
84
 
77
85
  file_tuple = (
78
86
  processed_filename,
79
87
  content,
80
- document.mimetype or "application/octet-stream",
88
+ processed_mimetype,
81
89
  )
82
90
 
83
91
  # Step 0: Delete existing chunks for this file before re-ingesting
models/processors.py CHANGED
@@ -5,6 +5,7 @@ from utils.file_utils import (
5
5
  get_file_extension,
6
6
  clean_connector_filename,
7
7
  get_filename_aliases,
8
+ langflow_safe_filename_and_mimetype,
8
9
  )
9
10
 
10
11
  logger = get_logger(__name__)
@@ -868,14 +869,10 @@ class LangflowFileProcessor(TaskProcessor):
868
869
  if not content_type:
869
870
  content_type = 'application/octet-stream'
870
871
 
871
- # Rename .txt to .md for Langflow compatibility
872
- # Langflow has issues processing text/plain files
873
- langflow_filename = original_filename
874
- if original_filename.lower().endswith('.txt'):
875
- langflow_filename = original_filename[:-4] + '.md'
876
- content_type = 'text/markdown'
877
- logger.debug(f"Renamed {original_filename} to {langflow_filename} for Langflow")
878
-
872
+ # Langflow's docling chokes on text/plain — rename .txt -> .md.
873
+ langflow_filename, content_type = langflow_safe_filename_and_mimetype(
874
+ original_filename, content_type
875
+ )
879
876
  file_tuple = (langflow_filename, content, content_type)
880
877
 
881
878
  # Get JWT token using same logic as DocumentFileProcessor
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openrag
3
- Version: 0.5.0.dev34
3
+ Version: 0.5.0.dev36
4
4
  Summary: OpenRAG is a comprehensive Retrieval-Augmented Generation platform that enables intelligent document search and AI-powered conversations.
5
5
  Classifier: Development Status :: 4 - Beta
6
6
  Classifier: Environment :: Console
@@ -14,7 +14,7 @@ api/documents.py,sha256=5H3yiFrU4JKSxuICvyk0xdXqOWijflzBZW829OLBtaw,6167
14
14
  api/flows.py,sha256=jMpfs9dV3ciz0fMAmMp80FOMxXphOiERyBweu3-t33c,1828
15
15
  api/keys.py,sha256=xml08ZVmciwKg-7_v5raxQ5mOkVpWB1vORNIXh120dU,3382
16
16
  api/knowledge_filter.py,sha256=krJTX83FdL2umArbmTosI8E4x_5SooiDABwqiODYpJ0,15515
17
- api/langflow_files.py,sha256=VS5WdeDM-AecuLPhBTk4EmRUwQyWStJ_WP3-QSVfFFE,7959
17
+ api/langflow_files.py,sha256=vXPucrspWRryoEndqy1xnqjUi9SRouUutr3z7q7JFoE,8099
18
18
  api/models.py,sha256=QvvSaTAM1KKx-RGjQrjhZ6b6zD9PTbyHQbZ4oiSQOk4,5582
19
19
  api/nudges.py,sha256=hVWnZN4aegl7tTnEv2NjqDoFs78r8eX9zkhe0NrorIY,1921
20
20
  api/oidc.py,sha256=WJRnditsha1CqZQCaKgzKVGAJuQqRgho1danLhUEhDE,3455
@@ -43,7 +43,7 @@ config/settings.py,sha256=zhvJ3TAmdZwoWk55BPX4OuAAJiDTHlJg4_MoSWPhZMI,39298
43
43
  connectors/__init__.py,sha256=6ijOhF7jG-zJ3bIxQ4HIHZHqpT127cNvCDaaqdN_Pm8,390
44
44
  connectors/base.py,sha256=s9gBEIxl8_nZVtCeMKz7LrlOV-H0rCxvN_cFH8B9DMg,4532
45
45
  connectors/connection_manager.py,sha256=LrfiuoBB-hqNGjXhH-5x4uL6msU-OVOp7--4V302a14,28187
46
- connectors/langflow_connector_service.py,sha256=HjVgTmlpZCWsoR2msEuCouw3snX0HBHNv6Szm4A0Iik,17251
46
+ connectors/langflow_connector_service.py,sha256=7kK66gs4RXpTDO58FG9SBxEpHadwQr_FZNMQOzp74ic,17512
47
47
  connectors/service.py,sha256=_qyRDskMiNfPa2OyOan9gAmOgB5JjcLTidzzg-rhLWs,18229
48
48
  connectors/aws_s3/__init__.py,sha256=ZRXSKmYvYK7Kr7Rzcd0_YIMpqfAm5qjm06zF-YfPPhA,369
49
49
  connectors/aws_s3/api.py,sha256=CDpsdOZaOM7hT93Je4O_JD7GxJjPN0-_qgQPPSPiy40,6861
@@ -70,10 +70,10 @@ connectors/sharepoint/utils.py,sha256=OBNEbXb8uAfR-iR-ML0aOojGfGj03vJnKm9DbYf2hW
70
70
  mcp_http/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
71
71
  mcp_http/server.py,sha256=JutP94fQRCizeCN69kKkdYDFE71L3DqLTCcb397T8Eo,7738
72
72
  models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
73
- models/processors.py,sha256=Vc6a1HIHpIe9t3Jx7HJ_lCRrSmWtzw63C5bzJpxTz8s,35793
73
+ models/processors.py,sha256=IzyYgov0VWmyDKxgEdzo9DumbbqDJWfa8BgdTCDCQqA,35614
74
74
  models/tasks.py,sha256=9iINXQZxA9-hcYzG8xC_baBfLa2w6gcRPJdQHsx_Kms,1643
75
75
  models/url.py,sha256=92rsrLLyIqUErYipYz5QwUNTdHwJ2jBRV7PIVpncTyo,5764
76
- openrag-0.5.0.dev34.dist-info/licenses/LICENSE,sha256=jWcnPXkUxEinX60Yn-_zjsY9i84vz2QSb0fi53djOkg,11334
76
+ openrag-0.5.0.dev36.dist-info/licenses/LICENSE,sha256=jWcnPXkUxEinX60Yn-_zjsY9i84vz2QSb0fi53djOkg,11334
77
77
  services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
78
78
  services/api_key_service.py,sha256=NMz2ohJo0jcuHjDN3tHuzhCTVo6lsOqAkUhozzmWSv0,11720
79
79
  services/auth_service.py,sha256=nAKTvMyX-YUtiNfKF06Dq4E4iwHPBhfKR6nliqGpOSs,22090
@@ -144,7 +144,7 @@ utils/embedding_fields.py,sha256=l4cjVKNbe6hM75oLwyyZ7t94JJXRIzvgfzPmKcvrCbE,740
144
144
  utils/embeddings.py,sha256=luyWDU6Y4gw116XaF3_wHfdyKEv8zi3qRrMUtOgP1X4,1357
145
145
  utils/encryption.py,sha256=aTsiuhiG9rM6UmvnttfNyMFIBLpPSvEFb054fMT1Ohc,7758
146
146
  utils/env_utils.py,sha256=slkoqbTStWn0xJQJ9Ws0qtv6bUH_bC-rBJbWsgDw5pk,890
147
- utils/file_utils.py,sha256=n0Tp8OiBQ7QygRljl6-b8dNgqtWg1P_SB0GwOnra-y8,4345
147
+ utils/file_utils.py,sha256=NRDfj4e-VloPay3iF7MKAKIZHLufxEqtiyDSOvnA-Hw,5241
148
148
  utils/gpu_detection.py,sha256=yU8PtO9Fp0rfHhY6JW0212cS_SVMA12BtWUXHXpQyp0,1697
149
149
  utils/hash_utils.py,sha256=LIEss0uTBNJcgOvMLoOoj0pIVkC3A7Wzs1IqfNx_23s,2200
150
150
  utils/langflow_headers.py,sha256=X8vZNYRv9jvwBu7Grd8S396dalPTZP9Ecb6owHMU2KE,3248
@@ -159,8 +159,8 @@ utils/telemetry/__init__.py,sha256=xoStY8hoYWnVe0B_jNthSdzRb7AxCT0rhM8ba9Q0Obg,2
159
159
  utils/telemetry/category.py,sha256=wei3V5WyUaiadYjEE5s0ys9PY0TjnebIvTykQU0P_2k,1114
160
160
  utils/telemetry/client.py,sha256=RhjW1a27w7W6gHt9X7AxdRPdZGmCEQDPskkxj5nsuiQ,12500
161
161
  utils/telemetry/message_id.py,sha256=IAu0wBVNOGPcSlQ0bAzvqIYr1Ac_n8wSTSxXzq_tiV0,9634
162
- openrag-0.5.0.dev34.dist-info/METADATA,sha256=f0L0xZ-KNdGeg-BriYou_3rtWkkzl-xa7P-trb86p1k,7819
163
- openrag-0.5.0.dev34.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
164
- openrag-0.5.0.dev34.dist-info/entry_points.txt,sha256=ArKNHB63I3K8vynNkogvZOLmmQFpIsHDL7MvreCmju4,45
165
- openrag-0.5.0.dev34.dist-info/top_level.txt,sha256=5vfLBIkzuwBJrizhCSZiXV7NTzTRIMlNLsyzYDEeCF8,125
166
- openrag-0.5.0.dev34.dist-info/RECORD,,
162
+ openrag-0.5.0.dev36.dist-info/METADATA,sha256=Vb6XbbV_JOqF6PkPkiZlDtECtd5YbumtFvMlL-mGI1A,7819
163
+ openrag-0.5.0.dev36.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
164
+ openrag-0.5.0.dev36.dist-info/entry_points.txt,sha256=ArKNHB63I3K8vynNkogvZOLmmQFpIsHDL7MvreCmju4,45
165
+ openrag-0.5.0.dev36.dist-info/top_level.txt,sha256=5vfLBIkzuwBJrizhCSZiXV7NTzTRIMlNLsyzYDEeCF8,125
166
+ openrag-0.5.0.dev36.dist-info/RECORD,,
utils/file_utils.py CHANGED
@@ -101,6 +101,25 @@ def clean_connector_filename(filename: str, mimetype: str) -> str:
101
101
  return clean_name
102
102
 
103
103
 
104
+ def langflow_safe_filename_and_mimetype(filename: str, mimetype: str | None) -> tuple[str, str]:
105
+ """Apply the .txt -> .md workaround for Langflow ingestion.
106
+
107
+ Langflow's docling component fails on text/plain (see commit f6b9fe0).
108
+ The workaround is to rename .txt files to .md with text/markdown before
109
+ handing the file to Langflow. Centralised here so every Langflow-upload
110
+ site applies it identically — local user uploads, connector-driven
111
+ ingestion, and the direct upload route.
112
+
113
+ Returns the (possibly rewritten) (filename, mimetype) pair. Pass-through
114
+ for all other extensions; falls back to application/octet-stream when
115
+ mimetype is missing.
116
+ """
117
+ safe_mimetype = mimetype or "application/octet-stream"
118
+ if filename and filename.lower().endswith(".txt"):
119
+ return filename[:-4] + ".md", "text/markdown"
120
+ return filename, safe_mimetype
121
+
122
+
104
123
  def get_filename_aliases(filename: str) -> list[str]:
105
124
  """Return equivalent filename variants used by ingestion/indexing.
106
125