yoshizen commited on
Commit
dd0280b
·
verified ·
1 Parent(s): 0d4c845

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +232 -151
app.py CHANGED
@@ -2,13 +2,19 @@ import re
2
  import requests
3
  import pandas as pd
4
  import torch
5
- from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
 
 
 
6
  import json
 
 
 
 
 
7
  import logging
8
  import time
9
  import sys
10
- import os
11
- from functools import lru_cache
12
 
13
  # Настройка логирования
14
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
@@ -16,192 +22,267 @@ logger = logging.getLogger("GAIA-Mastermind")
16
 
17
  # Конфигурация
18
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
19
- MODEL_NAME = "google/flan-t5-base" # Используем меньшую модель для быстрой загрузки
20
  API_RETRIES = 3
21
- API_TIMEOUT = 30
22
 
23
- # Настройка кэширования моделей
24
- os.environ["TRANSFORMERS_CACHE"] = "/tmp/transformers_cache"
25
- os.environ["HF_HOME"] = "/tmp/hf_home"
26
-
27
- class GAIAExpert:
28
- _instance = None
29
- _is_initialized = False
30
-
31
- def __new__(cls):
32
- # Паттерн Singleton для предотвращения повторной загрузки модели
33
- if cls._instance is None:
34
- cls._instance = super(GAIAExpert, cls).__new__(cls)
35
- return cls._instance
36
-
37
  def __init__(self):
38
- # Инициализируем только один раз
39
- if not GAIAExpert._is_initialized:
40
- self.device = "cuda" if torch.cuda.is_available() else "cpu"
41
- logger.info(f"Инициализация модели на {self.device.upper()}")
42
-
43
- # Отложенная инициализация - токенизатор загружаем сразу, модель - по требованию
44
  self.tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
45
- self.model = None
46
- GAIAExpert._is_initialized = True
47
-
48
- def _ensure_model_loaded(self):
49
- """Ленивая загрузка модели только при необходимости"""
50
- if self.model is None:
51
- try:
52
- logger.info("Загрузка модели...")
53
- # Оптимизированная загрузка модели
54
- self.model = AutoModelForSeq2SeqLM.from_pretrained(
55
- MODEL_NAME,
56
- torch_dtype=torch.float16 if self.device == "cuda" else torch.float32,
57
- low_cpu_mem_usage=True,
58
- device_map="auto" # Автоматическое распределение на доступные устройства
59
- ).eval()
60
- logger.info("Модель успешно загружена")
61
- except Exception as e:
62
- logger.exception("Ошибка загрузки модели")
63
- raise RuntimeError(f"Ошибка инициализации: {str(e)}")
 
64
 
65
- @lru_cache(maxsize=100) # Кэширование ответов для повторяющихся вопросов
66
- def process_question(self, question: str) -> str:
67
- """Обработка вопроса с оптимизацией и кэшированием"""
68
  try:
69
- # Загружаем модель только при первом вызове
70
- self._ensure_model_loaded()
71
 
72
- # Оптимизированная обработка токенов
73
- inputs = self.tokenizer(
74
- f"Вопрос: {question}\nОтвет:",
75
- return_tensors="pt",
76
- max_length=256,
77
- truncation=True,
78
- padding="max_length"
79
  )
80
 
81
- # Перемещаем тензоры на нужное устройство
82
- if self.device == "cuda":
83
- inputs = {k: v.to(self.device) for k, v in inputs.items()}
84
 
85
- # Оптимизированная генерация
86
- with torch.no_grad(): # Отключаем вычисление градиентов для экономии памяти
87
- outputs = self.model.generate(
88
- **inputs,
89
- max_new_tokens=50,
90
- num_beams=1, # Ускорение генерации
91
- early_stopping=True,
92
- do_sample=False # Детерминированная генерация для скорости
93
- )
94
-
95
- answer = self.tokenizer.decode(outputs[0], skip_special_tokens=True)
96
- return json.dumps({"final_answer": answer.strip()})
97
  except Exception as e:
98
- return json.dumps({"final_answer": f"ERROR: {str(e)}"})
 
 
 
 
 
99
 
100
- class GAIAEvaluator:
 
101
  def __init__(self, api_url: str = DEFAULT_API_URL):
102
  self.api_url = api_url
103
  self.questions_url = f"{api_url}/questions"
104
  self.submit_url = f"{api_url}/submit"
105
  self.session = requests.Session()
106
- self.session.headers.update({"Content-Type": "application/json"})
107
- # Настройка повторных попыток и таймаутов
108
- self.session.mount('https://', requests.adapters.HTTPAdapter(max_retries=API_RETRIES))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
 
110
- def run_evaluation(self, username: str, agent_code: str):
111
- """Консольный процесс оценки без интерфейса"""
112
- # Создаем агента только при необходимости
113
- agent = GAIAExpert()
 
 
 
114
 
115
- # Получение вопросов с повторными попытками
116
- questions = self._fetch_questions_with_retry()
117
- if not isinstance(questions, list):
118
- logger.error(f"Ошибка получения вопросов: {questions}")
119
- return 0, 0
120
 
121
  # Обработка вопросов
 
122
  answers = []
123
 
124
  for i, q in enumerate(questions):
125
- task_id = q.get("task_id", f"task_{i}")
126
- logger.info(f"Обработка задачи {i+1}/{len(questions)}: {q['question'][:50]}...")
127
-
128
  try:
129
- json_response = agent.process_question(q["question"])
130
- response_obj = json.loads(json_response)
131
- answer = response_obj.get("final_answer", "")
 
 
 
 
 
 
 
 
132
 
133
  answers.append({
134
  "task_id": task_id,
135
- "answer": str(answer)[:300]
 
 
 
 
 
 
 
136
  })
137
  except Exception as e:
138
- logger.error(f"Ошибка обработки: {str(e)}")
139
  answers.append({
140
  "task_id": task_id,
141
  "answer": f"ERROR: {str(e)}"
142
  })
 
 
 
 
 
 
143
 
144
- # Отправка ответов с повторными попытками
145
- return self._submit_answers_with_retry(username, agent_code, answers)
146
-
147
- def _fetch_questions_with_retry(self, max_retries=3):
148
- """Получение вопросов с API с повторными попытками"""
149
- for attempt in range(max_retries):
150
- try:
151
- response = self.session.get(self.questions_url, timeout=API_TIMEOUT)
152
- if response.status_code == 200:
153
- return response.json()
154
- logger.warning(f"HTTP error {response.status_code}, попытка {attempt+1}/{max_retries}")
155
- time.sleep(2 ** attempt) # Экспоненциальная задержка между попытками
156
- except Exception as e:
157
- logger.warning(f"Connection error: {str(e)}, попытка {attempt+1}/{max_retries}")
158
- time.sleep(2 ** attempt)
159
- return f"Failed after {max_retries} attempts"
160
 
161
- def _submit_answers_with_retry(self, username: str, agent_code: str, answers: list, max_retries=3):
162
- """Отправка ответов на сервер с повторными попытками"""
163
- for attempt in range(max_retries):
164
- try:
165
- payload = {
166
- "username": username.strip(),
167
- "agent_code": agent_code.strip(),
168
- "answers": answers
169
- }
170
-
171
- response = self.session.post(
172
- self.submit_url,
173
- json=payload,
174
- timeout=API_TIMEOUT * 2
175
- )
176
-
177
- if response.status_code == 200:
178
- result = response.json()
179
- score = result.get("score", 0)
180
- return score, len(answers)
181
-
182
- logger.warning(f"HTTP error {response.status_code}, попытка {attempt+1}/{max_retries}")
183
- time.sleep(2 ** attempt)
184
- except Exception as e:
185
- logger.error(f"Ошибка отправки: {str(e)}, попытка {attempt+1}/{max_retries}")
186
- time.sleep(2 ** attempt)
187
- return 0, len(answers)
188
 
189
- if __name__ == "__main__":
190
- # Параметры запуска
191
- USERNAME = "yoshizen"
192
- AGENT_CODE = "https://huggingface.co/spaces/yoshizen/FinalTest"
193
 
194
- logger.info(f"Запуск оценки для {USERNAME}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
195
 
196
- start_time = time.time()
197
- evaluator = GAIAEvaluator()
198
- score, total = evaluator.run_evaluation(USERNAME, AGENT_CODE)
 
199
 
200
- elapsed = time.time() - start_time
201
- logger.info(f"Оценка завершена за {elapsed:.1f} сек")
202
- logger.info(f"Результат: {score}/{total} правильных ответов")
203
 
204
- if total > 0:
205
- logger.info(f"Точность: {score/total*100:.1f}%")
206
- else:
207
- logger.error("Не удалось обработать ни одного вопроса")
 
 
 
 
 
 
 
 
 
 
 
2
  import requests
3
  import pandas as pd
4
  import torch
5
+ import gradio as gr
6
+ from tqdm import tqdm
7
+ from transformers import AutoTokenizer, AutoModelForSeq2SeqLM, pipeline
8
+ from typing import List, Dict, Any, Tuple, Optional
9
  import json
10
+ import ast
11
+ import numpy as np
12
+ from PIL import Image, UnidentifiedImageError
13
+ import io
14
+ import base64
15
  import logging
16
  import time
17
  import sys
 
 
18
 
19
  # Настройка логирования
20
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
 
22
 
23
  # Конфигурация
24
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
25
+ MODEL_NAME = "google/flan-t5-large" # Оптимизировано для CPU
26
  API_RETRIES = 3
27
+ API_TIMEOUT = 45
28
 
29
+ # === ЯДРО СИСТЕМЫ ===
30
+ class GAIAThoughtProcessor:
 
 
 
 
 
 
 
 
 
 
 
 
31
  def __init__(self):
32
+ self.device = "cuda" if torch.cuda.is_available() else "cpu"
33
+ logger.info(f"⚡ Инициализация GAIAThoughtProcessor на {self.device.upper()}")
34
+
35
+ try:
36
+ # Оптимизированная загрузка модели для CPU
 
37
  self.tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
38
+ self.model = AutoModelForSeq2SeqLM.from_pretrained(
39
+ MODEL_NAME,
40
+ device_map="auto" if torch.cuda.is_available() else None,
41
+ torch_dtype=torch.float32,
42
+ low_cpu_mem_usage=True
43
+ ).eval()
44
+
45
+ # Создаем пайплайн для генерации текста
46
+ self.text_generator = pipeline(
47
+ "text2text-generation",
48
+ model=self.model,
49
+ tokenizer=self.tokenizer,
50
+ device=-1 if self.device == "cpu" else 0,
51
+ max_new_tokens=128
52
+ )
53
+
54
+ logger.info("✅ GAIAThoughtProcessor готов")
55
+ except Exception as e:
56
+ logger.exception("Ошибка инициализации модели")
57
+ raise RuntimeError(f"Ошибка инициализации: {str(e)}")
58
 
59
+ def process_question(self, question: str, task_id: str) -> str:
60
+ """Упрощенная обработка вопроса"""
 
61
  try:
62
+ prompt = f"Реши задачу шаг за шагом: {question}\n\nФинальный ответ:"
 
63
 
64
+ result = self.text_generator(
65
+ prompt,
66
+ max_new_tokens=128,
67
+ num_beams=2,
68
+ early_stopping=True,
69
+ temperature=0.1
 
70
  )
71
 
72
+ response = result[0]['generated_text'].strip()
 
 
73
 
74
+ # Создаем JSON ответ
75
+ return json.dumps({"final_answer": response})
76
+
 
 
 
 
 
 
 
 
 
77
  except Exception as e:
78
+ logger.error(f"Ошибка обработки вопроса: {str(e)}")
79
+ return json.dumps({
80
+ "task_id": task_id,
81
+ "error": str(e),
82
+ "final_answer": f"ERROR: {str(e)}"
83
+ })
84
 
85
+ # === СИСТЕМА ОЦЕНКИ ===
86
+ class GAIAEvaluationRunner:
87
  def __init__(self, api_url: str = DEFAULT_API_URL):
88
  self.api_url = api_url
89
  self.questions_url = f"{api_url}/questions"
90
  self.submit_url = f"{api_url}/submit"
91
  self.session = requests.Session()
92
+ self.session.headers.update({
93
+ "Accept": "application/json",
94
+ "User-Agent": "GAIA-Mastermind/1.0",
95
+ "Content-Type": "application/json"
96
+ })
97
+ logger.info(f"🌐 Инициализирован GAIAEvaluationRunner для {api_url}")
98
+
99
+ def _fetch_questions(self) -> Tuple[list, str]:
100
+ """Получение вопросов с API"""
101
+ logger.info(f"🔍 Запрос вопросов с {self.questions_url}")
102
+ try:
103
+ response = self.session.get(
104
+ self.questions_url,
105
+ timeout=API_TIMEOUT
106
+ )
107
+
108
+ logger.info(f"Статус ответа: {response.status_code}")
109
+
110
+ if response.status_code == 200:
111
+ questions = response.json()
112
+ logger.info(f"Получено {len(questions)} вопросов")
113
+ return questions, "success"
114
+ else:
115
+ error_msg = f"Ошибка API: HTTP {response.status_code}"
116
+ logger.error(error_msg)
117
+ return [], error_msg
118
+
119
+ except Exception as e:
120
+ error_msg = f"Ошибка соединения: {str(e)}"
121
+ logger.exception(error_msg)
122
+ return [], error_msg
123
+
124
+ def _submit_answers(self, username: str, agent_code: str, answers: list) -> Tuple[str, int]:
125
+ """Отправка ответов на сервер"""
126
+ logger.info(f"📤 Отправка ответов для пользователя {username}")
127
+ try:
128
+ payload = {
129
+ "username": username.strip(),
130
+ "agent_code": agent_code.strip(),
131
+ "answers": answers
132
+ }
133
+
134
+ response = self.session.post(
135
+ self.submit_url,
136
+ json=payload,
137
+ timeout=API_TIMEOUT * 2
138
+ )
139
+
140
+ logger.info(f"Статус отправки: {response.status_code}")
141
+
142
+ if response.status_code == 200:
143
+ result = response.json()
144
+ score = result.get("score", 0)
145
+ return result.get("message", "Ответы успешно отправлены"), score
146
+ else:
147
+ error = f"HTTP Ошибка {response.status_code}"
148
+ if response.text:
149
+ error += f": {response.text[:200]}"
150
+ logger.error(error)
151
+ return error, 0
152
+
153
+ except Exception as e:
154
+ error = f"Ошибка отправки: {str(e)}"
155
+ logger.exception(error)
156
+ return error, 0
157
 
158
+ def run_evaluation(self, agent, username: str, agent_code: str, progress=gr.Progress()):
159
+ """Основной процесс оценки"""
160
+ # Получение вопросов
161
+ progress(0.1, desc="Получение вопросов")
162
+ questions, status = self._fetch_questions()
163
+ if status != "success":
164
+ return status, 0, 0, pd.DataFrame()
165
 
166
+ total_questions = len(questions)
167
+ if total_questions == 0:
168
+ return "Получено 0 вопросов", 0, 0, pd.DataFrame()
 
 
169
 
170
  # Обработка вопросов
171
+ results = []
172
  answers = []
173
 
174
  for i, q in enumerate(questions):
175
+ progress(i / total_questions, desc=f"Обработка задачи {i+1}/{total_questions}")
 
 
176
  try:
177
+ task_id = q.get("task_id", f"task_{i}")
178
+ logger.info(f"🔧 Обработка задачи {task_id}")
179
+
180
+ json_response = agent.process_question(q["question"], task_id)
181
+
182
+ # Парсинг ответа
183
+ try:
184
+ response_obj = json.loads(json_response)
185
+ final_answer = response_obj.get("final_answer", "")
186
+ except:
187
+ final_answer = json_response
188
 
189
  answers.append({
190
  "task_id": task_id,
191
+ "answer": str(final_answer)[:500]
192
+ })
193
+
194
+ results.append({
195
+ "Task ID": task_id,
196
+ "Question": q["question"][:50] + "..." if len(q["question"]) > 50 else q["question"],
197
+ "Answer": str(final_answer)[:50] + "..." if len(str(final_answer)) > 50 else str(final_answer),
198
+ "Status": "Processed"
199
  })
200
  except Exception as e:
201
+ logger.error(f"Ошибка обработки задачи: {str(e)}")
202
  answers.append({
203
  "task_id": task_id,
204
  "answer": f"ERROR: {str(e)}"
205
  })
206
+ results.append({
207
+ "Task ID": task_id,
208
+ "Question": "Error",
209
+ "Answer": f"ERROR: {str(e)}",
210
+ "Status": "Failed"
211
+ })
212
 
213
+ # Отправка ответов
214
+ progress(0.9, desc="Отправка результатов")
215
+ submission_result, score = self._submit_answers(username, agent_code, answers)
216
+ return submission_result, score, total_questions, pd.DataFrame(results)
 
 
 
 
 
 
 
 
 
 
 
 
217
 
218
+ # === ИНТЕРФЕЙС GRADIO ===
219
+ def run_evaluation(username: str, agent_code: str, progress=gr.Progress()):
220
+ try:
221
+ progress(0, desc="Инициализация агента")
222
+ agent = GAIAThoughtProcessor()
223
+
224
+ progress(0.1, desc="Подключение к API")
225
+ runner = GAIAEvaluationRunner()
226
+
227
+ # Запуск оценки
228
+ return runner.run_evaluation(agent, username, agent_code, progress)
229
+
230
+ except Exception as e:
231
+ logger.exception("Критическая ошибка в run_evaluation")
232
+ error_df = pd.DataFrame([{
233
+ "Task ID": "ERROR",
234
+ "Question": f"Критическая ошибка: {str(e)}",
235
+ "Answer": "См. логи",
236
+ "Status": "Failed"
237
+ }])
238
+ return f"Ошибка: {str(e)}", 0, 0, error_df
 
 
 
 
 
 
239
 
240
+ # Создание интерфейса
241
+ with gr.Blocks(title="GAIA Mastermind") as demo:
242
+ gr.Markdown("# GAIA Mastermind")
243
+ gr.Markdown("Многошаговое решение задач с декомпозицией")
244
 
245
+ with gr.Row():
246
+ with gr.Column():
247
+ gr.Markdown("## 🔐 Авторизация")
248
+ username = gr.Textbox(label="HF Username", value="yoshizen")
249
+ agent_code = gr.Textbox(label="Agent Code", value="https://huggingface.co/spaces/yoshizen/FinalTest")
250
+ run_btn = gr.Button("Запустить оценку")
251
+
252
+ gr.Markdown("## ⚙️ Статус системы")
253
+ sys_info = gr.Textbox(label="Системная информация", interactive=False)
254
+
255
+ with gr.Column():
256
+ gr.Markdown("## 📊 Результаты GAIA")
257
+ with gr.Row():
258
+ result_output = gr.Textbox(label="Статус отправки", interactive=False)
259
+ correct_output = gr.Number(label="Правильные ответы", interactive=False)
260
+ total_output = gr.Number(label="Всего вопросов", interactive=False)
261
+
262
+ results_table = gr.Dataframe(
263
+ label="Детализация ответов",
264
+ headers=["Task ID", "Question", "Answer", "Status"],
265
+ interactive=False
266
+ )
267
 
268
+ # Системная информация
269
+ def get_system_info():
270
+ device = "GPU" if torch.cuda.is_available() else "CPU"
271
+ return f"Device: {device} | Model: {MODEL_NAME} | API: {DEFAULT_API_URL}"
272
 
273
+ demo.load(get_system_info, inputs=None, outputs=sys_info)
 
 
274
 
275
+ run_btn.click(
276
+ fn=run_evaluation,
277
+ inputs=[username, agent_code],
278
+ outputs=[result_output, correct_output, total_output, results_table],
279
+ concurrency_limit=1
280
+ )
281
+
282
+ if __name__ == "__main__":
283
+ demo.queue(max_size=1).launch(
284
+ server_name="0.0.0.0",
285
+ server_port=7860,
286
+ share=False,
287
+ show_error=True
288
+ )