Spaces:
Paused
Paused
| from typing import List, Dict, Optional | |
| import pandas as pd | |
| import os | |
| from pathlib import Path | |
| import logging | |
| from datetime import datetime | |
| import matplotlib.pyplot as plt | |
| from docx import Document | |
| from docx.shared import Inches, Pt | |
| from docx.enum.text import WD_ALIGN_PARAGRAPH | |
| import xlsxwriter | |
| class ReportGenerator: | |
| """ | |
| Generator raport贸w ko艅cowych z analizy ofert przetargowych. | |
| """ | |
| def __init__(self, output_dir: str = "output"): | |
| self.output_dir = Path(output_dir) | |
| self.output_dir.mkdir(exist_ok=True) | |
| self.logger = logging.getLogger(__name__) | |
| async def generate_excel_report( | |
| self, | |
| analyses: Dict[str, 'OfferAnalysis'], | |
| criteria: List['EvaluationCriterion'] | |
| ) -> pd.DataFrame: | |
| """ | |
| Generuje raport Excel z wynikami oceny. | |
| Args: | |
| analyses: S艂ownik z analizami ofert | |
| criteria: Lista kryteri贸w oceny | |
| Returns: | |
| pd.DataFrame: DataFrame z wynikami | |
| """ | |
| try: | |
| # Przygotuj dane do DataFrame | |
| data = [] | |
| for criterion in criteria: | |
| row = { | |
| 'Kryterium': criterion.name, | |
| 'Waga': f"{criterion.weight}%" | |
| } | |
| # Dodaj oceny dla ka偶dej oferty | |
| for offer_id, analysis in analyses.items(): | |
| eval = next(e for e in analysis.evaluations | |
| if e.criterion_name == criterion.name) | |
| row[f"{offer_id}_score"] = eval.score | |
| row[f"{offer_id}_justification"] = eval.justification | |
| data.append(row) | |
| # Utw贸rz DataFrame | |
| df = pd.DataFrame(data) | |
| # Zapisz do Excel z formatowaniem | |
| timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") | |
| excel_path = self.output_dir / f"wyniki_oceny_{timestamp}.xlsx" | |
| with pd.ExcelWriter(excel_path, engine='xlsxwriter') as writer: | |
| df.to_excel(writer, sheet_name='Oceny', index=False) | |
| # Dodaj formatowanie | |
| workbook = writer.book | |
| worksheet = writer.sheets['Oceny'] | |
| # Formaty | |
| header_format = workbook.add_format({ | |
| 'bold': True, | |
| 'bg_color': '#4F81BD', | |
| 'font_color': 'white' | |
| }) | |
| score_format = workbook.add_format({ | |
| 'num_format': '0.00', | |
| 'align': 'center' | |
| }) | |
| # Zastosuj formaty | |
| for col_num, value in enumerate(df.columns.values): | |
| worksheet.write(0, col_num, value, header_format) | |
| # Dostosuj szeroko艣ci kolumn | |
| worksheet.set_column('A:A', 30) # Kryterium | |
| worksheet.set_column('B:B', 10) # Waga | |
| for i in range(2, len(df.columns), 2): | |
| worksheet.set_column(i, i, 15) # Ocena | |
| worksheet.set_column(i+1, i+1, 50) # Uzasadnienie | |
| self.logger.info(f"Wygenerowano raport Excel: {excel_path}") | |
| return df | |
| except Exception as e: | |
| self.logger.error(f"B艂膮d podczas generowania raportu Excel: {str(e)}") | |
| raise | |
| async def generate_word_report( | |
| self, | |
| analyses: Dict[str, 'OfferAnalysis'], | |
| criteria: List['EvaluationCriterion'], | |
| comparison_results: Dict | |
| ) -> str: | |
| """ | |
| Generuje szczeg贸艂owy raport Word z analiz膮 ofert. | |
| Args: | |
| analyses: S艂ownik z analizami ofert | |
| criteria: Lista kryteri贸w oceny | |
| comparison_results: Wyniki por贸wnania ofert | |
| Returns: | |
| str: Markdown z raportem | |
| """ | |
| try: | |
| # Generuj raport w formacie Markdown | |
| report_lines = [] | |
| # 1. Nag艂贸wek | |
| report_lines.append("# Raport z Oceny Ofert Przetargowych") | |
| report_lines.append(f"Data utworzenia: {datetime.now().strftime('%d.%m.%Y')}") | |
| report_lines.append(f"Liczba ocenionych ofert: {len(analyses)}") | |
| # 2. Podsumowanie wykonawcze | |
| report_lines.append("\n## Podsumowanie wykonawcze") | |
| # Tabela z kluczowymi wynikami | |
| report_lines.append("\n| Oferent | Wynik ko艅cowy | Ranking |") | |
| report_lines.append("|----------|---------------|---------|") | |
| # Posortuj oferty wg wyniku | |
| sorted_offers = sorted( | |
| analyses.items(), | |
| key=lambda x: x[1].total_score, | |
| reverse=True | |
| ) | |
| for i, (offer_id, analysis) in enumerate(sorted_offers, 1): | |
| report_lines.append( | |
| f"| {offer_id} | {analysis.total_score:.2f} | {i} |" | |
| ) | |
| # 3. Szczeg贸艂owa analiza ofert | |
| for offer_id, analysis in analyses.items(): | |
| report_lines.append(f"\n## Analiza oferty: {offer_id}") | |
| report_lines.append(f"Wynik ko艅cowy: {analysis.total_score:.2f}/100 punkt贸w") | |
| report_lines.append("\n### Mocne strony:") | |
| for strength in analysis.strengths: | |
| report_lines.append(f"* {strength}") | |
| report_lines.append("\n### S艂abe strony:") | |
| for weakness in analysis.weaknesses: | |
| report_lines.append(f"* {weakness}") | |
| report_lines.append("\n### Szczeg贸艂owe oceny:") | |
| report_lines.append("\n| Kryterium | Ocena | Uzasadnienie |") | |
| report_lines.append("|-----------|--------|--------------|") | |
| for eval in analysis.evaluations: | |
| report_lines.append( | |
| f"| {eval.criterion_name} | {eval.score:.2f} | {eval.justification} |" | |
| ) | |
| # 4. Por贸wnanie ofert | |
| report_lines.append("\n## Por贸wnanie ofert") | |
| report_lines.append(str(comparison_results)) | |
| report = "\n".join(report_lines) | |
| self.logger.info("Wygenerowano raport Word w formacie Markdown") | |
| return report | |
| except Exception as e: | |
| self.logger.error(f"B艂膮d podczas generowania raportu Word: {str(e)}") | |
| raise | |
| def _generate_bar_plot(self, analyses: Dict[str, 'OfferAnalysis']) -> str: | |
| """ | |
| Generuje wykres s艂upkowy por贸wnuj膮cy wyniki ko艅cowe. | |
| Args: | |
| analyses: S艂ownik z analizami ofert | |
| Returns: | |
| str: 艢cie偶ka do zapisanego wykresu | |
| """ | |
| try: | |
| # Przygotuj dane | |
| offer_ids = list(analyses.keys()) | |
| scores = [analysis.total_score for analysis in analyses.values()] | |
| # Utw贸rz wykres | |
| plt.figure(figsize=(10, 6)) | |
| plt.bar(offer_ids, scores) | |
| # Dodaj etykiety | |
| plt.title('Por贸wnanie wynik贸w ko艅cowych') | |
| plt.xlabel('Oferenci') | |
| plt.ylabel('Wynik ko艅cowy') | |
| plt.xticks(rotation=45) | |
| # Dodaj warto艣ci nad s艂upkami | |
| for i, score in enumerate(scores): | |
| plt.text(i, score, f'{score:.1f}', ha='center', va='bottom') | |
| # Zapisz wykres | |
| plot_path = self.output_dir / 'wyniki_koncowe.png' | |
| plt.savefig(plot_path, bbox_inches='tight') | |
| plt.close() | |
| return str(plot_path) | |
| except Exception as e: | |
| self.logger.error(f"B艂膮d podczas generowania wykresu: {str(e)}") | |
| return "" |