Skip to content

Клиент на базе мини-программы WeChat ​

Мини-программа WeChat предоставляет мобильную точку входа для вопросов по базе знаний и импорта веб-страниц, подключаясь к уже работающему сервису aihelpme.ru. Исходный код находится в miniprogram/. При использовании сначала настройте адрес API и API Key, затем выберите базу знаний:

  • Импорт URL веб-страницы в выбранную базу знаний.
  • Задавайте вопросы по выбранной базе знаний.

Адрес бэкенда и настройка аутентификации ​

Мини-программа не хардкодит адрес бэкенда в коде: все сведения о подключении пользователь вводит на странице «Настройки», они сохраняются в локальном хранилище по ключу weknora_settings через wx.setStorageSync и состоят из четырёх полей:

js
{
  baseUrl: "http://localhost:8080",   // значение по умолчанию, записывается app.js в onLaunch
  apiKey: "",
  selectedKnowledgeBaseId: "",
  locale: "zh"                        // язык интерфейса: zh | en
}
  • Значения по умолчанию: если в onLaunch в miniprogram/app.js обнаруживается отсутствие локальных настроек, записываются значения по умолчанию baseUrl: "http://localhost:8080", пустой apiKey и locale: "zh". Значения по умолчанию лишь упрощают локальную разработку; при реальном использовании нужно заменить их на настоящий адрес на странице настроек.
  • Чтение/запись и нормализация: miniprogram/utils/config.js предоставляет getSettings() / saveSettings(); функция normalizeBaseUrl() убирает пробелы по краям и завершающий /, а normalizeLocale() относит любое значение, отличное от en, к zh.
  • Способ аутентификации — API Key: все запросы в miniprogram/utils/request.js единообразно несут заголовки:
  • X-API-Key: <введённый пользователем API Key> (получается в aihelpme.ru в разделе «Настройки → Интеграции публикации → Интеграция API», имеет вид sk-...);
  • X-Request-ID: mp-<метка времени>-<случайная строка> (для трассировки на сервере);
  • Content-Type: application/json.
  • Предварительная проверка: если отсутствует baseUrl или apiKey, запрос сразу отклоняется ошибочным Promise, а подсказка отображается на текущем языке (например, «Сначала настройте адрес API aihelpme.ru.» / «Сначала настройте API Key aihelpme.ru.»); onShow в pages/index/index.js также показывает подсказку, ведущую пользователя на страницу настроек.
  • Настройка AppID: скопируйте miniprogram/project.private.config.json.example в project.private.config.json и укажите собственный AppID (содержимое файла-примера — {"appid": "your-wechat-mini-program-appid"}). Внимание: текущий общий project.config.json содержит поле appid; при использовании собственной мини-программы перекройте его приватной конфигурацией.

Используемые интерфейсы бэкенда (все определены в miniprogram/utils/request.js):

ФункцияМетод и путь
listKnowledgeBases()GET /api/v1/knowledge-bases
createKnowledgeFromURL(kbId, url, enableMultimodel)POST /api/v1/knowledge-bases/{kbId}/knowledge/url
createSession(kbId)POST /api/v1/sessions
knowledgeChat(sessionId, query, kbId)POST /api/v1/knowledge-chat/{sessionId}

Китайский/английский и локальные настройки ​

Начиная с v0.8.2, на странице настроек можно выбрать «Китайский» или «English», по умолчанию — китайский; выбор сохраняется в локальных настройках как locale (zh / en) и переживает перезапуск. После переключения немедленно обновляются тексты страниц, заголовок панели навигации (wx.setNavigationBarTitle) и тексты нижних tab (wx.setTabBarItem); нижние tab также имеют иконки (assets/tab/*.png). Тексты собраны в utils/i18n.js; новые страницы должны переиспользовать этот модуль.

Сейчас страница чата после завершения запроса разбирает весь текст SSE и накапливает фрагменты answer, без пофрагментного рендеринга в реальном времени. Для официального выпуска нужно добавить домен API в список разрешённых доменов для request.

Процесс сборки и публикации ​

Мини-программа не требует шага компиляции (нативная разработка, без цепочки инструментов сборки) — её достаточно открыть напрямую в инструментах разработчика WeChat (WeChat DevTools):

  1. Импорт проекта: в инструментах разработчика WeChat выберите «Импорт проекта», указав каталог miniprogram/ репозитория. Инструмент прочитает project.config.json (имя проекта "aihelpme.ru Mini Program").
  2. Настройка AppID: скопируйте miniprogram/project.private.config.json.example в project.private.config.json и замените appid на фактический AppID мини-программы. project.private.config.json является личной приватной конфигурацией, игнорируется .gitignore и не должен коммититься.
  3. Настройка подключения к бэкенду: после запуска перейдите на tab «Настройки», укажите API Base URL (например, https://weknora.example.com) и API Key aihelpme.ru (получается в «Настройки → Интеграции публикации → Интеграция API»), при необходимости переключите язык интерфейса и сохраните.
  4. Замечания по локальной отладке: в project.config.json включён urlCheck: true, поэтому инструменты разработчика по умолчанию блокируют запросы к неразрешённым доменам, таким как localhost. Для локального теста можно поставить галочку «Не проверять разрешённые домены» в DevTools или открыть сервис aihelpme.ru через HTTPS-домен разработки.
  5. Публикация: перед официальным выпуском нужно в административной панели мини-программы на платформе WeChat добавить домен API aihelpme.ru (обязательно HTTPS) в список разрешённых доменов для request (белый список доменов request); затем в инструментах разработчика нажать «Загрузить», чтобы отправить код, а в административной панели отправить на проверку и опубликовать.

Тестирование ​

miniprogram/package.json определяет единственный скрипт:

bash
cd miniprogram
npm test    # фактически выполняет node --test ../tests/miniprogram/*.test.js

То есть используются встроенный test runner Node.js и модульные тесты из tests/miniprogram/miniprogram.test.js репозитория (охватывают разбор SSE, нормализацию адреса, переключение китайский/английский, заголовки и тело запроса, логику загрузки страницы баз знаний); устанавливать зависимости не требуется.

Совместимость с базовой библиотекой ​

Страницы и код в utils/ не используют опциональную цепочку ?. и объединение с null ??: часть версий базовой библиотеки не поддерживает этот синтаксис, что приводит к белому экрану (в v0.8.2 исправлена пустая страница базы знаний из-за этой проблемы). Привязки текста в WXML также остаются плоскими полями, чтобы корректно рендериться в разных версиях базовой библиотеки. При изменении кода сохраняйте это ограничение.

Справочная реализация ​

Технологический стек ​

Этот клиент — нативная мини-программа WeChat (native Mini Program), без кросс-платформенных фреймворков вроде Taro / uni-app / mpvue и без каких-либо npm-зависимостей времени выполнения:

  • miniprogram/app.js — стандартная точка входа App({...}), при onLaunch записывает в локальное хранилище настройки по умолчанию;
  • miniprogram/app.json — стандартная глобальная конфигурация мини-программы (pages, window, tabBar);
  • miniprogram/app.wxss — глобальные стили; каждая страница представляет собой комплект из четырёх файлов js / wxml / wxss / json;
  • miniprogram/package.json — имя пакета weknora-miniprogram (version 0.1.0), description — "WeChat Mini Program plugin for aihelpme.ru", нет dependencies, только один тестовый скрипт (см. «Тестирование» ниже);
  • miniprogram/project.config.json — compileType: "miniprogram", libVersion: "latest" (базовая библиотека последней версии), в опциях компиляции включены es6, enhance, postcss, minified, minifyWXSS, minifyWXML, а также urlCheck: true (проверка разрешённых доменов). Сейчас этот файл содержит поле appid; собственный AppID задаётся через приватный файл конфигурации (см. «Процесс сборки и публикации»).

Глобальный стиль окна: заголовок панели навигации WeKnora, цвет фона #0d3b2a (тёмно-зелёный), текст белый.

Список страниц ​

В miniprogram/app.json зарегистрированы 3 страницы, и все три одновременно образуют нижний tabBar (цвет выбора #07c05f, у каждого пункта два набора иконок — обычная / выбранная). Тексты tab по умолчанию китайские и переключаются по языку во время работы:

Путь страницыТекст tabBar (Китайский / English)Назначение
pages/index/indexБаза знаний / KnowledgeГлавная страница. Проверяет, настроены ли baseUrl / API Key; если нет — показывает подсказку и позволяет одним действием перейти на страницу настроек; вызывает GET /api/v1/knowledge-bases для загрузки списка баз знаний, выбирает базу через picker или по списку (результат выбора сохраняется в локальное хранилище); после ввода URL веб-страницы вызывает POST /api/v1/knowledge-bases/{id}/knowledge/url, импортируя этот URL в выбранную базу знаний (enable_multimodel жёстко равно false)
pages/chat/chatВопросы / ChatСтраница вопросов по базе знаний. При первом вопросе лениво создаёт сессию через POST /api/v1/sessions (с выбранным knowledge_base_id), затем задаёт вопрос через POST /api/v1/knowledge-chat/{sessionId}; тело ответа — текст SSE, клиент разбирает его через utils/sse.js, склеивает фрагменты с response_type === "answer" и показывает целиком (при сбое разбора отображает исходный ответ)
pages/settings/settingsНастройки / SettingsСтраница настройки подключения. Ввод API Base URL и API Key (поле ввода пароля), выбор языка интерфейса, сохранение в локальное хранилище weknora_settings

Служебные модули utils/ ​

ФайлНазначение
miniprogram/utils/config.jsСлой хранения настроек: определяет ключ STORAGE_KEY = "weknora_settings", предоставляет getSettings(), saveSettings() (объединяющее обновление), normalizeBaseUrl() (trim и удаление завершающей косой черты) и normalizeLocale()
miniprogram/utils/i18n.jsТаблица текстов китайский/английский и t(), getLocale() / setLocale(), applyTabBar() (обновляет тексты и иконки нижних tab), applyNavTitle() (обновляет заголовок панели навигации)
miniprogram/utils/request.jsHTTP-обёртка на промисах поверх wx.request: склейка baseUrl + path, добавление заголовков X-API-Key / X-Request-ID, единая проверка 2xx и извлечение сообщения об ошибке (сначала error.message, затем message, в крайнем случае HTTP <status>); также экспортирует 4 бизнес-функции API из таблицы выше
miniprogram/utils/sse.jsРазбор текста Server-Sent Events: parseSSE(raw) разбивает на блоки событий по пустым строкам, разбирает строки event: / data:; collectAnswerFromSSE(raw) разбирает data каждого события как JSON и накапливает content с response_type === "answer", получая итоговый текст ответа. Обратите внимание: на стороне мини-программы нет потокового рендеринга — после получения полного текста SSE от wx.request он разбирается и отображается один раз

Обзор потока данных ​

Версия v0.8.3 · MIT License