Skip to content

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

Notifications You must be signed in to change notification settings

y13sint/FreeQwenApi

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

88 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Совместимость с курсором - теоритически возможно, но гвен не может напрямую вызывать инструменты как OpenAI, мб когда нибудь сделаю

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

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

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

📋 Оглавление


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

1.1 Установка

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

1.2 Запуск

npm start

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

start.bat

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 – реестр аккаунтов и состояний

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

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

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

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

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

5. API Reference

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

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

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

Эндпоинт Использование контекста Формат запроса Совместимость
/api/chat Прокси хранит внутреннюю историю chatId и автоматически подаёт её модели при каждом запросе. Упрощённый message или массив messages Нативный для прокси
/api/chat/completions Прокси НЕ хранит контекст между запросами: каждый вызов следует спецификации OpenAI — вы сами передаёте массив messages. Только массив messages (OpenAI format) OpenAI SDK

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

Прокси поддерживает два формата запросов к /api/chat:

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

{
  "message": "Текст сообщения",
  "model": "qwen-max-latest",
  "chatId": "идентификатор_чата"
}

2. Формат, совместимый с официальным API Qwen, с параметром messages

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

5.4 Работа с историей диалога

Важно понимать: Прокси использует внутреннюю систему хранения истории диалогов на сервере.

  1. При использовании формата message - сообщение просто добавляется в историю диалога.
  2. При использовании формата messages - из массива извлекается только последнее сообщение пользователя и добавляется в историю.

При отправке запроса к официальному API Qwen всегда используется полная история диалога, связанная с указанным chatId. Это означает, что при использовании параметра messages вам достаточно включить только новое сообщение пользователя с ролью "user", а не всю историю диалога.

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

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

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

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

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

{
  "messages": [
    {
      "role": "user", 
      "content": [
        {
          "type": "text",
          "text": "Опишите объекты на этом изображении"
        },
        {
          "type": "image",
          "image": "URL_ИЗОБРАЖЕНИЯ"
        }
      ]
    }
  ],
  "model": "qwen3-235b-a22b",
  "chatId": "идентификатор_чата"
}

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

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

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