Skip to content

Commit 1a04702

Browse files
committed
remove project_id requirement for media handling
1 parent 9203f8f commit 1a04702

4 files changed

Lines changed: 16 additions & 117 deletions

File tree

langfuse/_client/resource_manager.py

Lines changed: 0 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -229,16 +229,6 @@ def _initialize_instance(
229229
ingestion_consumer.start()
230230
self._ingestion_consumers.append(ingestion_consumer)
231231

232-
# Project ID handling
233-
self._project_id = None
234-
self._project_id_fetched = threading.Event()
235-
self._fetch_project_id_thread = threading.Thread(
236-
target=self._fetch_project_id_background,
237-
name="langfuse-project-id-fetcher",
238-
daemon=True,
239-
)
240-
self._fetch_project_id_thread.start()
241-
242232
# Register shutdown handler
243233
atexit.register(self.shutdown)
244234

@@ -251,49 +241,6 @@ def _initialize_instance(
251241
f"media_threads={media_upload_thread_count or 1}"
252242
)
253243

254-
def _fetch_project_id_background(self):
255-
try:
256-
projects = self.api.projects.get(
257-
request_options={"max_retries": 3, "timeout_in_seconds": 5}
258-
)
259-
self._project_id = projects.data[0].id if projects.data else None
260-
261-
langfuse_logger.debug(
262-
f"API: Successfully fetched project ID: {self._project_id} for project with public_key={self.public_key}"
263-
)
264-
except Exception as e:
265-
langfuse_logger.warning(
266-
f"API error: Failed to fetch project ID. This may affect media uploads and URL generation. Error: {str(e)}"
267-
)
268-
269-
finally:
270-
self._project_id_fetched.set()
271-
272-
@property
273-
def project_id(self):
274-
if self._project_id:
275-
return self._project_id
276-
277-
if self._project_id_fetched.is_set():
278-
langfuse_logger.warning(
279-
"Configuration issue: Project ID unavailable. Media uploads and project-specific features may be affected. "
280-
"Check API connectivity and permissions for your public/secret key pair."
281-
)
282-
return None
283-
284-
fetch_completed = self._project_id_fetched.wait(0.5)
285-
286-
if not self._project_id:
287-
langfuse_logger.warning(
288-
"Configuration issue: Project ID retrieval failed. Media uploads and project-specific features may be affected. "
289-
"Check API connectivity and permissions for your public/secret key pair."
290-
if fetch_completed
291-
else "Timing issue: Project ID still being fetched. Operation proceeding without project ID. "
292-
"This is normal during startup, but may temporarily affect media uploads and URL generation."
293-
)
294-
295-
return self._project_id
296-
297244
def add_score_task(self, event: dict):
298245
try:
299246
# Sample scores with the same sampler that is used for tracing

langfuse/_client/span.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,6 @@ def _process_media_in_attribute(
467467
field=field,
468468
trace_id=self.trace_id,
469469
observation_id=self.id,
470-
project_id=self._langfuse_client._resources.project_id,
471470
)
472471
)
473472

langfuse/_task_manager/media_manager.py

Lines changed: 3 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import base64
2-
import hashlib
31
import logging
42
import time
53
from queue import Empty, Full, Queue
@@ -54,58 +52,14 @@ def process_next_media_upload(self):
5452
)
5553
self._queue.task_done()
5654

57-
def process_media_in_event(self, event: dict):
58-
try:
59-
if "body" not in event:
60-
return
61-
62-
body = event["body"]
63-
trace_id = body.get("traceId", None) or (
64-
body.get("id", None)
65-
if "type" in event and "trace" in event["type"]
66-
else None
67-
)
68-
69-
if trace_id is None:
70-
raise ValueError("trace_id is required for media upload")
71-
72-
observation_id = (
73-
body.get("id", None)
74-
if "type" in event
75-
and ("generation" in event["type"] or "span" in event["type"])
76-
else None
77-
)
78-
79-
multimodal_fields = ["input", "output", "metadata"]
80-
81-
for field in multimodal_fields:
82-
if field in body:
83-
processed_data = self._find_and_process_media(
84-
data=body[field],
85-
trace_id=trace_id,
86-
observation_id=observation_id,
87-
field=field,
88-
)
89-
90-
body[field] = processed_data
91-
92-
except Exception as e:
93-
self._log.error(
94-
f"Media processing error: Failed to process multimodal event content. Event data may be incomplete. Error: {e}"
95-
)
96-
9755
def _find_and_process_media(
9856
self,
9957
*,
10058
data: Any,
10159
trace_id: str,
10260
observation_id: Optional[str],
10361
field: str,
104-
project_id: Optional[str],
10562
):
106-
if not project_id:
107-
return data
108-
10963
seen = set()
11064
max_levels = 10
11165

@@ -121,7 +75,6 @@ def _process_data_recursively(data: Any, level: int):
12175
trace_id=trace_id,
12276
observation_id=observation_id,
12377
field=field,
124-
project_id=project_id,
12578
)
12679

12780
return data
@@ -137,7 +90,6 @@ def _process_data_recursively(data: Any, level: int):
13790
trace_id=trace_id,
13891
observation_id=observation_id,
13992
field=field,
140-
project_id=project_id,
14193
)
14294

14395
return media
@@ -159,7 +111,6 @@ def _process_data_recursively(data: Any, level: int):
159111
trace_id=trace_id,
160112
observation_id=observation_id,
161113
field=field,
162-
project_id=project_id,
163114
)
164115

165116
data["data"] = media
@@ -183,7 +134,6 @@ def _process_data_recursively(data: Any, level: int):
183134
trace_id=trace_id,
184135
observation_id=observation_id,
185136
field=field,
186-
project_id=project_id,
187137
)
188138

189139
data["data"] = media
@@ -210,7 +160,6 @@ def _process_media(
210160
trace_id: str,
211161
observation_id: Optional[str],
212162
field: str,
213-
project_id: str,
214163
):
215164
if (
216165
media._content_length is None
@@ -220,10 +169,9 @@ def _process_media(
220169
):
221170
return
222171

223-
# Important as this is will be used in the media reference string in serializer
224-
media._media_id = self._get_media_id(
225-
project_id=project_id, content_sha256_hash=media._content_sha256_hash
226-
)
172+
if media._media_id is None:
173+
self._log.error("Media ID is None. Skipping upload.")
174+
return
227175

228176
try:
229177
upload_media_job = UploadMediaJob(
@@ -255,13 +203,6 @@ def _process_media(
255203
f"Media processing error: Failed to process media_id={media._media_id} for trace_id={trace_id}. Error: {str(e)}"
256204
)
257205

258-
def _get_media_id(self, *, project_id: str, content_sha256_hash) -> str:
259-
hash_obj = hashlib.sha256()
260-
hash_obj.update((project_id + content_sha256_hash).encode("utf-8"))
261-
media_id = base64.urlsafe_b64encode(hash_obj.digest()).decode("utf-8")[:22]
262-
263-
return media_id
264-
265206
def _process_upload_media_job(
266207
self,
267208
*,

langfuse/media.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ def __init__(
6868
the current working directory is used.
6969
"""
7070
self.obj = obj
71-
self._media_id = None
7271

7372
if base64_data_uri is not None:
7473
parsed_data = self._parse_base64_data_uri(base64_data_uri)
@@ -96,6 +95,8 @@ def __init__(
9695
self._content_type = None
9796
self._source = None
9897

98+
self._media_id = self._get_media_id()
99+
99100
def _read_file(self, file_path: str) -> Optional[bytes]:
100101
try:
101102
with open(file_path, "rb") as file:
@@ -105,6 +106,17 @@ def _read_file(self, file_path: str) -> Optional[bytes]:
105106

106107
return None
107108

109+
def _get_media_id(self):
110+
content_hash = self._content_sha256_hash
111+
112+
if content_hash is None:
113+
return
114+
115+
# Convert hash to base64Url
116+
url_safe_content_hash = content_hash.replace("+", "-").replace("/", "_")
117+
118+
return url_safe_content_hash[:22]
119+
108120
@property
109121
def _content_length(self) -> Optional[int]:
110122
return len(self._content_bytes) if self._content_bytes else None

0 commit comments

Comments
 (0)