RuSimulBench_arena / evaluate_creativity.py
MrSimple01's picture
Create evaluate_creativity.py
908acb6 verified
raw
history blame contribute delete
13 kB
import re
import time
import pandas as pd
import numpy as np
import google.generativeai as genai
from typing import Dict
class EvaluationConfig:
def __init__(self, api_key: str, model_name: str = "gemini-1.5-flash", batch_size: int = 5):
self.api_key = api_key
self.model_name = model_name
self.batch_size = batch_size
class EvaluationPrompts:
@staticmethod
def get_first_check(prompt: str, response: str) -> str:
return f"""Оцените следующий ответ по шкале от 0 до 10 с подробным обоснованием:
Оригинальный запрос: {prompt}
Ответ: {response}
Критерии оценки:
1. **Креативность**: Насколько уникален и оригинален ответ?
- 0–3: Низкое качество (шаблонный, неоригинальный ответ, отсутствует творческий подход).
- 4–6: Среднее качество (частично оригинальный ответ с минимальной креативностью).
- 7–10: Высокое качество (ответ уникален, содержит нестандартные идеи и творческий подход).
2. **Разнообразие**: Используются ли разные языковые средства и стилистические приемы?
- 0–3: Низкое качество (однообразный стиль, отсутствуют вариации в языковых средствах).
- 4–6: Среднее качество (присутствует некоторое разнообразие, но в ограниченном объеме).
- 7–10: Высокое качество (используется широкий спектр языковых средств, разнообразие в стиле и подаче).
3. **Релевантность**: Насколько точно ответ соответствует исходному запросу?
- 0–3: Низкое качество (ответ не связан или слабо соответствует запросу).
- 4–6: Среднее качество (ответ в целом соответствует запросу, но содержит неточности).
- 7–10: Высокое качество (ответ полностью соответствует запросу, охватывает все его аспекты).
Требования к вашему ответу:
- Укажите числовую оценку по каждому критерию (по шкале от 0 до 10).
- Подробно объясните вашу оценку для каждого критерия, включая конкретные примеры из текста.
- Предложите возможные улучшения для повышения качества ответа.
"""
@staticmethod
def get_second_check(prompt: str, response: str) -> str:
return f"""Оцените креативность и качество следующего ответа по шкале от 0 до 10:
Запрос: {prompt}
Ответ: {response}
Оцените по трем критериям:
1. **Креативность** (0-10): оригинальность идей и уникальность подхода
2. **Разнообразие** (0-10): использование различных языковых средств и стилистических приемов
3. **Релевантность** (0-10): соответствие ответа исходному запросу
Для каждого критерия укажите конкретную оценку по шкале от 0 до 10 и аргументируйте свое решение.
"""
@staticmethod
def get_third_check(prompt: str, response: str) -> str:
return f"""Проанализируйте следующий ответ на запрос и оцените его по трем критериям:
Запрос: {prompt}
Ответ: {response}
Критерии оценки (шкала 0-10):
1. **Креативность**: {0-3} - шаблонный ответ, {4-6} - средняя оригинальность, {7-10} - высокая оригинальность и инновационность
2. **Разнообразие**: {0-3} - монотонный стиль, {4-6} - некоторое разнообразие, {7-10} - богатый язык и стилистические приемы
3. **Релевантность**: {0-3} - не соответствует запросу, {4-6} - частично соответствует, {7-10} - полностью соответствует запросу
Выставите оценку по каждому критерию и обоснуйте свое решение. Приведите конкретные примеры из текста.
"""
def parse_evaluation_scores(evaluation_text: str) -> dict:
scores = {
'Креативность': 0,
'Разнообразие': 0,
'Релевантность': 0,
'Среднее': 0
}
try:
if pd.isna(evaluation_text):
return scores
overall_patterns = [
r'\*\*Общая оценка:\*\*\s*(\d+(?:\.\d+)?)/10',
r'Общая оценка:\s*(\d+(?:\.\d+)?)/10',
r'\*\*Общий балл:\s*(\d+(?:\.\d+)?)/10'
]
for pattern in overall_patterns:
overall_match = re.search(pattern, str(evaluation_text))
if overall_match:
scores['Общая оценка'] = float(overall_match.group(1))
break
criteria_patterns = [
r'\*\*\d+\.\s+(Креативность|Разнообразие|Релевантность)\s*\((\d+(?:\.\d+)?)/10\)',
r'\*\*(Креативность|Разнообразие|Релевантность)\s*\((\d+(?:\.\d+)?)/10\)',
r'\d+\.\s+(Креативность|Разнообразие|Релевантность)\s*\((\d+(?:\.\d+)?)/10\)',
r'\*\*(Креативность|Разнообразие|Релевантность)\*\*:\s*(\d+(?:\.\d+)?)',
r'(Креативность|Разнообразие|Релевантность):\s*(\d+(?:\.\d+)?)',
r'(Креативность|Разнообразие|Релевантность)[^\d]+(\d+(?:\.\d+)?)'
]
for pattern in criteria_patterns:
criteria_matches = re.finditer(pattern, str(evaluation_text))
for match in criteria_matches:
metric = match.group(1)
score = float(match.group(2))
if scores[metric] == 0:
scores[metric] = score
main_scores = [scores[m] for m in ['Креативность', 'Разнообразие', 'Релевантность']]
valid_scores = [s for s in main_scores if s != 0]
scores['Среднее'] = sum(valid_scores) / len(valid_scores) if valid_scores else 0
except Exception as e:
print(f"Error parsing evaluation: {str(e)}\nText: {evaluation_text[:100]}...")
return scores
def evaluate_creativity(api_key: str, df: pd.DataFrame, prompt_col: str, answer_col: str,
model_name: str = "gemini-1.5-flash", batch_size: int = 5,
progress=None) -> pd.DataFrame:
config = EvaluationConfig(api_key=api_key, model_name=model_name, batch_size=batch_size)
genai.configure(api_key=config.api_key)
model = genai.GenerativeModel(config.model_name)
evaluations = []
eval_answers = []
total_batches = (len(df) + config.batch_size - 1) // config.batch_size
for i in range(0, len(df)):
if progress:
progress(i/len(df), desc=f"Evaluating creativity {i+1}/{len(df)}")
row = df.iloc[i]
try:
evaluation_prompts = [
EvaluationPrompts.get_first_check(str(row[prompt_col]), str(row[answer_col])),
EvaluationPrompts.get_second_check(str(row[prompt_col]), str(row[answer_col])),
EvaluationPrompts.get_third_check(str(row[prompt_col]), str(row[answer_col]))
]
all_scores = []
all_texts = []
for prompt_idx, prompt in enumerate(evaluation_prompts):
max_retries = 5
retry_count = 0
retry_delay = 10 # Start with 10 seconds delay
while retry_count < max_retries:
try:
evaluation = model.generate_content(prompt)
scores = parse_evaluation_scores(evaluation.text)
all_scores.append(scores)
all_texts.append(evaluation.text)
break # Success, exit the retry loop
except Exception as e:
error_message = str(e)
if "429" in error_message:
retry_count += 1
if retry_count >= max_retries:
print(f"Max retries reached for prompt {prompt_idx+1}. Skipping.")
all_scores.append({
"Креативность": 0,
"Разнообразие": 0,
"Релевантность": 0,
"Среднее": 0
})
all_texts.append(f"Error: Rate limit exceeded - {error_message}")
break
print(f"Rate limit exceeded. Retrying in {retry_delay} seconds... (Attempt {retry_count}/{max_retries})")
time.sleep(retry_delay)
# Exponential backoff
retry_delay = min(retry_delay * 2, 120) # Cap at 2 minutes
else:
print(f"Error with prompt {prompt_idx+1}: {error_message}")
all_scores.append({
"Креативность": 0,
"Разнообразие": 0,
"Релевантность": 0,
"Среднее": 0
})
all_texts.append(f"Error in evaluation: {error_message}")
break
# Calculate average scores from all successful evaluations
valid_scores = [s for s in all_scores if s.get("Среднее", 0) > 0]
if valid_scores:
final_scores = {
"Креативность": np.mean([s.get("Креативность", 0) for s in valid_scores]),
"Разнообразие": np.mean([s.get("Разнообразие", 0) for s in valid_scores]),
"Релевантность": np.mean([s.get("Релевантность", 0) for s in valid_scores])
}
final_scores["Среднее"] = np.mean(list(final_scores.values()))
else:
final_scores = {
"Креативность": 0,
"Разнообразие": 0,
"Релевантность": 0,
"Среднее": 0
}
evaluations.append(final_scores)
eval_answers.append("\n\n".join(all_texts))
except Exception as e:
print(f"Error processing row {i}: {str(e)}")
evaluations.append({
"Креативность": 0,
"Разнообразие": 0,
"Релевантность": 0,
"Среднее": 0
})
eval_answers.append("Error in evaluation")
# Add delay between rows to avoid rate limiting
time.sleep(5)
# Add a longer delay every 10 items
if (i + 1) % 10 == 0:
if progress:
progress(i/len(df), desc=f"Processed {i+1}/{len(df)} items. Taking a break to avoid rate limits...")
time.sleep(60)
score_df = pd.DataFrame(evaluations)
result_df = df.copy()
result_df['gemini_eval_answer'] = eval_answers
return pd.concat([result_df, score_df], axis=1)