Marek4321 commited on
Commit
68c99be
verified
1 Parent(s): bf9df0b

Update deepseek_client.py

Browse files
Files changed (1) hide show
  1. deepseek_client.py +9 -220
deepseek_client.py CHANGED
@@ -91,224 +91,13 @@ class DeepSeekClient:
91
  'response_format': {"type": "json_object"}
92
  }
93
 
94
- async with self.client as client:
95
- self.logger.debug(f"Wysy艂anie zapytania do API (pr贸ba {retries + 1}/{max_retries})")
96
- response = await client.post(
97
- '/v1/chat/completions',
98
- json=request_data
99
- )
100
- response.raise_for_status()
101
- response_data = response.json()
102
-
103
- # Sprawd藕 struktur臋 odpowiedzi
104
- if 'choices' not in response_data or not response_data['choices']:
105
- raise ValueError("Nieprawid艂owa struktura odpowiedzi: brak choices")
106
-
107
- choice = response_data['choices'][0]
108
- if 'message' not in choice or 'content' not in choice['message']:
109
- raise ValueError("Nieprawid艂owa struktura odpowiedzi: brak message/content")
110
-
111
- content = choice['message']['content']
112
-
113
- # Pr贸ba parsowania JSON
114
- try:
115
- parsed_content = json.loads(content)
116
- return parsed_content
117
- except json.JSONDecodeError as e:
118
- self.logger.error(f"Nie uda艂o si臋 sparsowa膰 odpowiedzi jako JSON: {content}")
119
- raise ValueError(f"Odpowied藕 nie jest prawid艂owym JSON: {str(e)}")
120
-
121
- except (httpx.HTTPError, ValueError) as e:
122
- last_error = e
123
- retries += 1
124
-
125
- if retries < max_retries:
126
- # Exponential backoff z jitterem
127
- wait_time = retry_delay * (2 ** (retries - 1)) * (0.5 + random.random())
128
- self.logger.warning(
129
- f"Pr贸ba {retries} nie powiod艂a si臋: {str(e)}. "
130
- f"Czekam {wait_time:.2f}s przed ponowieniem..."
131
- )
132
- await asyncio.sleep(wait_time)
133
- continue
134
-
135
- self.logger.error(f"Wszystkie {max_retries} pr贸b nie powiod艂y si臋")
136
- break
137
-
138
- raise last_error
139
-
140
- async def analyze_criteria(self, brief_content: str) -> List[Dict]:
141
- """
142
- Analizuje brief/SIWZ w poszukiwaniu kryteri贸w oceny.
143
-
144
- Args:
145
- brief_content: Tre艣膰 dokumentu do analizy
146
-
147
- Returns:
148
- List[Dict]: Lista wyodr臋bnionych kryteri贸w
149
-
150
- Raises:
151
- ValueError: Gdy nie uda艂o si臋 wyodr臋bni膰 kryteri贸w
152
- """
153
- prompt = """
154
- Przeanalizuj poni偶szy dokument przetargowy i zidentyfikuj kryteria oceny ofert.
155
- Zwr贸膰 odpowied藕 dok艂adnie w poni偶szym formacie JSON (wa偶ne: odpowied藕 musi by膰 poprawnym JSON):
156
-
157
- {
158
- "criteria": [
159
- {
160
- "name": "nazwa kryterium",
161
- "weight": liczba,
162
- "description": "opis",
163
- "scoring_guide": "wskaz贸wki do oceny"
164
- }
165
- ]
166
- }
167
-
168
- Upewnij si臋, 偶e:
169
- - Suma wag wszystkich kryteri贸w wynosi dok艂adnie 100%
170
- - Ka偶de kryterium ma unikaln膮 nazw臋
171
- - Opisy s膮 konkretne i jednoznaczne
172
- - Format JSON jest 艣ci艣le zachowany
173
- """
174
-
175
- try:
176
- response = await self.analyze_text(prompt, brief_content)
177
-
178
- if not isinstance(response, dict) or 'criteria' not in response:
179
- raise ValueError("Nieprawid艂owa struktura odpowiedzi od modelu")
180
-
181
- criteria = response['criteria']
182
- await self._validate_criteria(criteria)
183
- return criteria
184
-
185
- except Exception as e:
186
- self.logger.error(f"B艂膮d podczas parsowania kryteri贸w: {str(e)}")
187
- raise
188
-
189
- async def analyze_offer(
190
- self,
191
- offer_content: str,
192
- criteria: List[Dict],
193
- brief_content: str
194
- ) -> Dict:
195
- """
196
- Analizuje ofert臋 wzgl臋dem zadanych kryteri贸w.
197
-
198
- Args:
199
- offer_content: Tre艣膰 oferty do analizy
200
- criteria: Lista kryteri贸w oceny
201
- brief_content: Tre艣膰 briefu/SIWZ
202
-
203
- Returns:
204
- Dict: Analiza oferty z ocenami i uzasadnieniami
205
-
206
- Raises:
207
- ValueError: Gdy nie uda艂o si臋 przeanalizowa膰 oferty
208
- """
209
- prompt = f"""
210
- Oce艅 poni偶sz膮 ofert臋 wzgl臋dem kryteri贸w. Zwr贸膰 odpowied藕 dok艂adnie w poni偶szym formacie JSON:
211
-
212
- {{
213
- "evaluations": [
214
- {{
215
- "criterion_name": "nazwa kryterium",
216
- "score": liczba 0-100,
217
- "justification": "szczeg贸艂owe uzasadnienie",
218
- "key_points": ["g艂贸wny punkt 1", "g艂贸wny punkt 2"],
219
- "evidence": ["cytat/referencja 1", "cytat/referencja 2"]
220
- }}
221
- ],
222
- "strengths": ["mocna strona 1", "mocna strona 2"],
223
- "weaknesses": ["s艂aba strona 1", "s艂aba strona 2"],
224
- "summary": "kr贸tkie podsumowanie oceny",
225
- "recommendations": ["rekomendacja 1", "rekomendacja 2"]
226
- }}
227
-
228
- Kryteria oceny:
229
- {json.dumps(criteria, indent=2, ensure_ascii=False)}
230
-
231
- Kontekst z briefu/SIWZ:
232
- {brief_content[:1000]}...
233
- """
234
-
235
- response = await self.analyze_text(prompt, offer_content)
236
- try:
237
- await self._validate_analysis(response)
238
- return response
239
- except Exception as e:
240
- self.logger.error(f"B艂膮d podczas parsowania analizy oferty: {str(e)}")
241
- raise
242
-
243
- async def _validate_criteria(self, criteria: List[Dict]) -> None:
244
- """
245
- Waliduje wyodr臋bnione kryteria.
246
-
247
- Args:
248
- criteria: Lista kryteri贸w do walidacji
249
-
250
- Raises:
251
- ValueError: Gdy kryteria nie spe艂niaj膮 wymaga艅
252
- """
253
- if not criteria:
254
- raise ValueError("Nie znaleziono 偶adnych kryteri贸w")
255
-
256
- # Sprawd藕 sum臋 wag
257
- total_weight = sum(c['weight'] for c in criteria)
258
- if abs(total_weight - 100) > 0.01:
259
- self.logger.warning(
260
- f"Suma wag kryteri贸w ({total_weight}%) r贸偶ni si臋 od 100%"
261
- )
262
-
263
- # Sprawd藕 unikalno艣膰 nazw
264
- names = [c['name'] for c in criteria]
265
- if len(names) != len(set(names)):
266
- raise ValueError("Znaleziono duplikaty w nazwach kryteri贸w")
267
-
268
- # Sprawd藕 wymagane pola
269
- required_fields = {'name', 'weight', 'description'}
270
- for criterion in criteria:
271
- missing_fields = required_fields - set(criterion.keys())
272
- if missing_fields:
273
- raise ValueError(f"Brakuj膮ce pola w kryterium: {missing_fields}")
274
-
275
- async def _validate_analysis(self, analysis: Dict) -> None:
276
- """
277
- Waliduje analiz臋 oferty.
278
-
279
- Args:
280
- analysis: Analiza do walidacji
281
-
282
- Raises:
283
- ValueError: Gdy analiza nie spe艂nia wymaga艅
284
- """
285
- required_fields = {
286
- 'evaluations', 'strengths', 'weaknesses',
287
- 'summary', 'recommendations'
288
- }
289
-
290
- missing_fields = required_fields - set(analysis.keys())
291
- if missing_fields:
292
- raise ValueError(f"Brakuj膮ce pola w analizie: {missing_fields}")
293
-
294
- if not analysis['evaluations']:
295
- raise ValueError("Brak ocen w analizie")
296
-
297
- for eval in analysis['evaluations']:
298
- if not (0 <= eval['score'] <= 100):
299
- raise ValueError(
300
- f"Nieprawid艂owa ocena: {eval['score']} "
301
- f"dla kryterium {eval['criterion_name']}"
302
  )
303
-
304
- async def close(self):
305
- """Zamyka klienta HTTP"""
306
- await self.client.aclose()
307
-
308
- async def __aenter__(self):
309
- """Context manager entry"""
310
- return self
311
-
312
- async def __aexit__(self, exc_type, exc_val, exc_tb):
313
- """Context manager exit"""
314
- await self.close()
 
91
  'response_format': {"type": "json_object"}
92
  }
93
 
94
+ self.logger.debug(f"Wysy艂anie zapytania do API (pr贸ba {retries + 1}/{max_retries})")
95
+ response = await self.client.post( # U偶yj self.client bez otwierania nowego kontekstu
96
+ '/v1/chat/completions',
97
+ json=request_data
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  )
99
+ response.raise_for_status()
100
+ response_data = response.json()
101
+
102
+ # Sprawd藕 struktur臋 odpowiedzi
103
+ if 'choices' not in response