fix: упрощение работы с Qwen Code
Изменения: - Использование флага -p для передачи задачи - Простой текстовый вывод вместо stream-json - Каждый запрос запускает новый процесс qwen - Убрано сложное управление сессиями - Edit сообщения вместо новых сообщений Теперь /ai работает стабильнее Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
parent
5d451ff870
commit
cac597688d
40
bot.py
40
bot.py
|
|
@ -2687,41 +2687,33 @@ async def ai_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
return
|
return
|
||||||
|
|
||||||
# Отправляем задачу в ИИ
|
# Отправляем задачу в ИИ
|
||||||
await update.message.reply_text("⏳ 🤖 Думаю...", parse_mode="Markdown")
|
status_msg = await update.message.reply_text("⏳ 🤖 Думаю...", parse_mode="Markdown")
|
||||||
|
|
||||||
output_buffer = []
|
output_buffer = []
|
||||||
oauth_url_sent = False
|
|
||||||
|
|
||||||
def on_output(text: str):
|
def on_output(text: str):
|
||||||
output_buffer.append(text)
|
output_buffer.append(text)
|
||||||
|
|
||||||
def on_oauth_url(url: str):
|
def on_oauth_url(url: str):
|
||||||
nonlocal oauth_url_sent
|
pass # OAuth обрабатывается автоматически при первом запуске
|
||||||
if not oauth_url_sent:
|
|
||||||
oauth_url_sent = True
|
|
||||||
asyncio.create_task(update.message.reply_text(
|
|
||||||
f"🔐 *Требуется авторизация Qwen Code*\n\n"
|
|
||||||
f"Откройте ссылку для авторизации:\n"
|
|
||||||
f"{url}\n\n"
|
|
||||||
f"После авторизации отправьте команду снова.",
|
|
||||||
parse_mode="Markdown"
|
|
||||||
))
|
|
||||||
|
|
||||||
# Выполняем задачу
|
# Выполняем задачу
|
||||||
result = await qwen_manager.run_task(user_id, task, on_output, on_oauth_url)
|
result = await qwen_manager.run_task(user_id, task, on_output, on_oauth_url)
|
||||||
|
|
||||||
# Если это не OAuth — показываем результат
|
# Показываем результат
|
||||||
if not oauth_url_sent:
|
full_output = "".join(output_buffer).strip()
|
||||||
full_output = "".join(output_buffer)
|
|
||||||
|
if not full_output:
|
||||||
if len(full_output) > 4000:
|
full_output = result
|
||||||
full_output = full_output[:4000] + "\n... (вывод обрезан)"
|
|
||||||
|
if len(full_output) > 4000:
|
||||||
await update.message.reply_text(
|
full_output = full_output[:4000] + "\n... (вывод обрезан)"
|
||||||
f"🤖 *Результат:*\n\n"
|
|
||||||
f"```\n{full_output if full_output else result}\n```",
|
await status_msg.edit_text(
|
||||||
parse_mode="Markdown"
|
f"🤖 *Результат:*\n\n"
|
||||||
)
|
f"```\n{full_output}\n```",
|
||||||
|
parse_mode="Markdown"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
|
||||||
|
|
@ -88,30 +88,17 @@ class QwenCodeManager:
|
||||||
on_oauth_url: Callable[[str], Any]) -> str:
|
on_oauth_url: Callable[[str], Any]) -> str:
|
||||||
"""
|
"""
|
||||||
Выполнить задачу в Qwen Code.
|
Выполнить задачу в Qwen Code.
|
||||||
|
Для простоты каждый раз запускаем новый процесс.
|
||||||
Args:
|
|
||||||
user_id: ID пользователя
|
|
||||||
task: Задача для выполнения
|
|
||||||
on_output: Callback для вывода (вызывается при появлении вывода)
|
|
||||||
on_oauth_url: Callback для OAuth URL (вызывается если нужна авторизация)
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Результат выполнения
|
|
||||||
"""
|
"""
|
||||||
|
# Создаём временную сессию для отслеживания
|
||||||
session = self.get_session(user_id)
|
session = self.get_session(user_id)
|
||||||
|
if not session:
|
||||||
# Если сессии нет или она в ошибке — создаём новую
|
|
||||||
if not session or session.state == QwenSessionState.ERROR:
|
|
||||||
session = self.create_session(user_id)
|
session = self.create_session(user_id)
|
||||||
|
|
||||||
session.last_activity = datetime.now()
|
session.last_activity = datetime.now()
|
||||||
session.pending_task = task
|
session.pending_task = task
|
||||||
|
|
||||||
# Если сессия ещё не готова (ожидает OAuth или запуска)
|
# Просто выполняем задачу через -p флаг
|
||||||
if session.state in [QwenSessionState.STARTING, QwenSessionState.WAITING_FOR_OAUTH]:
|
|
||||||
return await self._start_session(session, on_output, on_oauth_url, task)
|
|
||||||
|
|
||||||
# Если сессия готова — выполняем задачу
|
|
||||||
return await self._execute_task(session, task, on_output)
|
return await self._execute_task(session, task, on_output)
|
||||||
|
|
||||||
async def _start_session(self, session: QwenSession,
|
async def _start_session(self, session: QwenSession,
|
||||||
|
|
@ -208,11 +195,29 @@ class QwenCodeManager:
|
||||||
session.output_buffer = ""
|
session.output_buffer = ""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Отправляем задачу
|
# Для неинтерактивного режима используем -p
|
||||||
session.process.stdin.write(task + "\n")
|
env = os.environ.copy()
|
||||||
session.process.stdin.flush()
|
env["FORCE_COLOR"] = "0"
|
||||||
|
|
||||||
# Читаем ответ
|
cmd = [
|
||||||
|
self._qwen_command,
|
||||||
|
"-p", task, # Передаём задачу через флаг -p
|
||||||
|
"--output-format", "text", # Простой текстовый вывод
|
||||||
|
]
|
||||||
|
|
||||||
|
logger.info(f"Выполнение задачи: {' '.join(cmd)}")
|
||||||
|
|
||||||
|
process = subprocess.Popen(
|
||||||
|
cmd,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.STDOUT,
|
||||||
|
cwd=self._working_dir,
|
||||||
|
env=env,
|
||||||
|
text=True,
|
||||||
|
bufsize=1
|
||||||
|
)
|
||||||
|
|
||||||
|
# Читаем вывод
|
||||||
output = ""
|
output = ""
|
||||||
timeout = 300 # 5 минут на выполнение
|
timeout = 300 # 5 минут на выполнение
|
||||||
|
|
||||||
|
|
@ -222,31 +227,32 @@ class QwenCodeManager:
|
||||||
# Проверяем таймаут
|
# Проверяем таймаут
|
||||||
if (datetime.now() - start_time).total_seconds() > timeout:
|
if (datetime.now() - start_time).total_seconds() > timeout:
|
||||||
output += "\n\n⚠️ Таймаут выполнения (5 минут)"
|
output += "\n\n⚠️ Таймаут выполнения (5 минут)"
|
||||||
|
process.terminate()
|
||||||
break
|
break
|
||||||
|
|
||||||
# Проверяем процесс
|
# Проверяем процесс
|
||||||
if session.process.poll() is not None:
|
if process.poll() is not None:
|
||||||
# Процесс завершился
|
# Процесс завершился
|
||||||
remaining = session.process.stdout.read()
|
remaining = process.stdout.read()
|
||||||
if remaining:
|
if remaining:
|
||||||
output += remaining
|
output += remaining
|
||||||
on_output(remaining)
|
on_output(remaining)
|
||||||
break
|
break
|
||||||
|
|
||||||
# Читаем вывод
|
# Читаем вывод
|
||||||
line = session.process.stdout.readline()
|
line = process.stdout.readline()
|
||||||
if line:
|
if line:
|
||||||
output += line
|
output += line
|
||||||
session.output_buffer += line
|
session.output_buffer += line
|
||||||
on_output(line)
|
on_output(line)
|
||||||
|
|
||||||
# Небольшая пауза чтобы не блокировать
|
# Небольшая пауза
|
||||||
await asyncio.sleep(0.1)
|
await asyncio.sleep(0.1)
|
||||||
|
|
||||||
session.state = QwenSessionState.READY
|
session.state = QwenSessionState.READY
|
||||||
session.last_activity = datetime.now()
|
session.last_activity = datetime.now()
|
||||||
|
|
||||||
return self._parse_output(output)
|
return output.strip()
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
session.state = QwenSessionState.ERROR
|
session.state = QwenSessionState.ERROR
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue