Spaces:
Sleeping
Sleeping
File size: 12,990 Bytes
908acb6 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 |
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) |