@@ -29,7 +29,9 @@ def get_client() -> OpenAI:
2929embedding_cache : Dict [Tuple [str , str ], np .ndarray ] = {}
3030
3131
32- def get_embedding_with_cache (text : str , embedding_dim : int , llm_config : Optional [Any ] = None ) -> Optional [np .ndarray ]:
32+ def get_embedding_with_cache (
33+ text : str , embedding_dim : int , llm_config : Optional [Any ] = None
34+ ) -> Optional [np .ndarray ]:
3335 """Gets an embedding for a single text string, using a cache to avoid repeat API calls."""
3436 # Use direct attribute access on the Pydantic model
3537 model_name = llm_config .embedding_model if llm_config else "text-embedding-ada-002"
@@ -50,14 +52,18 @@ class EmbeddingValidationError(Exception):
5052 """Raised when embedding validation fails."""
5153
5254
53- def validate_embedding (embedding : Any , expected_dim : int , name : str = "embedding" ) -> bool :
55+ def validate_embedding (
56+ embedding : Any , expected_dim : int , name : str = "embedding"
57+ ) -> bool :
5458 """Validate embedding dimensions and properties."""
5559 if embedding is None :
5660 raise EmbeddingValidationError (f"{ name } is None" )
5761 if not isinstance (embedding , np .ndarray ):
5862 raise EmbeddingValidationError (f"{ name } is not a numpy array" )
5963 if embedding .shape [0 ] != expected_dim :
60- raise EmbeddingValidationError (f"{ name } dimension mismatch: got { embedding .shape [0 ]} , expected { expected_dim } " )
64+ raise EmbeddingValidationError (
65+ f"{ name } dimension mismatch: got { embedding .shape [0 ]} , expected { expected_dim } "
66+ )
6167 if np .any (np .isnan (embedding )):
6268 raise EmbeddingValidationError (f"{ name } contains NaN values" )
6369 if np .any (np .isinf (embedding )):
@@ -78,7 +84,9 @@ def get_embedding_from_llm(
7884 try :
7985 response = client .embeddings .create (input = text , model = model_name )
8086 embedding = np .array (response .data [0 ].embedding ).astype (np .float32 )
81- validate_embedding (embedding , expected_embedding_dim , f"embedding for '{ text [:50 ]} ...'" )
87+ validate_embedding (
88+ embedding , expected_embedding_dim , f"embedding for '{ text [:50 ]} ...'"
89+ )
8290 return embedding
8391 except EmbeddingValidationError :
8492 raise
@@ -87,7 +95,9 @@ def get_embedding_from_llm(
8795 return None
8896
8997
90- def get_embeddings_from_llm_batch (texts : List [str ], llm_config : Optional [Any ] = None ) -> Optional [List [np .ndarray ]]:
98+ def get_embeddings_from_llm_batch (
99+ texts : List [str ], llm_config : Optional [Any ] = None
100+ ) -> Optional [List [np .ndarray ]]:
91101 """Gets embeddings for a list of texts in a single, efficient API call."""
92102 if not texts :
93103 return []
@@ -104,15 +114,19 @@ def get_embeddings_from_llm_batch(texts: List[str], llm_config: Optional[Any] =
104114 return None
105115
106116
107- def query_llm (prompt_text : str , llm_config : Optional [Any ] = None ) -> tuple [str , int , float ]:
117+ def query_llm (
118+ prompt_text : str , llm_config : Optional [Any ] = None
119+ ) -> tuple [str , int , float ]:
108120 """Queries the LLM, returning the response, token usage, and estimated cost."""
109121 client = get_client ()
110122
111123 # Use direct attribute access on the Pydantic model, providing defaults if it's None
112124 model_name = llm_config .completion_model if llm_config else "gpt-4.1-nano"
113125 temp = llm_config .temperature if llm_config else 0.1
114126 max_tok = llm_config .max_tokens if llm_config else 700
115- prompt_prefix = llm_config .reflection_prompt_prefix if llm_config else "In 300 words or less, "
127+ prompt_prefix = (
128+ llm_config .reflection_prompt_prefix if llm_config else "In 300 words or less, "
129+ )
116130
117131 pricing = {
118132 "gpt-4o-mini" : {"prompt" : 0.15 / 1_000_000 , "completion" : 0.60 / 1_000_000 },
@@ -129,15 +143,21 @@ def query_llm(prompt_text: str, llm_config: Optional[Any] = None) -> tuple[str,
129143 )
130144
131145 response_text = ""
132- if response .choices and response .choices [0 ].message and response .choices [0 ].message .content :
146+ if (
147+ response .choices
148+ and response .choices [0 ].message
149+ and response .choices [0 ].message .content
150+ ):
133151 response_text = response .choices [0 ].message .content .strip ()
134152
135153 usage = response .usage
136154 if usage :
137155 prompt_tokens = usage .prompt_tokens
138156 completion_tokens = usage .completion_tokens
139157 total_tokens = usage .total_tokens
140- cost = (prompt_tokens * model_pricing ["prompt" ]) + (completion_tokens * model_pricing ["completion" ])
158+ cost = (prompt_tokens * model_pricing ["prompt" ]) + (
159+ completion_tokens * model_pricing ["completion" ]
160+ )
141161 return response_text , total_tokens , cost
142162 else :
143163 return response_text , 0 , 0.0
0 commit comments