enotkrutoy commited on
Commit
22cc7c7
·
verified ·
1 Parent(s): 3df88a1

Update g1.py

Browse files
Files changed (1) hide show
  1. g1.py +114 -121
g1.py CHANGED
@@ -4,58 +4,69 @@ import logging
4
  from typing import List, Tuple, Generator, Optional, Any
5
  import groq
6
 
7
- # Константы
8
- DEFAULT_MAX_TOKENS = 2000
9
- FINAL_MAX_TOKENS = 1000
10
- RETRY_DELAY = 1
 
11
  MAX_RETRIES = 3
12
- DEFAULT_MODEL = "llama3-8b-8192"
13
 
14
  logging.basicConfig(level=logging.INFO)
15
  logger = logging.getLogger(__name__)
16
 
17
  class APIError(Exception):
18
- """Кастомное исключение для ошибок API"""
19
  pass
20
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  def parse_json_response(raw_response: str) -> dict:
22
- """Улучшенный парсер с валидацией структуры и обработкой Unicode"""
23
- logger.debug("Parsing JSON response: %s", raw_response[:200])
24
-
25
  try:
26
- parsed = json.loads(raw_response)
27
- except json.JSONDecodeError as e:
28
- logger.error("JSON decode error: %s", e)
29
- raise ValueError(f"Invalid JSON: {e}")
30
-
31
- required = {"title", "content", "next_action"}
32
- if missing := required - parsed.keys():
33
- raise ValueError(f"Missing keys: {missing}")
34
-
35
- if parsed["next_action"] not in {"continue", "final_answer"}:
36
- raise ValueError("Invalid next_action value")
37
-
38
- return parsed
39
 
40
  def make_api_call(
41
  messages: List[dict],
42
  max_tokens: int,
43
  is_final_answer: bool = False,
44
  custom_client: Optional[Any] = None,
45
- model: str = DEFAULT_MODEL
 
46
  ) -> Any:
47
- """Унифицированный метод вызова API с улучшенной обработкой ошибок"""
48
  client = custom_client or groq.Client()
 
 
49
 
50
  params = {
51
  "model": model,
52
  "messages": messages,
53
  "max_tokens": max_tokens,
54
  "temperature": 0.5,
 
55
  }
56
-
57
- if not is_final_answer:
58
- params["response_format"] = {"type": "json_object"}
59
 
60
  for attempt in range(1, MAX_RETRIES + 1):
61
  try:
@@ -63,128 +74,110 @@ def make_api_call(
63
  content = response.choices[0].message.content
64
 
65
  if response.choices[0].finish_reason == "length":
66
- logger.warning("Response truncated! Consider increasing max_tokens")
67
-
68
  return content if is_final_answer else parse_json_response(content)
69
-
70
  except groq.APIConnectionError as e:
71
- logger.error("Connection error: %s. Attempt %d/%d", e, attempt, MAX_RETRIES)
72
  if attempt == MAX_RETRIES:
73
- raise APIError("Failed to connect to API after multiple attempts")
74
- time.sleep(RETRY_DELAY * attempt)
75
-
76
  except groq.APIError as e:
77
- logger.error("API error [%s]: %s", e.status_code, e.message)
78
  if e.status_code >= 500:
79
  time.sleep(RETRY_DELAY * attempt)
80
  else:
81
- raise APIError(f"API Error: {e.message}")
82
-
83
- except ValueError as e:
84
- logger.error("Parsing error: %s. Attempt %d/%d", e, attempt, MAX_RETRIES)
85
- if attempt == MAX_RETRIES:
86
- raise APIError("Failed to parse response after multiple attempts")
87
- time.sleep(RETRY_DELAY * attempt)
88
 
89
  def generate_response(
90
  prompt: str,
91
  context: Optional[str] = None,
92
  custom_client: Optional[Any] = None,
93
- max_steps: int = 25,
94
- model: str = DEFAULT_MODEL
 
95
  ) -> Generator[Tuple[List[Tuple[str, str, float]], Optional[float]], None, None]:
96
- """Улучшенная генерация ответа с валидацией ввода"""
97
- # Валидация входных параметров
98
- if not prompt.strip():
99
- raise ValueError("Prompt cannot be empty")
100
- if max_steps < 1:
101
- raise ValueError("max_steps must be at least 1")
102
-
103
- system_template = (
104
- "Вы – эксперт по Python. Анализируйте вопрос по шагам:\n"
105
- "1. Разбейте вопрос на под-вопросы\n"
106
- "2. Для каждого сгенерируйте 2-3 варианта рассуждений\n"
107
- "3. Оцените варианты по критериям ясности и релевантности\n"
108
- "4. Выберите оптимальную цепочку\n"
109
- "Формат ответа: JSON с ключами title, content, next_action"
110
  )
111
 
112
- user_content = f"Context: {context}\n\nQuestion: {prompt}" if context else prompt
113
  messages = [
114
- {"role": "system", "content": system_template},
115
- {"role": "user", "content": user_content}
116
  ]
117
-
118
  steps = []
119
  total_time = 0.0
120
- step_count = 1
121
-
122
- while step_count <= max_steps:
123
- start = time.monotonic()
124
-
125
- try:
126
- response = make_api_call(
127
- messages=messages,
128
- max_tokens=DEFAULT_MAX_TOKENS,
129
- is_final_answer=False,
130
- custom_client=custom_client,
131
- model=model
132
- )
133
- except APIError as e:
134
- logger.error("Critical error in step %d: %s", step_count, e)
135
- steps.append(("Error", str(e), time.monotonic() - start))
136
- break
137
-
138
- elapsed = time.monotonic() - start
139
- total_time += elapsed
140
-
141
- step_entry = (
142
- f"Step {step_count}: {response['title']}",
143
- response["content"],
144
- elapsed
145
- )
146
- steps.append(step_entry)
147
- messages.append({"role": "assistant", "content": json.dumps(response, ensure_ascii=False)})
148
-
149
- if response["next_action"] == "final_answer" or step_count == max_steps:
150
- break
151
-
152
- step_count += 1
153
- yield steps, None
154
-
155
- # Финализация ответа
156
- messages.append({
157
- "role": "user",
158
- "content": "Сформируй окончательный ответ с детальным объяснением и примерами кода, если необходимо."
159
- })
160
-
161
  try:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
  final_answer = make_api_call(
163
  messages=messages,
164
- max_tokens=FINAL_MAX_TOKENS,
165
  is_final_answer=True,
166
  custom_client=custom_client,
167
- model=model
168
  )
169
- except APIError as e:
170
- final_answer = f"Error generating final answer: {str(e)}"
171
-
172
- final_time = time.monotonic() - start
173
- total_time += final_time
174
- steps.append(("Final Answer", final_answer, final_time))
175
-
 
176
  yield steps, total_time
177
 
178
  if __name__ == "__main__":
179
- context = "https://console.groq.com/docs/autogen"
180
- prompt = "учитывай контекст autogen в ответ"
181
-
182
  try:
183
- for steps, total_time in generate_response(prompt, context):
 
 
 
 
 
184
  if total_time is not None:
185
- print(f"\nОбщее время обработки: {total_time:.2f} секунд")
186
- print("="*50)
187
  for title, content, t in steps:
188
- print(f"\n{title} ({t:.2f}s)\n{content}")
189
- except Exception as e:
190
- print(f"Critical error: {str(e)}")
 
 
 
 
4
  from typing import List, Tuple, Generator, Optional, Any
5
  import groq
6
 
7
+ # Конфигурация
8
+ DEFAULT_ITER_MODEL = "llama3-70b-8192"
9
+ DEFAULT_FINAL_MODEL = "mixtral-8x7b-32768"
10
+ MAX_TOKENS_LIMIT = 8192
11
+ RETRY_DELAY = 1.5
12
  MAX_RETRIES = 3
 
13
 
14
  logging.basicConfig(level=logging.INFO)
15
  logger = logging.getLogger(__name__)
16
 
17
  class APIError(Exception):
18
+ """Базовое исключение для API ошибок"""
19
  pass
20
 
21
+ class APIConnectionError(APIError):
22
+ """Ошибка подключения к API"""
23
+ pass
24
+
25
+ def adjust_max_tokens(model: str, max_tokens: int) -> int:
26
+ """Автоматическая корректировка max_tokens в зависимости от модели"""
27
+ model_limits = {
28
+ "llama3-8b-8192": 8192,
29
+ "llama3-70b-8192": 8192,
30
+ "mixtral-8x7b-32768": 32768
31
+ }
32
+ return min(max_tokens, model_limits.get(model, 4096))
33
+
34
  def parse_json_response(raw_response: str) -> dict:
35
+ """Улучшенный парсер с полной валидацией"""
 
 
36
  try:
37
+ data = json.loads(raw_response)
38
+ assert isinstance(data, dict), "Ответ должен быть объектом"
39
+ assert all(k in data for k in ["title", "content", "next_action"]), "Отсутствуют обязательные ключи"
40
+ assert data["next_action"] in {"continue", "final_answer"}, "Некорректное действие"
41
+ return data
42
+ except (json.JSONDecodeError, AssertionError) as e:
43
+ logger.error(f"Ошибка парсинга: {str(e)}")
44
+ return {
45
+ "title": "Ошибка парсинга",
46
+ "content": str(e),
47
+ "next_action": "final_answer"
48
+ }
 
49
 
50
  def make_api_call(
51
  messages: List[dict],
52
  max_tokens: int,
53
  is_final_answer: bool = False,
54
  custom_client: Optional[Any] = None,
55
+ iter_model: str = DEFAULT_ITER_MODEL,
56
+ final_model: str = DEFAULT_FINAL_MODEL
57
  ) -> Any:
58
+ """Улучшенный метод вызова API"""
59
  client = custom_client or groq.Client()
60
+ model = final_model if is_final_answer else iter_model
61
+ max_tokens = adjust_max_tokens(model, max_tokens)
62
 
63
  params = {
64
  "model": model,
65
  "messages": messages,
66
  "max_tokens": max_tokens,
67
  "temperature": 0.5,
68
+ "response_format": {"type": "json_object"} if not is_final_answer else None
69
  }
 
 
 
70
 
71
  for attempt in range(1, MAX_RETRIES + 1):
72
  try:
 
74
  content = response.choices[0].message.content
75
 
76
  if response.choices[0].finish_reason == "length":
77
+ logger.warning(f"Ответ обрезан! Рекомендуемый max_tokens: {max_tokens * 2}")
78
+
79
  return content if is_final_answer else parse_json_response(content)
80
+
81
  except groq.APIConnectionError as e:
82
+ logger.error(f"Сетевая ошибка (попытка {attempt}/{MAX_RETRIES}): {str(e)}")
83
  if attempt == MAX_RETRIES:
84
+ raise APIConnectionError(str(e))
85
+ time.sleep(RETRY_DELAY * (2 ** attempt))
86
+
87
  except groq.APIError as e:
88
+ logger.error(f"Ошибка API (код {e.status_code}): {e.message}")
89
  if e.status_code >= 500:
90
  time.sleep(RETRY_DELAY * attempt)
91
  else:
92
+ raise APIError(e.message)
 
 
 
 
 
 
93
 
94
  def generate_response(
95
  prompt: str,
96
  context: Optional[str] = None,
97
  custom_client: Optional[Any] = None,
98
+ max_steps: int = 10,
99
+ iter_model: str = DEFAULT_ITER_MODEL,
100
+ final_model: str = DEFAULT_FINAL_MODEL
101
  ) -> Generator[Tuple[List[Tuple[str, str, float]], Optional[float]], None, None]:
102
+ """Улучшенная генерация ответа"""
103
+ system_prompt = (
104
+ "Вы AI-ассистент для анализа технических вопросов. "
105
+ "Формат ответа: JSON с ключами title, content, next_action. "
106
+ "Используйте русский язык и технические термины."
 
 
 
 
 
 
 
 
 
107
  )
108
 
 
109
  messages = [
110
+ {"role": "system", "content": system_prompt},
111
+ {"role": "user", "content": f"Контекст: {context}\n\nВопрос: {prompt}" if context else prompt}
112
  ]
113
+
114
  steps = []
115
  total_time = 0.0
116
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
  try:
118
+ for step in range(1, max_steps + 1):
119
+ start = time.monotonic()
120
+
121
+ try:
122
+ response = make_api_call(
123
+ messages=messages,
124
+ max_tokens=MAX_TOKENS_LIMIT,
125
+ is_final_answer=False,
126
+ custom_client=custom_client,
127
+ iter_model=iter_model
128
+ )
129
+ except APIError as e:
130
+ logger.error("Критическая ошибка: %s", str(e))
131
+ yield [("Ошибка", str(e), time.monotonic() - start)], None
132
+ return
133
+
134
+ elapsed = time.monotonic() - start
135
+ total_time += elapsed
136
+
137
+ steps.append((f"Шаг {step}: {response['title']}", response["content"], elapsed))
138
+ messages.append({"role": "assistant", "content": json.dumps(response, ensure_ascii=False)})
139
+
140
+ if response["next_action"] == "final_answer":
141
+ break
142
+
143
+ yield steps, None
144
+
145
+ # Финализация
146
+ messages.append({"role": "user", "content": "Сформируйте финальный ответ с примерами кода и пояснениями."})
147
+
148
+ final_start = time.monotonic()
149
  final_answer = make_api_call(
150
  messages=messages,
151
+ max_tokens=MAX_TOKENS_LIMIT,
152
  is_final_answer=True,
153
  custom_client=custom_client,
154
+ final_model=final_model
155
  )
156
+ total_time += time.monotonic() - final_start
157
+
158
+ steps.append(("Финальный ответ", final_answer, time.monotonic() - final_start))
159
+
160
+ except Exception as e:
161
+ logger.exception("Непредвиденная ошибка:")
162
+ steps.append(("Критическая ошибка", str(e), 0.0))
163
+
164
  yield steps, total_time
165
 
166
  if __name__ == "__main__":
 
 
 
167
  try:
168
+ for steps, total_time in generate_response(
169
+ prompt="Опишите процесс обработки запросов в Groq API",
170
+ context="Используйте официальную документацию Groq",
171
+ iter_model="llama3-70b-8192",
172
+ final_model="mixtral-8x7b-32768"
173
+ ):
174
  if total_time is not None:
175
+ print(f"\n Готово за {total_time:.2f}s")
176
+ print("=" * 60)
177
  for title, content, t in steps:
178
+ print(f"\n🔹 {title} [{t:.2f}s]\n{content}")
179
+
180
+ except APIConnectionError as e:
181
+ print(f"🚨 Ошибка подключения: {str(e)}")
182
+ except APIError as e:
183
+ print(f"🚨 Ошибка API: {str(e)}")