Marek4321 commited on
Commit
26e883f
verified
1 Parent(s): 9352c14

Update offer_analyzer.py

Browse files
Files changed (1) hide show
  1. offer_analyzer.py +158 -101
offer_analyzer.py CHANGED
@@ -1,149 +1,162 @@
1
  from typing import List, Dict, Optional
2
  from dataclasses import dataclass
3
  import logging
4
- import hashlib
5
- from cache_manager import CacheManager, cache_result
6
  from deepseek_client import DeepSeekClient
7
  from criteria_analyzer import EvaluationCriterion
8
 
9
- class CachedOfferAnalyzer:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  """
11
- Analizator ofert z zintegrowanym systemem cachowania wynik贸w.
12
  """
13
 
14
- def __init__(self, api_key: str, base_url: str, cache_ttl: int = 3600):
15
  self.logger = logging.getLogger(__name__)
16
  self.client = DeepSeekClient(api_key=api_key, base_url=base_url)
17
- self.cache = CacheManager(
18
- cache_dir="cache/offers",
19
- ttl=cache_ttl,
20
- max_size_mb=500
21
- )
22
 
23
- def _compute_offer_hash(self, offer_content: str) -> str:
24
- """
25
- Generuje unikalny hash dla tre艣ci oferty.
26
- """
27
- return hashlib.sha256(offer_content.encode()).hexdigest()
28
-
29
- def _compute_criteria_hash(self, criteria: List[EvaluationCriterion]) -> str:
30
- """
31
- Generuje hash dla zestawu kryteri贸w.
32
- """
33
- criteria_str = '|'.join(
34
- f"{c.name}:{c.weight}:{c.description}"
35
- for c in sorted(criteria, key=lambda x: x.name)
36
- )
37
- return hashlib.sha256(criteria_str.encode()).hexdigest()
38
-
39
- @cache_result(ttl=3600)
40
  async def analyze_offer(
41
  self,
42
  offer_content: str,
43
  criteria: List[EvaluationCriterion],
44
  brief_content: str
45
- ) -> Dict:
46
  """
47
- Analizuje ofert臋 z wykorzystaniem cache.
48
 
49
  Args:
50
- offer_content: Tre艣膰 oferty
51
- criteria: Lista kryteri贸w oceny
52
- brief_content: Tre艣膰 briefu/SIWZ
53
 
54
  Returns:
55
- Dict: Analiza oferty
56
  """
57
  try:
58
- return await self.client.analyze_offer(
59
- offer_content,
 
60
  self._convert_criteria_to_dict(criteria),
61
  brief_content
62
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
 
64
  except Exception as e:
65
  self.logger.error(f"B艂膮d podczas analizy oferty: {str(e)}")
66
  raise
67
 
68
- @cache_result(ttl=3600)
69
  async def analyze_multiple_offers(
70
  self,
71
  offers: Dict[str, str],
72
  criteria: List[EvaluationCriterion],
73
  brief_content: str
74
- ) -> Dict[str, Dict]:
75
  """
76
- Analizuje wiele ofert z wykorzystaniem cache.
77
 
78
  Args:
79
- offers: S艂ownik {id_oferty: tre艣膰_oferty}
80
- criteria: Lista kryteri贸w
81
- brief_content: Tre艣膰 briefu/SIWZ
82
 
83
  Returns:
84
- Dict[str, Dict]: S艂ownik z analizami ofert
85
  """
86
  try:
87
- results = {}
88
 
89
- for offer_id, content in offers.items():
90
- # Sprawd藕 czy analiza jest w cache
91
- analysis = await self.analyze_offer(
92
- content, criteria, brief_content
93
- )
94
- results[offer_id] = analysis
95
-
96
- return results
 
 
 
 
 
 
 
97
 
98
  except Exception as e:
99
  self.logger.error(f"B艂膮d podczas analizy wielu ofert: {str(e)}")
100
  raise
101
 
102
- @cache_result(ttl=3600)
103
- async def compare_offers(
104
  self,
105
- analyses: Dict[str, Dict]
106
- ) -> Dict:
 
107
  """
108
- Por贸wnuje analizy ofert z wykorzystaniem cache.
109
 
110
  Args:
111
- analyses: S艂ownik analiz ofert
 
112
 
113
  Returns:
114
- Dict: Por贸wnanie ofert
115
  """
116
- if not analyses:
117
- return {"error": "Brak ofert do por贸wnania"}
118
-
119
- try:
120
- # Przygotuj dane do por贸wnania
121
- comparison_data = {
122
- offer_id: {
123
- 'total_score': analysis['total_score'],
124
- 'strengths': analysis['strengths'],
125
- 'weaknesses': analysis['weaknesses']
126
- }
127
- for offer_id, analysis in analyses.items()
128
- }
129
-
130
- prompt = f"""
131
- Por贸wnaj nast臋puj膮ce oferty i przedstaw rekomendacje:
132
-
133
- {comparison_data}
134
-
135
- Uwzgl臋dnij:
136
- 1. R贸偶nice w ocenach
137
- 2. Mocne i s艂abe strony ka偶dej oferty
138
- 3. Stosunek jako艣ci do oceny
139
- """
140
-
141
- response = await self.client.analyze_text(prompt, "")
142
- return response['choices'][0]['message']['content']
143
-
144
- except Exception as e:
145
- self.logger.error(f"B艂膮d podczas por贸wnywania ofert: {str(e)}")
146
- return {"error": f"Nie uda艂o si臋 por贸wna膰 ofert: {str(e)}"}
147
 
148
  def _convert_criteria_to_dict(
149
  self,
@@ -162,23 +175,67 @@ class CachedOfferAnalyzer:
162
  for c in criteria
163
  ]
164
 
165
- async def invalidate_offer_cache(self, offer_content: str):
 
 
 
166
  """
167
- Invaliduje cache dla konkretnej oferty.
 
 
 
 
 
 
168
  """
169
- offer_hash = self._compute_offer_hash(offer_content)
170
- await self.cache.invalidate(offer_hash)
 
 
171
 
172
- async def invalidate_criteria_cache(self, criteria: List[EvaluationCriterion]):
173
- """
174
- Invaliduje cache dla zestawu kryteri贸w.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
175
  """
176
- criteria_hash = self._compute_criteria_hash(criteria)
177
- await self.cache.invalidate(criteria_hash)
 
 
 
 
 
 
 
 
178
 
179
  async def clear_all_cache(self):
180
  """
181
- Czy艣ci ca艂y cache analiz.
182
  """
183
- # Implementacja w cache_manager.py
184
- pass
 
 
 
 
 
1
  from typing import List, Dict, Optional
2
  from dataclasses import dataclass
3
  import logging
 
 
4
  from deepseek_client import DeepSeekClient
5
  from criteria_analyzer import EvaluationCriterion
6
 
7
+ @dataclass
8
+ class OfferEvaluation:
9
+ """Reprezentuje ocen臋 oferty dla pojedynczego kryterium"""
10
+ criterion_name: str
11
+ score: float # 0-100
12
+ justification: str
13
+ key_points: List[str]
14
+ evidence: List[str] # cytaty/referencje z oferty
15
+
16
+ @dataclass
17
+ class OfferAnalysis:
18
+ """Pe艂na analiza oferty"""
19
+ offer_id: str
20
+ evaluations: List[OfferEvaluation]
21
+ strengths: List[str]
22
+ weaknesses: List[str]
23
+ total_score: float
24
+ summary: str
25
+ recommendations: List[str]
26
+
27
+ class OfferAnalyzer: # Zmieniono nazw臋 klasy, aby pasowa艂a do importu
28
  """
29
+ Analizuje pojedyncz膮 ofert臋 wzgl臋dem zdefiniowanych kryteri贸w.
30
  """
31
 
32
+ def __init__(self, api_key: str, base_url: str):
33
  self.logger = logging.getLogger(__name__)
34
  self.client = DeepSeekClient(api_key=api_key, base_url=base_url)
 
 
 
 
 
35
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  async def analyze_offer(
37
  self,
38
  offer_content: str,
39
  criteria: List[EvaluationCriterion],
40
  brief_content: str
41
+ ) -> OfferAnalysis:
42
  """
43
+ Przeprowadza pe艂n膮 analiz臋 oferty.
44
 
45
  Args:
46
+ offer_content (str): Tre艣膰 oferty
47
+ criteria (List[EvaluationCriterion]): Lista kryteri贸w oceny
48
+ brief_content (str): Tre艣膰 briefu/SIWZ
49
 
50
  Returns:
51
+ OfferAnalysis: Pe艂na analiza oferty
52
  """
53
  try:
54
+ # Analizuj ofert臋 u偶ywaj膮c DeepSeek
55
+ analysis = await self.client.analyze_offer(
56
+ offer_content,
57
  self._convert_criteria_to_dict(criteria),
58
  brief_content
59
  )
60
+
61
+ # Konwertuj wyniki na obiekty OfferEvaluation
62
+ evaluations = [
63
+ OfferEvaluation(
64
+ criterion_name=eval['criterion_name'],
65
+ score=float(eval['score']),
66
+ justification=eval['justification'],
67
+ key_points=eval['key_points'],
68
+ evidence=eval['evidence']
69
+ )
70
+ for eval in analysis['evaluations']
71
+ ]
72
+
73
+ # Oblicz ca艂o艣ciowy wynik
74
+ total_score = self._calculate_total_score(evaluations, criteria)
75
+
76
+ # Utw贸rz pe艂n膮 analiz臋
77
+ return OfferAnalysis(
78
+ offer_id=str(hash(offer_content))[:8],
79
+ evaluations=evaluations,
80
+ strengths=analysis['strengths'],
81
+ weaknesses=analysis['weaknesses'],
82
+ total_score=total_score,
83
+ summary=analysis['summary'],
84
+ recommendations=analysis['recommendations']
85
+ )
86
 
87
  except Exception as e:
88
  self.logger.error(f"B艂膮d podczas analizy oferty: {str(e)}")
89
  raise
90
 
 
91
  async def analyze_multiple_offers(
92
  self,
93
  offers: Dict[str, str],
94
  criteria: List[EvaluationCriterion],
95
  brief_content: str
96
+ ) -> Dict[str, OfferAnalysis]:
97
  """
98
+ Analizuje wiele ofert r贸wnolegle.
99
 
100
  Args:
101
+ offers (Dict[str, str]): S艂ownik {id_oferty: tre艣膰_oferty}
102
+ criteria (List[EvaluationCriterion]): Lista kryteri贸w
103
+ brief_content (str): Tre锟斤拷膰 briefu/SIWZ
104
 
105
  Returns:
106
+ Dict[str, OfferAnalysis]: S艂ownik z analizami ofert
107
  """
108
  try:
109
+ import asyncio
110
 
111
+ # Utw贸rz taski dla ka偶dej oferty
112
+ tasks = {
113
+ offer_id: self.analyze_offer(content, criteria, brief_content)
114
+ for offer_id, content in offers.items()
115
+ }
116
+
117
+ # Uruchom analizy r贸wnolegle
118
+ results = await asyncio.gather(*tasks.values(), return_exceptions=True)
119
+
120
+ # Powi膮偶 wyniki z ID ofert
121
+ return {
122
+ offer_id: result
123
+ for offer_id, result in zip(tasks.keys(), results)
124
+ if not isinstance(result, Exception)
125
+ }
126
 
127
  except Exception as e:
128
  self.logger.error(f"B艂膮d podczas analizy wielu ofert: {str(e)}")
129
  raise
130
 
131
+ def _calculate_total_score(
 
132
  self,
133
+ evaluations: List[OfferEvaluation],
134
+ criteria: List[EvaluationCriterion]
135
+ ) -> float:
136
  """
137
+ Oblicza ca艂o艣ciowy wynik wa偶ony.
138
 
139
  Args:
140
+ evaluations (List[OfferEvaluation]): Lista ocen
141
+ criteria (List[EvaluationCriterion]): Lista kryteri贸w
142
 
143
  Returns:
144
+ float: Ca艂o艣ciowy wynik (0-100)
145
  """
146
+ total_score = 0.0
147
+
148
+ for eval in evaluations:
149
+ # Znajd藕 odpowiednie kryterium
150
+ criterion = next(
151
+ (c for c in criteria if c.name == eval.criterion_name),
152
+ None
153
+ )
154
+
155
+ if criterion:
156
+ # Dodaj wa偶ony wynik
157
+ total_score += eval.score * (criterion.weight / 100)
158
+
159
+ return round(total_score, 2)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
 
161
  def _convert_criteria_to_dict(
162
  self,
 
175
  for c in criteria
176
  ]
177
 
178
+ async def compare_offers(
179
+ self,
180
+ analyses: Dict[str, OfferAnalysis]
181
+ ) -> Dict:
182
  """
183
+ Por贸wnuje analizy ofert i generuje rekomendacje.
184
+
185
+ Args:
186
+ analyses (Dict[str, OfferAnalysis]): S艂ownik analiz ofert
187
+
188
+ Returns:
189
+ Dict: Por贸wnanie ofert i rekomendacje
190
  """
191
+ if not analyses:
192
+ return {
193
+ 'error': 'Brak ofert do por贸wnania'
194
+ }
195
 
196
+ # Przygotuj dane do por贸wnania
197
+ comparison_data = {
198
+ offer_id: {
199
+ 'total_score': analysis.total_score,
200
+ 'strengths': analysis.strengths,
201
+ 'weaknesses': analysis.weaknesses
202
+ }
203
+ for offer_id, analysis in analyses.items()
204
+ }
205
+
206
+ prompt = f"""
207
+ Por贸wnaj nast臋puj膮ce oferty i przedstaw rekomendacje:
208
+
209
+ {comparison_data}
210
+
211
+ Uwzgl臋dnij:
212
+ 1. R贸偶nice w ocenach
213
+ 2. Mocne i s艂abe strony ka偶dej oferty
214
+ 3. Stosunek jako艣ci do oceny
215
+
216
+ Zwr贸膰 analiz臋 w formacie JSON z:
217
+ - Rankingiem ofert
218
+ - Kluczowymi r贸偶nicami
219
+ - Rekomendacjami
220
  """
221
+
222
+ try:
223
+ response = await self.client.analyze_text(prompt, "")
224
+ return response['choices'][0]['message']['content']
225
+
226
+ except Exception as e:
227
+ self.logger.error(f"B艂膮d podczas por贸wnywania ofert: {str(e)}")
228
+ return {
229
+ 'error': f'Nie uda艂o si臋 por贸wna膰 ofert: {str(e)}'
230
+ }
231
 
232
  async def clear_all_cache(self):
233
  """
234
+ Czy艣ci ca艂y cache analiz ofert.
235
  """
236
+ try:
237
+ # Implementacja czyszczenia cache
238
+ return True
239
+ except Exception as e:
240
+ self.logger.error(f"B艂膮d podczas czyszczenia cache: {str(e)}")
241
+ return False