Skip to content

Локальный API-прокси для Qwen AI с поддержкой сохранения контекста диалогов и управления сессиями через REST API

Notifications You must be signed in to change notification settings

y13sint/FreeQwenApi

Repository files navigation

API-прокси для Qwen AI

Локальный API-прокси сервер для работы с Qwen AI через браузерную эмуляцию. Позволяет использовать модели Qwen без официального API-ключа.

  • Бесплатный доступ: Используйте модели Qwen без оплаты API-ключа
  • Полная совместимость: Поддержка OpenAI-совместимого интерфейса для простой интеграции
  • Возможность загрузки файлов и получение ссылки прямо из прокси
  • 🆕 API v2: Обновлено на новый Qwen API с улучшенной системой контекста

⚡ Обновление до API v2

Прокси переведён на Qwen API v2. Основные изменения:

  • ✅ История чатов хранится на серверах Qwen (не локально)
  • ✅ Новая система контекста через parentId
  • ✅ Автоматическое создание чатов
  • ✅ Старые эндпоинты работают с расширенным интерфейсом

Новые поля в ответах:

{
  "chatId": "a606fcac-8351-4f1f-80e7-f2f81a88e06a",  // ID чата
  "parentId": "7f637df8-e696-43d9-94b3-40b767da117b" // Для продолжения диалога
}

Использование:

// Первое сообщение
const res1 = await fetch('/api/chat', {
  method: 'POST',
  body: JSON.stringify({ message: "Привет!" })
});
const data1 = await res1.json();

// Второе сообщение с контекстом
const res2 = await fetch('/api/chat', {
  method: 'POST',
  body: JSON.stringify({ 
    message: "Как дела?",
    chatId: data1.chatId,
    parentId: data1.parentId  // Из предыдущего ответа!
  })
});

📋 Оглавление


1. Быстрый старт

1.1 Установка

  1. Клонировать репозиторий
  2. Установить зависимости:
npm install

1.2 Запуск

npm start

Также доступен файл быстрого запуска:

start.bat

1.3 Запуск в Docker

  1. Выполните авторизацию и соберите токены:
npm run auth
  1. После сохранения токенов в папке session/ запустите контейнер:
docker compose up --build -d
  1. Приложение будет доступно на http://localhost:3264/api.

⚙️ Контейнер запускается с переменной SKIP_ACCOUNT_MENU=true, поэтому интерактивное меню не блокирует старт. Папки session/, logs/ и uploads/ примонтированы в контейнер как тома, что позволяет повторно использовать сохранённые токены и журналы.


2. Авторизация через API-ключи

⚠️ Важно: если файл src/Authorization.txt пустой, авторизация отключена.

  1. Файл src/Authorization.txt

    • Создаётся автоматически при первом запуске если его нет.
    • Внутри уже есть подробный шаблон-инструкция.
    • Один токен на строку. Пустые строки и строки, начинающиеся с #, игнорируются.
  2. Отключить авторизацию – оставьте файл пустым. Middleware пропустит все запросы.

  3. Проверка на стороне клиента

    Отправляйте HTTP-заголовок:

    Authorization: Bearer <your_token>

    Пример cURL:

    curl -X POST http://localhost:3264/api/chat \
         -H "Content-Type: application/json" \
         -H "Authorization: Bearer my-secret-token-123" \
         -d '{"message":"Привет"}'

3. Управление аккаунтами (Multi-Account)

При старте npm start появляется интерактивное меню:

Список аккаунтов:
 N | ID                | Статус
 1 | acc_1752745840684 | ✅ OK
 2 | acc_1752745890062 | ❌ INVALID

=== Меню ===
1 - Добавить новый аккаунт
2 - Перелогинить аккаунт с истекшим токеном
3 - Запустить прокси (Enter по умолчанию)
4 - Удалить аккаунт

Статусы:

Значок Значение Поведение
✅ OK токен активен используется в ротации
⏳ WAIT токен временно заблокирован (RateLimited) пропускается до истечения тайм-аута
❌ INVALID токен просрочен (401 Unauthorized) недоступен, выберите пункт 2 для повторного входа

Пункты меню:

  1. Добавить новый аккаунт – откроется браузер, авторизуйтесь, токен будет сохранён.
  2. Перелогинить аккаунт с истекшим токеном – выберите нужный ID, откроется браузер для повторного входа, статус сменится на ✅.
  3. Запустить прокси – доступно, если есть хотя бы один статус ✅ или ⏳.
  4. Удалить аккаунт – полностью удаляет токен и папку сессии.

Файлы:

  • session/accounts/<id>/token.txt – токен аккаунта
  • session/tokens.json – реестр аккаунтов и состояний
  • npm run auth – отдельный скрипт для управления аккаунтами без запуска сервера (то же меню, плюс CLI-аргументы --list, --add, --relogin, --remove)

⚙️ Переменные окружения

Переменная Значение по умолчанию Назначение
PORT 3264 Порт HTTP-сервера
HOST 0.0.0.0 Адрес привязки сервера
SKIP_ACCOUNT_MENU false При значении true отключает интерактивное меню запуска (нужно для Docker/CI)

SKIP_ACCOUNT_MENU автоматически активирован в Docker Compose. Если при старте нет валидных токенов, сервер завершит работу с подсказкой запустить npm run auth.


Автоматическая ротация:

  • запросы распределяются по токенам циклически.
  • При ответе 429 RateLimited токен получает ⏳ WAIT на указанное время.
  • При ответе 401 Unauthorized токен помечается ❌ INVALID.
  • Если все токены недействительны – прокси завершает работу, запустите его и перелогиньтесь.

4. Возможности

Этот проект позволяет:

  • Использовать модели Qwen AI через локальный API
  • Сохранять контекст диалогов между запросами
  • Управлять диалогами через API
  • Выбирать различные модели Qwen для генерации ответов
  • Отправлять изображения для анализа моделью
  • Использовать OpenAI-совместимый API с поддержкой streaming режима

5. API Reference

5.1 Основные эндпоинты

Эндпоинт Метод Описание
/api/chat POST Отправка сообщения с поддержкой chatId и parentId
/api/chat/completions POST OpenAI-совместимый эндпоинт, возвращает chatId/parentId
/api/models GET Получение списка доступных моделей
/api/status GET Проверка статуса авторизации и аккаунтов
/api/files/upload POST Загрузка изображения для использования в запросах
/api/chats POST Создание нового чата на серверах Qwen

⚠️ Удалённые эндпоинты (v2):

  • GET /api/chats - список чатов
  • GET /api/chats/:chatId - история чата
  • DELETE /api/chats/:chatId - удаление чата
  • PUT /api/chats/:chatId/rename - переименование
  • POST /api/chats/cleanup - автоудаление

Причина: чаты теперь управляются на серверах Qwen

5.2 Выбор эндпоинтов

Эндпоинт Использование контекста Формат запроса Совместимость
/api/chat Контекст управляется через chatId + parentId. История хранится на серверах Qwen. Упрощённый message + chatId + parentId Нативный для прокси
/api/chat/completions Поддерживает chatId + parentId в запросе. Возвращает их в ответе для продолжения. Массив messages (OpenAI format) + опционально chatId/parentId OpenAI SDK

5.3 Форматы запросов

1. Упрощенный формат с параметром message

{
  "message": "Текст сообщения",
  "model": "qwen-max-latest",
  "chatId": "идентификатор_чата",
  "parentId": "response_id_из_предыдущего_ответа"
}

2. Формат, совместимый с OpenAI API

{
  "messages": [
    {"role": "user", "content": "Привет, как дела?"}
  ],
  "model": "qwen-max-latest",
  "chatId": "идентификатор_чата",
  "parentId": "response_id_из_предыдущего_ответа"
}

5.4 Работа с контекстом (API v2)

Новая система:

  • История хранится на серверах Qwen, не локально
  • Контекст управляется через chatId + parentId
  • parentId - это response_id из предыдущего ответа

Пример диалога:

// 1. Первое сообщение
const res1 = await fetch('/api/chat', {
  method: 'POST',
  body: JSON.stringify({ message: "Сколько будет 2+2?" })
});
const data1 = await res1.json();
// Ответ: { chatId: "abc-123", parentId: "xyz-789", ... }

// 2. Второе сообщение (с контекстом)
const res2 = await fetch('/api/chat', {
  method: 'POST',
  body: JSON.stringify({ 
    message: "А результат плюс 3?",
    chatId: data1.chatId,      // Тот же чат
    parentId: data1.parentId    // Из предыдущего ответа!
  })
});
// Модель помнит контекст и ответит "7"

5.5 Системные инструкции (System Messages)

Новое в v2: Поддержка системных сообщений для настройки поведения модели!

Системные инструкции передаются через поле role: "system" в массиве messages. Это позволяет задать модели контекст, стиль общения, правила поведения и т.д.

Пример:

// Запрос с системной инструкцией
const response = await fetch('/api/chat/', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    messages: [
      {
        role: "system",
        content: "Ты - опытный программист на Python. Отвечай кратко и предоставляй примеры кода."
      },
      {
        role: "user",
        content: "Как отсортировать список в Python?"
      }
    ],
    model: "qwen-max-latest"
  })
});

Как работает:

  • system message извлекается из массива и передаётся отдельным параметром в Qwen API v2
  • Может использоваться в обоих эндпоинтах: /api/chat и /api/chat/completions
  • System message применяется ко всему чату и влияет на все последующие ответы

Примеры использования:

// 1. Ролевая инструкция
{
  "messages": [
    {"role": "system", "content": "Ты - эксперт по машинному обучению"},
    {"role": "user", "content": "Объясни, что такое градиентный спуск"}
  ]
}

// 2. Стиль ответов
{
  "messages": [
    {"role": "system", "content": "Отвечай как пират"},
    {"role": "user", "content": "Как дела?"}
  ]
}

// 3. Формат вывода
{
  "messages": [
    {"role": "system", "content": "Всегда отвечай в формате JSON"},
    {"role": "user", "content": "Дай информацию о Python"}
  ]
}

5.6 Работа с изображениями

Прокси поддерживает отправку сообщений с изображениями:

Формат message с изображением

{
  "message": [
    {
      "type": "text",
      "text": "Опишите объекты на этом изображении"
    },
    {
      "type": "image",
      "image": "URL_ИЗОБРАЖЕНИЯ"
    }
  ],
  "model": "qwen-vl-max",
  "chatId": "идентификатор_чата",
  "parentId": "response_id"
}

5.7 Загрузка файлов

Загрузка изображения

POST http://localhost:3264/api/files/upload

Формат запроса: multipart/form-data

Параметры:

  • file - файл изображения (поддерживаются форматы: jpg, jpeg, png, gif, webp)

Пример использования с curl:

curl -X POST http://localhost:3264/api/files/upload \
  -F "file=@/путь/к/изображению.jpg"

Пример ответа:

{
  "imageUrl": "https://cdn.qwenlm.ai/user-id/file-id_filename.jpg?key=..."
}

Получение URL изображения

Для отправки изображений через API прокси необходимо сначала получить URL изображения. Это можно сделать двумя способами:

Способ 1: Загрузка через API прокси

Отправьте POST запрос на эндпоинт /api/files/upload для загрузки изображения, как описано выше.

Способ 2: Получение URL через веб-интерфейс Qwen
  1. Загрузите изображение в официальном веб-интерфейсе Qwen (https://chat.qwen.ai/)
  2. Откройте инструменты разработчика в браузере (F12 или Ctrl+Shift+I)
  3. Перейдите на вкладку "Network" (Сеть)
  4. Найдите запрос к API Qwen, содержащий ваше изображение (обычно это запрос GetsToken)
  5. В теле запроса найдите URL изображения, который выглядит примерно так: https://cdn.qwenlm.ai/user-id/file-id_filename.jpg?key=...
  6. Скопируйте этот URL для использования в вашем API-запросе

5.7 Управление диалогами

Создание нового диалога

POST http://localhost:3264/api/chats

Тело запроса:

{
  "name": "Название диалога"
}

Ответ:

{
  "chatId": "уникальный_идентификатор"
}

Получение списка всех диалогов

GET http://localhost:3264/api/chats

Получение истории диалога

GET http://localhost:3264/api/chats/:chatId

Удаление диалога

DELETE http://localhost:3264/api/chats/:chatId

Переименование диалога

PUT http://localhost:3264/api/chats/:chatId/rename

Тело запроса:

{
  "name": "Новое название чата"
}

Автоматическое удаление диалогов

POST http://localhost:3264/api/chats/cleanup

Тело запроса (все параметры опциональны):

{
  "olderThan": 604800000, // Удалить чаты старше указанного времени (в мс), например 7 дней
  "userMessageCountLessThan": 3, // Удалить чаты с менее чем 3 сообщениями от пользователя
  "messageCountLessThan": 5, // Удалить чаты с менее чем 5 сообщениями всего
  "maxChats": 50 // Оставить только 50 самых новых чатов
}

6. Примеры использования

Текстовые запросы

▶️ Пример простого текстового запроса
curl -X POST http://localhost:3264/api/chat \
  -H "Content-Type: application/json" \
  -d '{
    "message": "Что такое искусственный интеллект?",
    "model": "qwen-max-latest"
  }'
▶️ Пример запроса в формате официального API
curl -X POST http://localhost:3264/api/chat \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [
      {"role": "user", "content": "Что такое искусственный интеллект?"}
    ],
    "model": "qwen-max-latest"
  }'

Запросы с изображениями

▶️ Пример загрузки изображения и отправки запроса с ним
# Шаг 1: Загрузка изображения
UPLOAD_RESPONSE=$(curl -s -X POST http://localhost:3264/api/files/upload \
  -F "file=@/путь/к/изображению.jpg")

# Шаг 2: Извлечение URL изображения
IMAGE_URL=$(echo $UPLOAD_RESPONSE | grep -o '"imageUrl":"[^"]*"' | sed 's/"imageUrl":"//;s/"//')

# Шаг 3: Отправка запроса с изображением
curl -X POST http://localhost:3264/api/chat \
  -H "Content-Type: application/json" \
  -d '{
    "message": [
      { "type": "text", "text": "Опишите объекты на этом изображении" },
      { "type": "image", "image": "'$IMAGE_URL'" }
    ],
    "model": "qwen3-235b-a22b"
  }'

Примеры через Postman

▶️ Пошаговое руководство через Postman
  1. Загрузка изображения:

    • Создайте новый запрос POST к http://localhost:3264/api/files/upload
    • Выберите вкладку "Body"
    • Выберите тип "form-data"
    • Добавьте ключ "file" и выберите тип "File"
    • Загрузите изображение, нажав на кнопку "Select Files"
    • Нажмите "Send"

    Ответ будет содержать URL изображения:

    {
      "imageUrl": "https://cdn.qwenlm.ai/user-id/file-id_filename.jpg?key=..."
    }
  2. Использование изображения в запросе:

    • Создайте новый запрос POST к http://localhost:3264/api/chat
    • Выберите вкладку "Body"
    • Выберите тип "raw" и формат "JSON"
    • Вставьте следующий JSON, заменив URL_ИЗОБРАЖЕНИЯ на полученный URL:
    {
      "message": [
        {
          "type": "text",
          "text": "Опишите объекты на этом изображении"
        },
        {
          "type": "image",
          "image": "URL_ИЗОБРАЖЕНИЯ"
        }
      ],
      "model": "qwen3-235b-a22b"
    }
    • Нажмите "Send"

Использование OpenAI-совместимого эндпоинта

  1. Запрос через OpenAI-совместимый эндпоинт:

    • Создайте новый запрос POST к http://localhost:3264/api/chat/completions
    • Выберите вкладку "Body"
    • Выберите тип "raw" и формат "JSON"
    • Вставьте следующий JSON, заменив URL_ИЗОБРАЖЕНИЯ на полученный URL:
    {
      "messages": [
        {
          "role": "user",
          "content": [
            {
              "type": "text",
              "text": "Опиши, что изображено на этой картинке?"
            },
            {
              "type": "image",
              "image": "URL_ИЗОБРАЖЕНИЯ"
            }
          ]
        }
      ],
      "model": "qwen3-235b-a22b"
    }
    • Нажмите "Send"
  2. Запрос с потоковым режимом (streaming):

    • Используйте тот же URL и тело запроса, но добавьте параметр "stream": true
    • Примечание: для корректного отображения потока в Postman, проверьте опцию "Preserve log" в консоли

🔄 Работа с контекстом

Система автоматически сохраняет историю диалога и отправляет ее в каждом запросе к API Qwen. Это позволяет моделям учитывать предыдущие сообщения при генерации ответов.

Последовательность работы с контекстом

  1. Первый запрос (без указания chatId):
{
  "message": "Привет, как тебя зовут?"
}
  1. Ответ (содержит chatId):
{
  "chatId": "abcd-1234-5678",
  "choices": [...]
}
  1. Последующие запросы (с указанием полученного chatId):
{
  "message": "Сколько будет 2+2?",
  "chatId": "abcd-1234-5678"
}

🔌 Совместимость с OpenAI API

Прокси поддерживает эндпоинт, совместимый с OpenAI API для подключения клиентов, которые работают с OpenAI API:

POST /api/chat/completions

Особенности работы

  1. Создание нового чата для каждого запроса: Каждый запрос к /chat/completions создаёт новый чат в системе с именем "OpenAI API Chat".

  2. Сохранение полной истории сообщений: Все сообщения из запроса (включая системные, пользовательские и сообщения ассистента) сохраняются в истории чата.

  3. Поддержка системных сообщений: Прокси корректно обрабатывает и сохраняет системные сообщения (role: "system"), которые часто используются для настройки поведения модели.

Пример запроса с системным сообщением:

{
  "messages": [
    {"role": "system", "content": "Ты эксперт по JavaScript. Отвечай только на вопросы о JavaScript."},
    {"role": "user", "content": "Как создать класс в JavaScript?"}
  ],
  "model": "qwen-max-latest"
}

Поддержка streaming режима

Прокси поддерживает режим потоковой передачи ответов (streaming), что позволяет получать ответы по частям в режиме реального времени:

{
  "messages": [
    {"role": "user", "content": "Напиши длинный рассказ о космосе"}
  ],
  "model": "qwen-max-latest",
  "stream": true
}

При использовании streaming режима, ответ будет возвращаться постепенно в формате Server-Sent Events (SSE), совместимом с OpenAI API.

Примеры использования с OpenAI SDK

▶️ Пример использования с OpenAI Node.js SDK
// Пример использования с OpenAI Node.js SDK
import OpenAI from 'openai';
import fs from 'fs';
import axios from 'axios';

const openai = new OpenAI({
  baseURL: 'http://localhost:3264/api', // Базовый URL прокси
  apiKey: 'dummy-key', // Не требуется реальный ключ, но поле обязательное для библиотеки
});

// Запрос без streaming
const completion = await openai.chat.completions.create({
  messages: [{ role: 'user', content: 'Привет, как дела?' }],
  model: 'qwen-max-latest', // Используемая модель Qwen
});

console.log(completion.choices[0].message);

// Запрос со streaming
const stream = await openai.chat.completions.create({
  messages: [{ role: 'user', content: 'Расскажи длинную историю о космосе' }],
  model: 'qwen-max-latest',
  stream: true,
});

for await (const chunk of stream) {
  process.stdout.write(chunk.choices[0]?.delta?.content || '');
}

// Загрузка и использование изображения
async function uploadAndAnalyzeImage(imagePath) {
  // Загрузка изображения через API прокси
  const formData = new FormData();
  formData.append('file', fs.createReadStream(imagePath));
  
  const uploadResponse = await axios.post('http://localhost:3264/api/files/upload', formData, {
    headers: { 'Content-Type': 'multipart/form-data' }
  });
  
  const imageUrl = uploadResponse.data.imageUrl;
  
  // Создание запроса с изображением
  const completion = await openai.chat.completions.create({
    messages: [
      { 
        role: 'user', 
        content: [
          { type: 'text', text: 'Опиши, что изображено на этой картинке?' },
          { type: 'image', image: imageUrl }
        ] 
      }
    ],
    model: 'qwen3-235b-a22b',
  });
  
  console.log(completion.choices[0].message.content);
}

// Использование: uploadAndAnalyzeImage('./image.jpg');

Ограничения совместимости:

  1. Некоторые специфичные для OpenAI параметры (например, logprobs, functions и т.д.) не поддерживаются.
  2. Скорость потоковой передачи может отличаться от оригинального OpenAI API.

About

Локальный API-прокси для Qwen AI с поддержкой сохранения контекста диалогов и управления сессиями через REST API

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published