Spaces:
Paused
Paused
| from typing import List, Dict, Optional | |
| from dataclasses import dataclass | |
| import logging | |
| import hashlib | |
| from cache_manager import CacheManager, cache_result | |
| from deepseek_client import DeepSeekClient | |
| from dataclasses import dataclass, asdict | |
| from typing import Optional | |
| class EvaluationCriterion: | |
| """Reprezentuje pojedyncze kryterium oceny""" | |
| name: str | |
| weight: float | |
| description: str | |
| scoring_guide: Optional[str] = None | |
| min_score: float = 0.0 | |
| max_score: float = 100.0 | |
| def to_dict(self) -> dict: | |
| """Konwertuje obiekt na s艂ownik do serializacji""" | |
| return asdict(self) | |
| def from_dict(cls, data: dict) -> 'EvaluationCriterion': | |
| """Tworzy obiekt ze s艂ownika""" | |
| return cls(**data) | |
| class CriteriaAnalyzer: # Zmieniono nazw臋 z CachedCriteriaAnalyzer na CriteriaAnalyzer | |
| """ | |
| Analizator kryteri贸w z zintegrowanym systemem cachowania. | |
| """ | |
| def __init__(self, api_key: str, base_url: str, cache_ttl: int = 3600 * 24): | |
| self.logger = logging.getLogger(__name__) | |
| self.client = DeepSeekClient(api_key=api_key, base_url=base_url) | |
| self.cache = CacheManager( | |
| cache_dir="cache/criteria", | |
| ttl=cache_ttl, | |
| max_size_mb=100 | |
| ) | |
| async def close(self): | |
| """Zamyka klienta HTTP""" | |
| await self.client.close() | |
| async def __aenter__(self): | |
| """Context manager entry""" | |
| return self | |
| async def __aexit__(self, exc_type, exc_val, exc_tb): | |
| """Context manager exit""" | |
| await self.close() | |
| def _compute_brief_hash(self, brief_content: str) -> str: | |
| """ | |
| Generuje unikalny hash dla tre艣ci briefu/SIWZ. | |
| """ | |
| return hashlib.sha256(brief_content.encode()).hexdigest() | |
| async def extract_criteria(self, brief_content: str) -> List[EvaluationCriterion]: | |
| """ | |
| Ekstrahuje kryteria z briefu z wykorzystaniem cache. | |
| Args: | |
| brief_content: Tre艣膰 dokumentu SIWZ/brief | |
| Returns: | |
| List[EvaluationCriterion]: Lista wyodr臋bnionych kryteri贸w | |
| """ | |
| try: | |
| # U偶yj DeepSeek do analizy dokumentu | |
| criteria_data = await self.client.analyze_criteria(brief_content) | |
| # Konwertuj wyniki na obiekty EvaluationCriterion | |
| criteria = [ | |
| EvaluationCriterion( | |
| name=c['name'], | |
| weight=float(c['weight']), | |
| description=c['description'], | |
| scoring_guide=c.get('scoring_guide') | |
| ) | |
| for c in criteria_data | |
| ] | |
| # Upewnij si臋, 偶e suma wag wynosi 100% | |
| self._normalize_weights(criteria) | |
| self.logger.info(f"Wyodr臋bniono {len(criteria)} kryteri贸w") | |
| return criteria | |
| except Exception as e: | |
| self.logger.error(f"B艂膮d podczas ekstrakcji kryteri贸w: {str(e)}") | |
| raise | |
| async def create_evaluation_matrix( | |
| self, | |
| criteria: List[EvaluationCriterion], | |
| offer_ids: List[str] | |
| ) -> Dict: | |
| """ | |
| Tworzy matryc臋 ocen z wykorzystaniem cache. | |
| Args: | |
| criteria: Lista kryteri贸w oceny | |
| offer_ids: Lista identyfikator贸w ofert | |
| Returns: | |
| Dict: Matryca ocen | |
| """ | |
| try: | |
| matrix = { | |
| 'criteria': [c.name for c in criteria], | |
| 'offers': offer_ids, | |
| 'weights': [c.weight for c in criteria], | |
| 'scores': [[None for _ in offer_ids] for _ in criteria], | |
| 'descriptions': [c.description for c in criteria], | |
| 'scoring_guides': [c.scoring_guide for c in criteria] | |
| } | |
| self.logger.info(f"Utworzono matryc臋 ocen: {len(criteria)} kryteri贸w x {len(offer_ids)} ofert") | |
| return matrix | |
| except Exception as e: | |
| self.logger.error(f"B艂膮d podczas tworzenia matrycy ocen: {str(e)}") | |
| raise | |
| async def get_criteria_details( | |
| self, | |
| criterion: EvaluationCriterion | |
| ) -> Dict[str, str]: | |
| """ | |
| Generuje szczeg贸艂owe wytyczne oceny z wykorzystaniem cache. | |
| Args: | |
| criterion: Kryterium do analizy | |
| Returns: | |
| Dict[str, str]: Szczeg贸艂owe wytyczne oceny | |
| """ | |
| prompt = f""" | |
| Stw贸rz szczeg贸艂owe wytyczne oceny dla kryterium: | |
| Nazwa: {criterion.name} | |
| Waga: {criterion.weight}% | |
| Opis: {criterion.description} | |
| Okre艣l: | |
| 1. Co stanowi ocen臋 maksymaln膮 (100%) | |
| 2. Co stanowi ocen臋 艣redni膮 (50%) | |
| 3. Co stanowi ocen臋 minimaln膮 (0%) | |
| 4. Jakie elementy nale偶y wzi膮膰 pod uwag臋 | |
| 5. Na co szczeg贸lnie zwr贸ci膰 uwag臋 | |
| """ | |
| try: | |
| response = await self.client.analyze_text(prompt, "") | |
| return response['choices'][0]['message']['content'] | |
| except Exception as e: | |
| self.logger.error( | |
| f"B艂膮d podczas generowania wytycznych dla kryterium {criterion.name}: {str(e)}" | |
| ) | |
| return { | |
| "error": f"Nie uda艂o si臋 wygenerowa膰 wytycznych: {str(e)}" | |
| } | |
| def _normalize_weights(self, criteria: List[EvaluationCriterion]) -> None: | |
| """ | |
| Normalizuje wagi kryteri贸w do 100%. | |
| """ | |
| total_weight = sum(c.weight for c in criteria) | |
| if abs(total_weight - 100) > 0.01: | |
| self.logger.warning( | |
| f"Normalizacja wag kryteri贸w (suma pocz膮tkowa: {total_weight}%)" | |
| ) | |
| factor = 100 / total_weight | |
| for criterion in criteria: | |
| criterion.weight *= factor | |
| criterion.weight = round(criterion.weight, 2) | |
| total_after = sum(c.weight for c in criteria) | |
| if total_after != 100: | |
| diff = 100 - total_after | |
| criteria[0].weight += diff | |
| async def invalidate_brief_cache(self, brief_content: str): | |
| """ | |
| Invaliduje cache dla konkretnego briefu. | |
| """ | |
| brief_hash = self._compute_brief_hash(brief_content) | |
| await self.cache.invalidate(brief_hash) | |
| async def clear_criteria_cache(self): | |
| """ | |
| Czy艣ci ca艂y cache kryteri贸w. | |
| """ | |
| try: | |
| await self.cache.invalidate_all() | |
| return True | |
| except Exception as e: | |
| self.logger.error(f"B艂膮d podczas czyszczenia cache: {str(e)}") | |
| return False |