LLM-Bridge 1.15.4__py3-none-any.whl → 1.15.7__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.
@@ -2,7 +2,7 @@ from openai.types.responses import ResponseInputTextParam, ResponseInputImagePar
2
2
  ResponseInputContentParam, EasyInputMessageParam, ResponseOutputMessageParam, ResponseInputFileParam
3
3
 
4
4
  from llm_bridge.logic.chat_generate import media_processor
5
- from llm_bridge.logic.message_preprocess.file_type_checker import get_file_type, get_file_name
5
+ from llm_bridge.logic.message_preprocess.file_type_checker import get_file_type, get_filename_without_timestamp
6
6
  from llm_bridge.type.message import Message, ContentType
7
7
  from llm_bridge.type.model_message.openai_responses_message import OpenAIResponsesMessage
8
8
 
@@ -33,7 +33,7 @@ async def convert_message_to_openai_responses(message: Message) -> OpenAIRespons
33
33
  file_data, _ = await media_processor.get_base64_content_from_url(file_url)
34
34
  pdf_content = ResponseInputFileParam(
35
35
  type="input_file",
36
- filename=get_file_name(file_url),
36
+ filename=get_filename_without_timestamp(file_url),
37
37
  file_data=f"data:application/pdf;base64,{file_data}",
38
38
  )
39
39
  content.append(pdf_content)
@@ -1,6 +1,7 @@
1
1
  import mimetypes
2
2
  import os
3
3
  import re
4
+ from pathlib import PurePosixPath
4
5
 
5
6
  from llm_bridge.logic.file_fetch import fetch_file_data
6
7
  from llm_bridge.logic.message_preprocess.code_file_extensions import code_file_extensions
@@ -14,9 +15,12 @@ def is_file_type_supported(file_name: str) -> bool:
14
15
 
15
16
 
16
17
  async def get_file_type(file_url: str) -> tuple[str, str]:
17
- file_name = get_file_name(file_url)
18
+ file_name: str = get_filename_without_timestamp(file_url)
19
+
20
+ # Treat filenames without an extension as their own extension
21
+ suffix: str = PurePosixPath(file_name).suffix.lower()
22
+ file_extension: str = suffix if suffix else '.' + file_name.lower()
18
23
 
19
- file_extension = '.' + file_name.split('.')[-1].lower() # Treat filenames without an extension as their own extension
20
24
  if file_extension in code_file_extensions:
21
25
  return 'text', 'code'
22
26
  if file_extension == '.pdf':
@@ -41,9 +45,8 @@ async def get_file_type(file_url: str) -> tuple[str, str]:
41
45
  return 'unknown', 'unknown'
42
46
 
43
47
 
44
- # Without Timestamp
45
- def get_file_name(file_url: str) -> str:
46
- base_name = os.path.basename(file_url)
48
+ def get_filename_without_timestamp(file_url: str) -> str:
49
+ base_name = PurePosixPath(file_url).name
47
50
  match = re.search(r'-(.+)', base_name)
48
51
  if match:
49
52
  return match.group(1)
@@ -1,5 +1,5 @@
1
1
  from llm_bridge.logic.message_preprocess import document_processor
2
- from llm_bridge.logic.message_preprocess.file_type_checker import get_file_type, get_file_name
2
+ from llm_bridge.logic.message_preprocess.file_type_checker import get_file_type, get_filename_without_timestamp
3
3
  from llm_bridge.type.message import Message, Role, Content, ContentType
4
4
 
5
5
 
@@ -24,12 +24,12 @@ async def extract_text_files_to_message(message: Message, api_type: str) -> None
24
24
  if sub_type == "pdf" and api_type in ("OpenAI", "OpenAI-Azure", "Gemini-Vertex", "Gemini-Free", "Gemini-Paid", "Claude"):
25
25
  continue
26
26
 
27
- filename = get_file_name(file_url)
27
+ filename = get_filename_without_timestamp(file_url)
28
28
  file_text = await document_processor.extract_text_from_file(file_url)
29
29
 
30
30
  message.contents[i] = Content(
31
31
  type=ContentType.Text,
32
- data=f"{filename}: \n{file_text}\n"
32
+ data=f"<file name=\"{filename}\">\n{file_text}\n</file>"
33
33
  )
34
34
 
35
35
 
@@ -1,5 +1,5 @@
1
- import importlib.resources
2
1
  import json
2
+ from importlib.resources import files
3
3
  from typing import TypedDict
4
4
 
5
5
  from fastapi import HTTPException
@@ -12,13 +12,17 @@ class ModelPrice(TypedDict):
12
12
  output: float
13
13
 
14
14
 
15
- def load_json_file(package, filename):
16
- with importlib.resources.open_text(package, filename) as f:
17
- return json.load(f)
15
+ def load_json_file(package: str, filename: str):
16
+ content = files(package).joinpath(filename).read_text(encoding="utf-8")
17
+ return json.loads(content)
18
18
 
19
19
 
20
20
  def get_model_prices() -> list[ModelPrice]:
21
- return load_json_file("llm_bridge.resources", "model_prices.json")
21
+ prices = load_json_file("llm_bridge.resources", "model_prices.json")
22
+ for price in prices:
23
+ price["input"] = float(price["input"])
24
+ price["output"] = float(price["output"])
25
+ return prices
22
26
 
23
27
 
24
28
  def find_model_prices(api_type: str, model: str) -> ModelPrice | None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: LLM-Bridge
3
- Version: 1.15.4
3
+ Version: 1.15.7
4
4
  Summary: A Bridge for LLMs
5
5
  Author-email: windsnow1025 <windsnow1025@gmail.com>
6
6
  License-Expression: MIT
@@ -24,7 +24,7 @@ Description-Content-Type: text/markdown
24
24
 
25
25
  # LLM Bridge
26
26
 
27
- LLM Bridge is a unified Python interface for interacting with LLMs, including OpenAI (Native / Azure / GitHub), Gemini (AI Studio / Vertex), Claude, and Grok.
27
+ LLM Bridge is a unified Python interface for native interactions with various LLM providers.
28
28
 
29
29
  GitHub: [https://github.com/windsnow1025/LLM-Bridge](https://github.com/windsnow1025/LLM-Bridge)
30
30
 
@@ -81,12 +81,6 @@ The features listed represent the maximum capabilities of each API type supporte
81
81
 
82
82
  Copy `./usage/.env.example` and rename it to `./usage/.env`, then fill in the environment variables.
83
83
 
84
- ### Test
85
-
86
- ```bash
87
- uv run pytest
88
- ```
89
-
90
84
  ### Build
91
85
 
92
86
  ```bash
@@ -26,7 +26,7 @@ llm_bridge/client/model_client/gemini_client.py,sha256=4dcueIbpLFqkT98WxmeVmW9Vb
26
26
  llm_bridge/client/model_client/openai_client.py,sha256=tRb5-T5J5swwEwQW4ryz1L1KBoWF_VGwkQQpeVVy854,1526
27
27
  llm_bridge/logic/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
28
  llm_bridge/logic/file_fetch.py,sha256=Q8PGNj76E25sKD70TmlnSIdPgAxpNlb89syk87DbAGg,1341
29
- llm_bridge/logic/model_prices.py,sha256=hiXVbki3004Rrm5LQrmVfdm0lLABeygxtFB-Qn9_mm0,1219
29
+ llm_bridge/logic/model_prices.py,sha256=yQ65U-OBtsw1dhYhEn9a59RisHiIegaLHDI3Ak3OMXY,1396
30
30
  llm_bridge/logic/chat_generate/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
31
  llm_bridge/logic/chat_generate/chat_client_factory.py,sha256=g34iodMfCqopsPu2aDYp9hsEBY2ap7I_io620y1wy-Q,4385
32
32
  llm_bridge/logic/chat_generate/chat_message_converter.py,sha256=40VTBOPXg_ocrEZMdt1ObYlm-mhRL35zWzzxv8m2xRc,1538
@@ -40,12 +40,12 @@ llm_bridge/logic/chat_generate/model_message_converter/__init__.py,sha256=47DEQp
40
40
  llm_bridge/logic/chat_generate/model_message_converter/claude_message_converter.py,sha256=YiPqMkybCXrsAJOFcUfPOHXdMkn3mZxq7gft_W449dA,2439
41
41
  llm_bridge/logic/chat_generate/model_message_converter/gemini_message_converter.py,sha256=m6IeeQ_-yKcyBwLcEO_1HOoQAXDR5nl0mz_DNSsjieo,1529
42
42
  llm_bridge/logic/chat_generate/model_message_converter/openai_message_converter.py,sha256=lmc-lUVZ_LgHcJZVB-l989TgrB4FtbCyGlRDp4eXycE,2179
43
- llm_bridge/logic/chat_generate/model_message_converter/openai_responses_message_converter.py,sha256=R1cl0rhkbG_PditrVGqrP_CiDi_KsmibqciVgPbuFxc,2977
43
+ llm_bridge/logic/chat_generate/model_message_converter/openai_responses_message_converter.py,sha256=kJt5wwcte5xsqQLsysfYeH5iGtawiKt6EGHUsVq9ZOk,3011
44
44
  llm_bridge/logic/message_preprocess/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
45
45
  llm_bridge/logic/message_preprocess/code_file_extensions.py,sha256=5bsnSKC9PGbl6ZMy80sXfagAbz77pGjt6Z2-qwzUw48,9306
46
46
  llm_bridge/logic/message_preprocess/document_processor.py,sha256=IsVqoFgWNa9i8cRsDAfmCynJMdlvBqiCKIT9kbx96kg,2861
47
- llm_bridge/logic/message_preprocess/file_type_checker.py,sha256=nkrVki1a2udCeVqUnfIVi7Wxx8OMKbBuHw3FOlm17uo,1603
48
- llm_bridge/logic/message_preprocess/message_preprocessor.py,sha256=VR4__ip4ytAo62DHn9HeeYdbcx5lWItBnKsm9l3gmY4,1924
47
+ llm_bridge/logic/message_preprocess/file_type_checker.py,sha256=k4q9KGdaOV_TFDmZLeiBYBhRD8QeY4bqtaXZGbk_bzM,1733
48
+ llm_bridge/logic/message_preprocess/message_preprocessor.py,sha256=ECKHF6BHsucs7QZ8b4WgPDX9vKseziHSK7jaIBB9NgM,1979
49
49
  llm_bridge/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
50
  llm_bridge/resources/model_prices.json,sha256=dgjdMXcm0JxTZgcfVsJ8dbYnwtVmMBu84aUkp4sDyGw,2674
51
51
  llm_bridge/type/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -57,7 +57,7 @@ llm_bridge/type/model_message/claude_message.py,sha256=gYJUTbLUeifQMva3Axarc-VFe
57
57
  llm_bridge/type/model_message/gemini_message.py,sha256=mh8pf929g7_NkBzSOwnLXyrwSzTT4yt2FmyX7NZn0sM,4302
58
58
  llm_bridge/type/model_message/openai_message.py,sha256=xFaLY-cZoSwNd7E9BSWQjBNcRfCVH11X9s2yxXlctR0,453
59
59
  llm_bridge/type/model_message/openai_responses_message.py,sha256=be1q2euA0ybjj4NO6NxOGIRB9eJuXSb4ssUm_bM4Ocs,1529
60
- llm_bridge-1.15.4.dist-info/METADATA,sha256=POcmJhTZdAmKvBSDqiPD_7lpy5JViq-_4CPLtqYtd2I,3417
61
- llm_bridge-1.15.4.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
62
- llm_bridge-1.15.4.dist-info/licenses/LICENSE,sha256=m6uon-6P_CaiqcBfApMfjG9YRtDxcr40Z52JcqUCEAE,1069
63
- llm_bridge-1.15.4.dist-info/RECORD,,
60
+ llm_bridge-1.15.7.dist-info/METADATA,sha256=WZX8QphxFPKqevUGltMA97_nUryJzRGp0_ho9aoOGVw,3314
61
+ llm_bridge-1.15.7.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
62
+ llm_bridge-1.15.7.dist-info/licenses/LICENSE,sha256=m6uon-6P_CaiqcBfApMfjG9YRtDxcr40Z52JcqUCEAE,1069
63
+ llm_bridge-1.15.7.dist-info/RECORD,,