"Что? У вас еще нет своего ChatGPT? 》Буквально вчера в ChatGPT возникла серьезная ошибка. В командном режиме можно пригласить неограниченное количество пользователей 3.5 для игры в функции 4.0, поэтому я как можно скорее присоединился к ней, а затем разместил ее в своей группе с открытым исходным кодом и созвал большую группу. ребята бесплатно. В результате они спросили меня, как создать свой ChatGPT, и попросили опубликовать обучающую статью, и вот оно!!!
В ходе ChatGPT мы стали свидетелями удивительного развития искусственного интеллекта: от первоначальной модели диалога до сегодняшнего ChatGPT. Эта эволюция является не только технологическим прогрессом, но и блестящим проявлением человеческого мышления. Со временем ChatGPT постепенно стал неотъемлемой частью жизни людей, предоставляя неограниченные возможности для общения, обучения и инноваций.
ChatGPT может помочь нам с рядом проблем, таких как рисование, ролевые игры, генератор кода, анализ кода и т. д. Хотя в официальную модель ChatGPT3.5 можно играть бесплатно, разработчикам, которые хотят иметь свою собственную, нужен API , тогда чиновнику API нужны деньги, поэтому эта статья находится здесь! Создайте свой собственный КЛЮЧ API для ChatGPT Baiguo 3.5, прежде всего, отдайте должное «Цинь Шихуану» Если вы меня не знаете, вы узнаете это позже. В этой статье мы создадим ChatGPT с нуля и подключим его к нашей личной официальной учетной записи для индивидуального ответа. Разве это не здорово? Сегодня утром я создал его с нуля, и это заняло у меня больше двух часов. Можете себе представить, сколько времени заняла эта статья. Если она вам понравилась и она вам помогла, пожалуйста, поставьте палец вверх и добавьте ее в избранное~.
Первоначально для доступа планировалось использовать большую модель Hunyuan, но для API требуется корпоративное приложение. Хотя он у меня есть, а у вас его может не быть, я не буду выполнять эту операцию, но я продолжу расширять код Hunyuan для реализации стыковки. в конце. Приходите и учитесь. Давайте создадим собственное программное обеспечение для общения. В этой статье более 30 000 слов и полностью создадим свой собственный GPT.
В этой статье рассматривается создание ChatGPT, а затем создание сервисов на основе Proxy Api для подключения к общедоступным учетным записям, использование идей, основанных на домене DDD, для создания проектов SpringBoot и использование фабрик сеансов для создания запросов OpenAI на основе наиболее полезного okHttp. См. рисунок ниже. подробности.
существование Подготовить начал с публикации рендеринга, затем в беседу в паблик аккаунте вмешался следующий
Сначала мы работаем
Посетите Juhuasuan, чтобы приобрести серверы Tencent Cloud в конце года: https://curl.qcloud.com/Ukg0wxww
Это всего лишь сто долларов, так что если тебе нужно спешить с закрытыми глазами, ладно?
Выбор конфигурации centOs 7.6
Остальное — настроить среду для развертывания приложения. Я не буду вдаваться в подробности. Я предполагаю, что вы являетесь экспертом в основах Linux.
Все следующие методы установки взяты из JPOM.
Этот скрипт автоматически проверит, существуют ли jdk, mvn, node в текущей среде. Если они не существуют, установите их.
curl -fsSL https://jpom.top/docs/install.sh | bash -s Server jdk+mvn+node+default
Вы можете использовать пошаговую установку, а можете использовать комплексную установку (рекомендую пошаговую установку в один клик, я никогда этого не делал)
# 下载并Установить Докер Местонуждатьсяизпакет программного обеспечения
sudo yum install -y yum-utils
# Добавить официальный адрес склада Docker
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# Установите адрес склада Alibaba Cloud зеркалоизюм
sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# Обновить кэш yum
sudo yum makecache fast
# Установите новую версию Docker
sudo yum install -y docker-ce docker-ce-cli containerd.io
curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun
https://jpom.top/pages/feb7c1/#%E5%89%8D%E8%A8%80
по путь по умолчанию: /usr/java/xxxx
Версия: 1.8
Источник: https://mirrors.tuna.tsinghua.edu.cn/Adoptium/
curl -fsSL https://jpom.top/docs/install.sh | bash -s Server jdk+only-module+default
#gccУстановить, nginxИсходный кодкомпилироватьнуждаться
yum install -y gcc-c++
#PCRE pcre-devel Установить, nginx из http модульиспользовать pcre анализировать регулярные выражения
yum install -y pcre pcre-devel
#zlibУстановить, nginx Usezlib сжимает содержимое http-пакета из
yum install -y zlib zlib-devel
#OpenSSL Установка, мощная криптографическая библиотека Secure Sockets Layer, nginx. не только поддержка http протокол, также поддерживает https (т.е. http передается по существующему протоколу Sl)
yum install -y openssl openssl-devel
Загрузите с помощью команды wget
mkdir -p /usr/local/nginx && cd /usr/local/nginx
#Номер версии загрузки можно изменить в соответствии с последней стабильной версией текущего официального сайта.
wget -O nginx-1.20.2.tar.gz https://nginx.org/download/nginx-1.20.2.tar.gz
Скомпилировать nginx
Команда #Root DirectoryUsls позволяет увидеть, как приезжает загрузить сжатый пакет изnginx, а затем разархивировать его.
tar -zxvf nginx-1.20.2.tar.gz
#Входим в каталог после распаковки
cd nginx-1.20.2
#использоватьпо умолчанию Конфигурация
./configure
# компилировать Установить
make
make install
# Запустить nginx
cd /usr/local/nginx
./sbin/nginx
тестовый доступ к да успешен, появляется следующий контент, это полный успех
Выше приведена базовая среда. Это займет около 10 минут, и ошибок не будет. Я делал это несколько раз! !
Pandora Cloud + Pandora Server + Shared Chat + BackendAPI Proxy + Chat2API = PandoraNext
PandoraNext да zhile(Цинь Шихуан)Место写документадрес:Документация Пандоры
Здесь нам нужно только использовать его вызов API-прокси, чтобы позвонить в Chat.openai.com. Прямой доступ к да внутри страны затруднен, поэтому я не буду объяснять это подробно здесь. Все это понимают~.
Итак, без лишних слов, давайте начнем собирать PandoraNext напрямую. Откройте документ, и вы увидите три метода развертывания. Мы сразу выбираем Docker, самый удобный из них. Мы уже создали вышеупомянутый.
Если здесь есть сервер, вы можете использовать локальный, если сервера нет. Здесь я буду использовать MacOS в качестве примера для локальной сборки PandoraNext.
⚠️: Linux Можете ли вы понять, что мы с сервером работаем точно так же и продолжаем работать? Если он не локальный, пропустите здесь и прочтите ниже. ⚠️: Proxy модель Не поддерживается местныйвызов
Docker Desktop: https://docs.docker.com/desktop/install/mac-install/
⚠️: Пожалуйста, заранее установите компьютерную версию Docker Desktop. Я не буду брать ее с собой. Просто следуйте официальной документации, и все готово.
После завершения загрузки Да Так
Не забудьте настроить ускоренную загрузку внутри страны.
"registry-mirrors": [
"https://xv6jnj6e.mirror.aliyuncs.com"
]
Затем перезагрузка завершена, затем откройте терминал
Добавляем новую папку под названием pandoranext-deploy. Файлы в ней основаны на картинках.
mkdir -p data session
Просто добавьте файл config.json и файл tokens.json в данные.
touch config.json tokens.json
здесьдапо умолчаниюиз Конфигурационный официальный файл, уберите его, мы только меняем его
Всего четыре параметра: License_id, site_password, setup_password, proxy_api_prefix.
{
"bind": "0.0.0.0:8181",
"tls": {
"enabled": false,
"cert_file": "",
"key_file": ""
},
"timeout": 600,
"proxy_url": "",
"license_id": «очень важно»,
"public_share": false,
"site_password": «Пароль доступа к вашей веб-странице»,
"setup_password": «Управление конфигурацией паролей»,
"server_tokens": true,"proxy_api_prefix": "prox api просить префикс",
"isolated_conv_title": "*",
"disable_signup": false,
"auto_conv_arkose": false,
"proxy_file_service": true,
"custom_doh_host": "",
"captcha": {
"provider": "",
"site_key": "",
"site_secret": "",
"site_login": false,
"setup_login": false,
"oai_username": false,
"oai_password": false,
"oai_signup": false
},
"whitelist": null
}
Укажите свой идентификатор лицензии для уникальных сервисов Pandora
Скопируйте License_id в config.json
⚠️ Разрешите нам копировать все, что находится вокруг нас, и вводить это непосредственно на сервер.
Нажмите Enter, чтобы завершить загрузку, и появится файл License.jwt.
Итак, мы завершили базовую настройку. Далее приступим непосредственно к сборке сервиса Pandora.
当тынастраивать Понятноэтотпароль,ты就可以Проходить过<ты部署изстоятьточка>/setupтакиз Сделайте некоторые настройки для адреса,Такие как: существование конфигурацииconfig.json, tokens.json, горячая перезагрузка и т. д.
⚠️: Обратите внимание на требования к надежности пароля: он должен быть не менее 8 символов и содержать как цифры, так и буквы!
Чтобы установить пароль для всего сайта, вам необходимо сначала ввести пароль и убедиться в его правильности, прежде чем вы сможете получить доступ к последующим страницам. Полностью гарантируйте конфиденциальность вашего развернутого сайта, исключите использование неизвестного трафика и удовлетворите потребности небольших кругов в совместном использовании.
⚠️: Обратите внимание на требования к надежности пароля: он должен быть не менее 8 символов и содержать как цифры, так и буквы!
Даодиночень важноизпараметр,правильныйизнастраивать才能让ты部署изPandoraNextвключатьproxyмодель(ты可以Проходить过启动时из В журналеModeда Не включаетproxyсудить)
⚠️: Обратите внимание на требования к надежности пароля: он должен быть не менее 8 символов и содержать как цифры, так и буквы!
у меня тут все едино
"license_id": «Фронт из лицензии»,
"site_password": "yangbuyiya123",
"setup_password": "yangbuyiya123",
"proxy_api_prefix": "yangbuyiya123",
Все приведенные выше конфигурации взяты из config.json. Не заблуждайтесь.
Целью этого файла является доступ к веб-версии /shared.html (общий чатgpt), и его можно использовать напрямую, когда к нему обращаются другие.
Существующая прокси-модельсредида не работает, поэтому вот краткое введение. Если вам интересно, вы можете изучить ее.
существовать tokens.json записать в файл
{
"token1": {
// Он поддерживает несколько токенов, а также поддерживает авторизацию учетной записи и пароля (рекомендуется использовать учетную запись и пароль). например "token": "тыизсчет&пароль"
"token": "access token / session token / refresh token / share token / username & password",
"password": "12345"
}
}
Если вам интересно, вы можете ознакомиться с подробной документацией: https://docs.pandoranext.com/zh-CN/configuration/tokens
На этом наша базовая настройка завершена. Далее мы создадим сервис Pandora.
docker pull pengzhile/pandora-next
Запустив контейнер, мы попадаем на самый внешний слой pandoranext-deploy В каталоге Linux Служить Посудада Так嗷
docker run -d --restart always --name PandoraNext --net=bridge \
-p 8181:8181 \
-v ./data:/data \
-v ./sessions:/root/.cache/PandoraNext \
pengzhile/pandora-next
Даодиниспользовать Docker Запустите программу под названием pengzhile/pandora-next
из контейнера из команды. Команда даэтот объясняется ниже:
docker run
: Да Docker Базовая команда для создания и запуска одного нового контейнера.-d
: Эта опция означает отсоединенную модель (отдельную mode) для запуска контейнера. Это означает, что контейнер будет работать в фоновом режиме, не занимая терминал на переднем плане.--restart always
: Эта опция указывает, что контейнер всегда должен запускаться автоматически при запуске существующейсистемы.,Несмотря на тосуществоватьсистема Даже после перезапускадатаким образом。--name PandoraNext
: эта опция для контейнера указывает одно имя, здесь да PandoraNext
。--net=bridge
: Эта опция указывает, что контейнер будет подключаться к месту проживания. Docker по умолчаниюизмостовая сеть。-p 8181:8181
: этот вариант будет содержать экспорт 8181 Картирование прибытия контейнера в порт 8181. Это означает отправку с хоста в контейнер из 8181 Портиз трафик будет перенаправлен приезжать внутри контейнера из 8181 порт。-v ./data:/data
: этот вариант будет размещаться из ./data
Каталог mount привезти контейнер из /data
Оглавление. Это означает, что внутри контейнера. /data
Любые изменения в каталоге будут отражены на хосте. ./data
в каталоге.-v ./sessions:/root/.cache/PandoraNext
: этот вариант будет размещаться из ./sessions
Каталог mount привезти контейнер из /root/.cache/PandoraNext
Оглавление. Это означает, что внутри контейнера. /root/.cache/PandoraNext
Любые изменения в каталоге будут отражены на хосте. ./sessions
в каталоге.pengzhile/pandora-next
: Да хочу бежать из Docker зеркалоизимя。Таким образом, эта команда создает и запускает файл с именем PandoraNext
контейнер, используя pengzhile/pandora-next
зеркало. Контейнер существует работает в фоновом режиме и запускается автоматически при запуске системы. экспорт контейнера 8181 Порт, сопоставленный с хостом 8181 и внутри контейнера /data
и /root/.cache/PandoraNext
Каталоги монтируются к хосту соответственно. ./data
и ./sessions
Оглавление.
Просто нажмите Enter и дождитесь успешного завершения операции.
Далее мы посещаем PandoraNext Служить IP:8181
ты да Linux Служитьправила использования посудыиспользоватьтыиз IP:порт
⚠️ Служить не забудьте обратиться к поставщику облака Конфигурация группы безопасности для утверждения. 8181 порт
за этим Да输入тыс己из ChatGPT счетипароль Авторизоваться Понятно
После успешного входа вы попадете на главную страницу Моя мама полностью воспроизводит официальную. UI стиль,Записи разговоров тоже сохраняются. Они точно такие же, как и официальные.,唯один Нетодин样из Да Нетнуждаться Маленький самолет прибыл, чтобы отвезти нас туда поиграть.~
Мы можем попытаться поговорить,Тогда диалог и нас поглотит из Квота,Да используется изначально github Вход на сайт
Проверьте сумму: https://dash.pandoranext.com
⚠️ Proxy модель Не поддерживается местныйвызов Переднийизбазовый Конфигурация Всесуществовать linux Служить сторону агрегата Вот и все
Если вы пойдете, чтобы понять ChatGPT из API просить будет знать, что он дануждаться денегиз купить То есть, если мы будем заниматься свободной проституцией, мы будем продолжать заниматься свободной проституцией до конца. PandoraNext Поддержка прямой полной агентской переадресации приезда должностного лица из API нет разницы, вызов только да добавил слой агента посередине, очень гладкий и шелковистый
существоватьпрежде чем мысуществовать config.json который установлен proxy_api_prefix для xxxx Мы используем нуждаться для доступа к официальному сайту через этот API
Предположим, вы используете proxy_api_prefixдля yangbuyiya123
,тыизbindдля 127.0.0.1:8181
则тыизBaseURLдля:http://127.0.0.1:8181/yangbuyiya123
,Да以下Местоиметьинтерфейсизпрефикс
Официальный специфический интерфейс: https://platform.openai.com/docs/api-reference
Мы будем использовать этот интерфейс для работы
использовать IP:8181/proxy_api_prefix Плюс официальный интерфейс /v1/chat/completions
локон http://СлужитьустройствоIP:8181/yangbuyiya123/v1/chat/completions \
-H "Тип контента: приложение/json" \
-H "Авторизация: носитель $OPENAI_API_KEY" \
-д '{
"модель": "gpt-3.5-турбо",
"messages": [{"role": "user", "content": "Скажите, что это тест!"}],
«температура»: 0,7
}'
Вы можете посмотреть, как приезжатьнаша бедность идет получать Authorization token этот token Да access_token
нода PandoraNext Обработано и необходимо сгенерировать PandoraNext из share token смотреть вниз
⚠️ интерфейспотреблятьдля1:100
curl http://СлужитьустройствоIP:8181/yangbuyiya123/api/auth/login' \
-H 'Тип контента: приложение/x-www-form-urlencoded' \
-d 'имя_пользователя=user%40mail.com' \
-d 'пароль=abc123'
Продолжим получать access_token
Возвращаемые параметры: {"access_token":"Выходной токен","token_type":"Носитель"}
curl 'http://127.0.0.1:8181/yangbuyi123/api/token/register' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'unique_name=abcdefg' \
-d 'access_token=eyxxxx' \
-d 'site_limit=https%3A%2F%2Fchat.oaifree.com' \
-d 'expires_in=0' \
-d 'show_conversations=false' \
-d 'show_userinfo=false'
получатьприезжать Понятно Fk token Тогда вы можете запросить его напрямую!!!
Продолжите исследовательскую беседу Модель ChatGPT3.5
вызовуспех! да, нет, да so easy to happy Нравится нарезать овощи?
Итак, дальше мы Да Введите код программированияиз学习Понятно,Подготовить, вы готовы? Поехали~
Честно говоря, я прочитал всего одну-две статьи.,Позвольте мне сначала объяснить, что это такое, исходя из моего собственного понимания.,Босс, не критикуйте меня, просто научите меня в разделе комментариев.,Если что-то не так с из, пожалуйста, дайте мне несколько советов~
Доменно-ориентированный дизайн (англ. Domain-Driven Design) Design, аббревиатура DDD) да Проектирование на основе модели и метод, который собирает знания предметной области через поля Модель, исполь зовать поля Конструкции моделей легче поддерживать, но да DDD Это сложно реализовать да. Оно не имеет единой сущностииз приложения, поэтому. MVC Имеет ряд строгих правил
MVC Датретий этажиз Архитектурас уровня управления(controller) -> Служитьслой(service) -> Уровень взаимодействия данных (Дао) Набор сборочных линий, но мы существуем, сотрудничаем с использованием сложных проектов из сцен, которые мы найдем здесь из ПО, ВО, сущности объектов существуют. Service Длительное взаимодействие между слоями приведет к расширению количества атрибутивных полей и возникнут некоторые проблемы в текущей ситуации. PO по сути бесполезно из поля атрибута, потому что для из Служить это тоже цитировалось PO Возможно, будут добавлены какие-то новые поля атрибутов (просто делаю это иногда для удобства)
DDD Архитектура Решите сначалаэтотвопрос Да属Вс己поле(domain)в пределах досягаемостииз Логически инкапсулируйте это Да DDD Спроектируйте этоизодинточка,подробныйиз Даон надеетсясуществовать分治слой面合理切割вопрос空间дляменьший масштабиз若干子вопрос,Чем меньше проблема, тем легче ее понять и решить.,Сделайте приезжать высокой сплоченностью и низкой связанностью. Об этом также упоминает закон да Конвея.,Решение сложных сценариев и дизайн в основном делятся на: разделяй и властвуй, абстракция и знание.
DDD из Архитектура Модель
Не буду вдаваться в подробности, рекомендую Tencent. DDD Концепции и методы Реконструировано из Tencent Video Архитектура, смотрите DDDиз Концепции и методы Есть также эта статья от брата Сяо Фу. Я также следил за братом Сяо Фу (боссом Цзиндуна), чтобы учиться из этой статьи. От MVC к DDD, как начать рефакторинг?
Приложение ChatGPT и стыковка с публичными аккаунтами для общения в чате
Строительство проекта Новое название проекта yby6PandoraChatGPT
JDK 17 ХОРОШО JDK1.8 Это не имеет значения
общийиз Архитектура Датаким образом
Давайте создадим архитектуру DDD следующим образом.
DDD из Архитектура Модель
Затем загрузите папку «ИнициализацияDDD Архитектура каждого одного поля», чтобы вы могли понять, почему используется каждый уровень да.
Помните, что мы делали раньше Запрос API режима прокси, продолжим использовать apifox Приходите на вызов и получитеотправьте код просить
⚠️ если token Недействительно, пожалуйста, посмотрите каталог
PandoraNex
t Собственная регенерация интерфейса Share token аббревиатура FK
Затем продолжайте сначала отправлять запрос вручную, а затем появится фактическая точка запроса.
Существует множество кодов запросов, которые мы можем просмотреть непосредственно в Java и выполнить их непосредственно для нас.
будет кодироватькопироватьприезжать Юнит-тестсреди Вот и все
Потом я тайно добавил лог просить, а потом импортировал okhttp изполагаться
<!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.12.0</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>logging-interceptor</artifactId>
<version>4.12.0</version>
</dependency>
/**
* Юнит-тест
*/
@SpringBootTest
class Yby6PandoraChatGptApplicationTests {
@Test
void testApi() throws IOException {
// бревно Конфигурация HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
// Создайте, пожалуйста, окhttp клиент
OkHttpClient client = new OkHttpClient().newBuilder()
.addInterceptor(httpLoggingInterceptor)
.build();
MediaType mediaType = MediaType.parse("application/json");
String req = "{\n" +
" \"model\": \"gpt-3.5-turbo\",\n" +
" \"messages\": [\n" +
" {\n" +
" \"role\": \"user\",\n" +
" \"content\": «Привет, я да Ян Буи\"\n" +
" }\n" +
" ],\n" +
" \"temperature\": 0.7,\n" +
" \"stream\": false\n" +
"}";
RequestBody body = RequestBody.create(req, mediaType);
Request request = new Request.Builder()
.url("http://IP:8181/prefix/v1/chat/completions")
.method("POST", body)
.addHeader("Authorization", "Bearer FK token")
.addHeader("Content-Type", "application/json")
.addHeader("Accept", "*/*")
.addHeader("Host", "IP:8181")
.addHeader("Connection", "keep-alive")
.build();
Response response = client.newCall(request).execute();
System.out.println(response.body().string());
}
}
Вы можете видеть, что добраться до точки нам тоже удалось без проблем, в конце концов, да рождается из ха-ха-ха.
Взгляните на возвращаемую структуру данных,сейчассуществоватьмы получаемприезжатьиздаодиннанизай наснуждатьсяруководитьсоздавать Перепискаответ получен,Удобные эксплуатационные свойства,здесь直接 IDEA из плагина GsonFormatPlus
использовать JSON Просто преобразуйте его в класс сущности, и все готово.
{
"id": "chatcmpl-OtyWJeU0gQBFhfyA5XHHv37wRLyNx",
"object": "chat.completion",
"created": 1705425154,
"model": "gpt-3.5-turbo",
"usage": {
"prompt_tokens": 0,
"completion_tokens": 0,
"total_tokens": 0
},
"choices": [
{
"message": {
"role": "assistant",
"content": «Привет, Ян Буи! Чем я могу тебе помочь?»
},
"finish_reason": "stop",
"index": 0
}
]
}
package com.yby6.yby6pandorachatgpt;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* ../
*
* @author Yang Shuai
* Create By 2024/01/17
*/
@Data
public class ChatGPTResponse {
/**
* Удостоверение личности
*/
@JsonProperty("id")
private String id;
/**
* объект
*/
@JsonProperty("object")
private String object;
/**
* создавать
*/
@JsonProperty("created")
private Integer created;
/**
* Модель
*/
@JsonProperty("model")
private String model;
/**
* использование токена
*/
@JsonProperty("usage")
private UsageDTO usage;
/**
* Ответ на сообщение
*/
@JsonProperty("choices")
private List<ChoicesDTO> choices;
@NoArgsConstructor
@Data
public static class UsageDTO {
@JsonProperty("prompt_tokens")
private Integer promptTokens;
@JsonProperty("completion_tokens")
private Integer completionTokens;
@JsonProperty("total_tokens")
private Integer totalTokens;
}
@NoArgsConstructor
@Data
public static class ChoicesDTO {
@JsonProperty("message")
private MessageDTO message;
@JsonProperty("finish_reason")
private String finishReason;
@JsonProperty("index")
private Integer index;
@NoArgsConstructor
@Data
public static class MessageDTO {
@JsonProperty("role")
private String role;
@JsonProperty("content")
private String content;
}
}
}
Нажмите ok Вы можете увидеть это позже, чтобы мы могли следить за ним. JSON Класс сущности генерируется так, чтобы мы могли использовать JSON Чтобы преобразовать сущности в отображение, нам нужно JSON Инструменты для работы, которые мы представляем Java Мощная библиотека инструментов Hutool
<!-- Мощная библиотека инструментов Java. -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.25</version>
</dependency>
Таким образом, мы можем легко управлять данными атрибутов. Вы можете увидеть ответ и сохранить данные в существующем виде. MessageDTO среди прочего, когда мы приезжаем, мы используем это только для возврата в общедоступный аккаунт Вот и вседругойиз Я не имею ничего общего с дождем
~
На данный момент мы завершили самые основные DDD Архитектурное строительство и завершение OkHttp Юнит-тестстыковкауспех,Следующий Да Текстовый ответ на официальный аккаунт WeChat,Иди, иди, иди, позволь мне вести тебя шаг за шагом!
Нажмите на меня, чтобы перейти на платформу общедоступных учетных записей и зарегистрироваться.
Если это применимо к физическим лицам, мы выберем его и зарегистрируем.,Позже мы шаг за шагом проследим логику регистрации.,После завершения создания отсканируйте код Авторизоваться.
Давайте сначала посмотрим на текстовый ответ из документа нуждаться ЧТО Конфигурация параметра
документ: Пассивно отвечать на сообщения пользователей
Когда пользователь отправляет сообщение в официальную учетную запись (или когда определенные действия пользователя вызывают отправку события),произведу один ПОСТпросить,Разработчики могут возвращать определенные XML-структуры в существующем пакете ответов (Get).,ответить на сообщение (теперь поддерживается текст ответа, изображение, графика, голос, видео, музыка). строго говоря,Отправка пассивного ответного сообщения на самом деле не является разновидностью пассивного ответного сообщения.,И да ответил на сообщение, отправленное устройством WeChat Служить один раз.
После существования устройства WeChat Служить отправляет сообщение пользователя на официальный аккаунт разработчика по адресу устройства Служить (Центр разработчиков Конфигурация),Если WeChat Служить существовать не ответит в течение пяти секунд, соединение будет разорвано.,и перезапустить просить,Всего три попытки,еслисуществовать Отладка,Было обнаружено, что пользователь не смог получить ответ на сообщение «Приехать».,Вы можете проверить, истекло ли время обработки сообщения. О повторной попытке сообщения Смещаемый вес,Рекомендуемые новости о msgiduse msgid Смещаемый вес. Рекомендация по сообщению типа событияиспользоватьFromUserName + CreateTime Смещаемый вес
Согласно официальной инструкции, я составил следующую блок-схему.
основной Да Пользователь отправляет сообщениеприезжать Официальный аккаунт,Тогда WeChat последует за нами Конфигурацияиз Служитьустройствоадрес(Подробности позже)посетите насизодин POST интерфейс(сопределение)существоватьполучить внутри xml параметр Просто занимайтесь своим бизнесом
Прежде чем существовать писать код, давайте сделаем все это за один раз.,В любом случае Да这套流程Нет会变死死из就Так操作,Далее, позвольте мне сначала представить, что такое нуждаться в параметре.
⚠️ Потому что для нас нужна локальная отладка,Место以нуждаться Проникнуть через интранетизменятьволосыпроситьприезжатья们местныйиз Служить,Здесь я использую скорлупу арахиса для работы
Далее приступим к настройке публичного аккаунта.
Войдите в официальную панель управления аккаунтом. Нажмите строку меню. Настройка и разработка
получатьоригинальный ID ,отвечатьизкогдануждатьсяиспользоватьприезжать Идентификатор разработчика WeChatэтот Да
копироватьприезжатьпроектсредииз Конфигурационный файл application.yml
# Вичат Официальная конфигурация аккаунта Информация
шх: config:
originalid: Ваш исходный идентификатор
token: token
Войдите в официальную панель управления аккаунтом. Нажмите строку меню. Настройка и разработка
Нажмитебазовый Конфигурация,смотретьpriezzatIspravrativConfiguratsiya edamagn izorzet dotka goin
Просто настройте URL, токен и EncodingAESKey.
URL дасопределениеиз: напримеряиз ip да Публичная сеть IP/wx/gzh/яиз публичной учетной записииз appid
В сети мы заменим нуждаться на наш IP Служить Вот и все
Итак, теперь WeChat использует нашу местную нуждаться. Служить вызовприезжать Здесь я использую скорлупу арахиса, чтобы проникнуть в интранет.
Моё текущее доменное имя: https://34330745e8.picp.vip/ Агент приезжать для местных из 9632 порт 待会я们изпроект Служитьпорт Даэтот,Вы можете изменить его на что-нибудь другое
Затем я начну конфигурацию ниже. Обратите внимание, что все эти конфигурации являются конфиденциальной информацией, не пропустите ее.
Затем мы Нажмите представили,Сообщим об ошибке,Дадля Что?
Дапотому чтодля Вичатнуждаться验证ты Даватьприезжатьизпроситьадресданетвызовиз Проходить,и выполнить проверку внутри,документследующеезаинтересованныйиз可以подробныйсмотретьсмотреть документ: Сообщение о подтверждениеиииз действительно от WeChat
Затем мы непосредственно напишем код общедоступной учетной записи WeChat.
Перейти к проектированию существования DDD Архитектураиз interface
в каталоге Новый WechatController
控制устройство,просить приставку для себя Конфигурацияиз.
После того как разработчик предоставит информацию,WeChat Служить отправит GET проситьприезжать, введите адрес из Служить по URL-адресу.,GET просить CARRY параметр, показанный в следующей таблице:
параметр | описывать |
---|---|
signature | Шифрование WeChatзнак,Подпись объединяет параметр изтокена параметрипросить, параметр из отметки времени и параметр nonce, заполненные разработчиком. |
timestamp | Временная метка |
nonce | случайное число |
echostr | случайная строка |
然назадя们нуждатьсяруководить Проверить знак предотвращает подделку просить,Приведен официальный метод работы.
Разработчики проверяют просить, проверяя подпись (способ проверки указан ниже). Если подтвердится, что этот GET просить пришел с устройства WeChat Служить,Пожалуйста, верните содержимое параметра echostr как есть.,Доступ вступает в силу,Станьте успешным разработчиком,В противном случае доступ невозможен. Процесс шифрования/верификации следующий:
1)Сортировка токена, метки времени и nonce в лексикографическом порядке.
2)Объедините три строки параметров в одну строку для шифрования sha1.
3) После того, как разработчик получит зашифрованную строку, ее можно сравнить с подписью, чтобы определить, что запрос исходит от WeChat.
яздесь Давать大家写好Понятно直接использоватьэтот Приходитьруководить Проверить знак,Не нужно писать вручную,Знай, что есть что-то Вот и все
существовать DDD Архитектурасредииз infrastructure -> util Новый wechat Создайте класс средства проверки подписи в папке
package com.yby6.yby6pandorachatgpt.infrastructure.util.wechat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* Wechat знакutil
*
* @author Yang Shuai
* Create By 2024/01/13
*/
public class WechatSignatureUtil {
private static final Logger logger = LoggerFactory.getLogger(WechatSignatureUtil.class);
/**
* Проверить знак
*/
public static boolean check(String token, String signature, String timestamp, String nonce) {
String[] arr = new String[]{token, timestamp, nonce};
// Сортировка токена, метки времени и nonce в лексикографическом порядке.
sort(arr);
StringBuilder content = new StringBuilder();
for (String s : arr) {
content.append(s);
}
MessageDigest md;
String tmpStr = null;
try {
md = MessageDigest.getInstance("SHA-1");
// Объедините три строки параметров в одну строку для шифрования sha1.
byte[] digest = md.digest(content.toString().getBytes());
tmpStr = byteToStr(digest);
} catch (NoSuchAlgorithmException e) {
logger.error(e.getMessage());
}
// После шифрования sha1 строку «из» можно сравнить с подписью, чтобы указать, что запрос поступил от WeChat.
return tmpStr != null && tmpStr.equals(signature.toUpperCase());
}
/**
* Преобразовать массив байтов в шестнадцатеричную строку
*/
private static String byteToStr(byte[] byteArray) {
StringBuilder strDigest = new StringBuilder();
for (byte b : byteArray) {
strDigest.append(byteToHexStr(b));
}
return strDigest.toString();
}
/**
* Преобразование байтов в шестнадцатеричную строку
*/
private static String byteToHexStr(byte mByte) {
char[] Digit = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
char[] tempArr = new char[2];
tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
tempArr[1] = Digit[mByte & 0X0F];
return new String(tempArr);
}
/**
* Выполнить сортировку по словарю
*/
private static void sort(String[] str) {
for (int i = 0; i < str.length - 1; i++) {
for (int j = i + 1; j < str.length; j++) {
if (str[j].compareTo(str[i]) < 0) {
String temp = str[i];
str[i] = str[j];
str[j] = temp;
}
}
}
}
}
Конфигурация Проверкапараметр Исправлять application.yml Конфигурационный файл
# Вичат Официальная конфигурация аккаунта Информация
шх:config:
originalid: Исходный идентификатор
token: Конфигурация серверавизtoken Просто настройте это
Здесь я также дам вам универсальное руководство. Оно очень простое, его можно прочитать и понять. Мне не нужно, чтобы вы его писали.
package com.yby6.yby6pandorachatgpt.interfaces;
import com.yby6.yby6pandorachatgpt.infrastructure.util.wechat.WechatSignatureUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Yang Shuai
* Create By 2024/1/18
*/
@RestController
@RequestMapping("/chat-api/wx/portal")
public class WechatController {
private final Logger logger = LoggerFactory.getLogger(WechatController.class);
// Служитьустройство Token
@Value("${wx.config.token}")
private String token;
/**
* Обработать сообщение WeChat Служить, отправленное изgetпросить, для проверки знака
*
* <p>
* appid Идентификатор приложения WeChat
* signature Отправлено через WeChat
* timestamp Отправлено через WeChat из Временная метка
* nonce Отправлено через WeChat строка
* echostr Строка подтверждения отправлена из WeChat
*/
@GetMapping(produces = "text/plain;charset=utf-8")
public String validate(
@RequestParam(value = "signature", required = false) String signature,
@RequestParam(value = "timestamp", required = false) String timestamp,
@RequestParam(value = "nonce", required = false) String nonce,
@RequestParam(value = "echostr", required = false) String echostr) {
try {
logger.info("Информация о проверке подписи общедоступной учетной записи WeChat {} начинается [{}, {}, {}]", signature, timestamp, nonce, echostr);
if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) {
throw new IllegalArgumentException("проситьпараметр недопустим, проверьте!");
}
boolean check = WechatSignatureUtil.check(token, signature, timestamp, nonce);
logger.info("Проверка общедоступной учетной записи WeChat: {}", check);
if (!check) {
return null;
}
return echostr;
} catch (Exception e) {
logger.error("Информация о проверке подписи общедоступной учетной записи WeChat{} не удалась [{}, {}, {}]", signature, timestamp, nonce, echostr, e);
return null;
}
}
}
Начать проникновение в интранет、Запустить серверную часть Служить,紧接着яруководить Понятно提交тест Прямая отправка прошла успешно. Проверьте серверную консоль, и она также распечатает подтверждение того, что предыдущий успех был успешным.
Затем включаем нуждаться в сервере, иначе мы не будем получать сообщения, отправленные паблик аккаунтом приезжатьиз
включатьназаднуждатьсяждать待五六分钟,Дайте устройству WeChat Служить немного слабину,Подходит ли мне? Продолжить работу смотреть вниз?
Так что приезжать сюда,В принципе мы это завершили,Прогресс напрямую увеличился на 80%,Следующий就剩下 post Напишем интерфейс шаг за шагом Но как писать? смотреть вниз
Давайте продолжим читать документ, и там сказано, что мы получим к нему доступ. post интерфейс(мы устанавливаем из) А нам ничего не сказал параметр? пока я не увидел XML 数据包那Нет Да字符串嘛那就直接использовать字符串Приходить接收就行
/**
* Здесь да ручки WeChat Служить для пересылки сообщений из
*/
@PostMapping(produces = "application/xml; charset=UTF-8")
public String post(@RequestBody String requestBody) {
logger.info("Получить параметр:{}",requestBody);
return "толькосуществовать开волосы中....";
}
Начните проникновение во внутреннюю сеть, запустите серверную часть Служить, а затем откройте свою собственную общедоступную учетную запись, чтобы отправлять тестовые сообщения серверной части, получать ли параметр прибытия.
⚠️ Конфигурация сервер должен быть включен, иначе вы не сможете получать сообщения о прибытии. 10 Около минут...
Вы можете увидеть приезжать. Я отправил сообщение через официальный аккаунт, и устройство WeChat Служить вернуло один. xmk верни мне, тогда нам нужно xml Проанализируйте и преобразуйте его в нас из Java Bean
Новыйполагаться xstream для картографирования xml поле, оно также имеет функцию да можно Конфигурация restful интерфейс руководитьпроситьвызов,середина Конфигурацияодин Перехватчик注入один些проситьпараметрждать Конфигурация
<!-- Подключитесь к общедоступной учетной записи WeChat, нуждайтесь в анализе xml -->
<!-- https://mvnrepository.com/artifact/com.thoughtworks.xstream/xstream -->
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.20</version>
</dependency>
писать xml Переписка JavaBean ,существовать DDD Архитектурасредииз Domain полеслой Новый Wechat папкаписать MessageTextEntity сущность
package com.yby6.yby6pandorachatgpt.domain.wechat;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Getter;
/**
* Текст ответного сообщения сущность
*
* @author Yang Shuai
* Create By 2024/01/18
*/
@Getter
public class MessageTextEntity {
@XStreamAlias("MsgId")
private String msgId;
@XStreamAlias("ToUserName")
private String toUserName;
@XStreamAlias("FromUserName")
private String fromUserName;
@XStreamAlias("CreateTime")
private String createTime;
@XStreamAlias("MsgType")
private String msgType;
@XStreamAlias("Content")
private String content;
@XStreamAlias("Event")
private String event;
@XStreamAlias("EventKey")
private String eventKey;
public MessageTextEntity() {
}
public void setMsgId(String msgId) {
this.msgId = msgId;
}
public void setToUserName(String toUserName) {
this.toUserName = toUserName;
}
public void setFromUserName(String fromUserName) {
this.fromUserName = fromUserName;
}
public void setCreateTime(String createTime) {
this.createTime = createTime;
}
public void setMsgType(String msgType) {
this.msgType = msgType;
}
public void setContent(String content) {
this.content = content;
}
public void setEvent(String event) {
this.event = event;
}
public void setEventKey(String eventKey) {
this.eventKey = eventKey;
}
}
Тогда мы будем xml Анализ для насиз MessageTextEntity Bean ,существовать DDD Архитектурасредииз Domain продолжать Новый XmlUtil Инструменты
package com.yby6.yby6pandorachatgpt.infrastructure.util.wechat;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.DomDriver;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;
import org.apache.commons.lang3.StringUtils;
import java.io.Writer;
/**
* XmlUtil
*
* @author yangbuyiya
* Create By 2024/01/18
*/
public class XmlUtil {
/**
* расширение xstream, автоматически добавляется bean-компонент, преобразованный в xml [CDATA[]]!
*/
public static XStream getMyXStream() {
return new XStream(new XppDriver() {
@Override
public HierarchicalStreamWriter createWriter(Writer out) {
return new PrettyPrintWriter(out) {
// Добавить тег CDATA во все разделы xml.
final boolean cdata = true;
@Override
public void startNode(String name, Class clazz) {
super.startNode(name, clazz);
}
@Override
protected void writeText(QuickWriter writer, String text) {
if (cdata && !StringUtils.isNumeric(text)) {
writer.write("<![CDATA[");
writer.write(text);
writer.write("]]>");
} else {
writer.write(text);
}
}
};
}
});
}
/**
* Преобразование bean-компонента в формат сообщения WeChat изxml
*/
public static String beanToXml(Object object) {
XStream xStream = getMyXStream();
xStream.alias("xml", object.getClass());
xStream.processAnnotations(object.getClass());
String xml = xStream.toXML(object);
if (!StringUtils.isEmpty(xml)) {
return xml;
} else {
return null;
}
}
/**
* Преобразование xml в общий метод bean-компонента
*/
public static <T> T xmlToBean(String resultXml, Class clazz) {
// XStreamобъектнастраиватьпо умолчанию Защита безопасности,同时настраивать允许издобрый
Поток XStream = новый XStream (новый DomDriver());
XStream.setupDefaultSecurity(поток);
поток.allowTypes(новый класс[]{clazz});
stream.processAnnotations(new Class[]{clazz});
поток.setMode(XStream.NO_REFERENCES);
stream.alias("xml", clazz);
вернуть (T) поток.fromXML(resultXml);
}
}
logger.info("Получить параметр:{}", requestBody);
MessageTextEntity messageTextEntity = XmlUtil.xmlToBean(requestBody, MessageTextEntity.class);
logger.info("Разобрать XML-данные:{}", messageTextEntity);
Затем мы продолжаем тест, чтобы проверить, успешно ли отображается да.
Успешно завершили анализ,Такнаконецодин步Да Пассивно отвечать на сообщения пользователей, Собираемся ниже из XML Вернуться в WeChat и все
Я написал это прямо здесь, так что ничего делать не нужно.
для обеспечения безопасности мы используем сами Конфигурационный файлсредииз Исходный идентификатор
@PostMapping(produces = "application/xml; charset=UTF-8")
public String post(@RequestBody String requestBody) {
logger.info("Получить параметр:{}", requestBody);
MessageTextEntity messageTextEntity = XmlUtil.xmlToBean(requestBody, MessageTextEntity.class);
logger.info("Разобрать XML-данные:{}", messageTextEntity);
// Соберите текстовые ответы
MessageTextEntity res = new MessageTextEntity();
// Аккаунт получателя (получатель приезжатьизOpenID) Да Возьми этоиз FromUserName этотдаресиверизопенид
res.setToUserName(messageTextEntity.getFromUserName());
// Идентификатор разработчика WeChat Да разбирает из ToUserName этотда Идентификатор разработчика WeChat(Исходный идентификатор)
// Но дадля безопасно, мы используем сами Конфигурационный файлсредииз Исходный идентификатор
res.setFromUserName(originalId);
// Время создания сообщения (целочисленный тип)
res.setCreateTime(String.valueOf(System.currentTimeMillis() / 1000L));
// Тип сообщения, текст для текста
res.setMsgType("text");
// Ответ из содержимого сообщения (перенос строк: существующий контент может быть перенесен, а клиент WeChat поддерживает отображение переноса строк)
res.setContent("Что ты делаешь!!!!");
String result = XmlUtil.beanToXml(res);
logger.info("Получить информацию об общедоступной учетной записи WeChat просить завершено {}, openid:{}", result, messageTextEntity.getFromUserName());
return result;
}
Запустите скорлупу арахиса, запустите бэкэнд Служить,существовать общедоступную учетную запись и отправьте сообщение, чтобы узнать, ответил ли да на текстовое сообщение.
Так что приезжать сюдая们就已经完成базовыйиз Это сделано,Следующий Дастыковка ChatGPT Операция вопросов и ответов
я们可以直接把я们Юнит-тестиз OkHttp Запрос на перенос, что эквивалентно завершению ответа на вопросы. Мы можем сначала это продемонстрировать.
Затем проведите тест,Проверьте эффект, включить проникновение в интранет、включатьназад端Служить、тест查смотреть控制台данет输出вызов ChatGPT Возврат изпараметра
На самом деле, это можно сделать здесь, если ваше стремление к совершенству продолжится, смотрите вниз!
Вы можете посмотреть приезжать Мы усовершенствовали интерактивную функцию вопросов и ответов, вам не кажется, что это очень просто? настоящийиз Да Это похоже на нарезку овощей. Хотя так выглядит очень удобно, это требует много производительности. Прежде чем отправить новое сообщение, нам приходится повторно отправлять его. Например:
OkHttpClient client = new OkHttpClient().newBuilder().build();
этотновыйиз OkHttpClient Экземпляр не зависит от предыдущего создателя экземпляра, и они не будут использовать одну и ту же конфигурацию или пул соединений, которые часто создают новые. OkHttpClient Экземпляры могут вызывать проблемы с производительностью, поскольку каждый экземпляр использует собственный пул соединений и пул потоков, что может привести к нерациональной трате ресурсов и снижению производительности.
Итак, мы решаем проблему потребности в этом потенциальном существовании.,использоватьфабрика сеансовмодель,Здесь я ссылка mybatis извыполнить способ,Далее я просто расскажу о раше-раше!
Путь к пакету просмотра исходного кода Mybatis: org.apache.ibatis.session
если вы уже изучали исходный код mybatis, вы это поймете,mybatisизосновной ДаSqlSessionFactory
Вы можете увидеть это только через идею SqlSessionFactory извыполнитьобъектда DefaultSqlSessionFactory и SqlSessionManager
Такя们就Нажмите DefaultSqlSessionFactory Введите исходный код, чтобы увидеть, что он сделал
Осуществленный SqlSessionFactory интерфейс openSession метод Начать сеанс оченьиз Перегрузка
существоватьopenSession методсреди可以смотретьприезжатьвызов openSessionFromDataSource Созданный DefaultSqlSession по умолчаниюизсессия
Итак, давайте продолжим нажимать DefaultSqlSession, чтобы посмотреть, что было сделано?
существовать DefaultSqlSession в Осуществленный SqlSession интерфейсизметод
DefaultSqlSession Это эквивалентно последней функции калибровки из класса, Мой анализ очень прост. Если вам интересно, вы можете посмотреть исходный код.
Следующийя就根据mybatisизфабрика сеансовмодель Приходитьвыполнитьодин
ссылка структура mybatis, первое определение выходит из существования, чтобы увидеть специфику отношений
существовать外слой Новый session Папки представляют функции сеанса
/**
* Фабрика сессий OpenAI
*
* @author yangs
* @date 2024/01/18
*/
public interface OpenAiSessionFactory {
/**
* Начать сеанс
*
* @return {@link OpenAiSession}
*/
OpenAiSession openSession();
}
проситьпараметрстроитьссылкачиновникизпросить
я已经для大家搞好Понятно Не нужно делать это самому
package com.yby6.yby6pandorachatgpt.domain.chatgpt;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.*;
import lombok.extern.slf4j.Slf4j;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
/**
* Модель строителя строитьпроситьинформация * проситьинформация依照;OpenAIОфициальный сайтAPIстроитьпараметр;<a href="https://platform.openai.com/playground">...</a>
*
* @author yangs
* @date 2024/01/18
*/
@Data
@Builder
@Slf4j
@JsonInclude(JsonInclude.Include.NON_NULL)
@NoArgsConstructor
@AllArgsConstructor
public class ChatGPTRequest implements Serializable {
/**
* По умолчанию Модель
*/
private String model = Model.GPT_3_5_TURBO.getCode();
/**
* вопросописывать */
private List<ChatGPTResponse.ChoicesDTO.MessageDTO> messages;
/**
* Контролировать температуру [случайность] между 0приезжать2. Более высокие значения (например, 0,8) сделают вывод более случайным, а более низкие значения (например, 0,2) сделают вывод более целенаправленным и детерминированным.
*/
private double temperature = 0.2;
/**
* Контроль разнообразия; использовать выборку температуры из альтернативного метода, называемого для отбора проб керна, где Модель рассматривается с массой вероятности top_p из токенов из результатов. Следовательно, 0,1 означает только рассмотрение перед включением 10% Вероятностная масса из токена
*/
@JsonProperty("top_p")
private Double topP = 1d;
/**
* для Число завершений, созданных для каждого запроса из
*/
private Integer n = 1;
/**
* данетдля Потоковый вывод;Даодин蹦один蹦из,出Приходить结果
*/
private boolean stream = false;
/**
* Флаг остановки вывода
*/
private List<String> stop;
/**
* Ограничение выходной строки 0; ~ 4096
*/
@JsonProperty("max_tokens")
private Integer maxTokens = 2048;
/**
* Штраф за частоту уменьшает вероятность повторения одной и той же строки Моделью;
*/
@JsonProperty("frequency_penalty")
private double frequencyPenalty = 0;
/**
* сохранить наказание; улучшить модель возможность говорить на новые темы из
*/
@JsonProperty("presence_penalty")
private double presencePenalty = 0;
/**
* Генерируйте несколько результатов вызовов и показывайте только лучшие из них. Это поглотит вас больше api token
*/
@JsonProperty("logit_bias")
private Map logitBias;
/**
* логотип вызова, чтобы избежать дублирования вызова
*/
private String user;
@Getter
@AllArgsConstructor
public enum Model {
/**
* gpt-3.5-turbo
*/
GPT_3_5_TURBO("gpt-3.5-turbo"),
/**
* GPT4.0
*/
GPT_4("gpt-4"),
/**
* GPT4.0 Очень длинный контекст
*/
GPT_4_32K("gpt-4-32k"),
;
private final String code;
}
}
package com.yby6.yby6pandorachatgpt.session;
import com.yby6.yby6pandorachatgpt.domain.chatgpt.ChatGPTRequest;
import com.yby6.yby6pandorachatgpt.domain.chatgpt.ChatGPTResponse;
/**
* OpenAi сессияинтерфейс *
* @author yangs
* @date 2024/01/11
*/
public interface OpenAiSession {
/**
* по умолчанию GPT-3.5 Модель вопросов и ответов
*
* @param chatGPTRequest проситьинформация * @return Возврат результатов
*/
ChatGPTResponse completions(ChatGPTRequest chatGPTRequest);
}
Давайте посмотрим mybatis структурная ручкапо умолчаниюиз单独管理起Приходить Мы тоже Новыйодин defaults папка
Новый DefaultOpenAiSessionFactory Класс реализации Реализация openSession метод Функция здесьиз Да Приходить管理сессиявключать
Реализация openSession метод Функция, Функция метода используется для сборки okhttp просить создавать API Служить Создать сеанс по По умолчанию возвращается единообразно, так что мы открываем только одну сессию Вот и всеизбегать повторенийсоздавать okhttp просить, Идея заключается в следующем
я们首先выполнить строить OkHttpClient и его нужно перехватить okhttp изпросить Даватьпросить Новый Аутентификацияждатьодин些проситьпараметр
Новый OpenAiInterceptor OkHttp просить Перехватчик
существоватьinfrastructure(инфраструктура)среди Новый interceptor папка Новый OpenAiInterceptor Перехватчик
нуждаться open Session Передать APIKey использовать Встроитьпросить Аутентификацияпараметр
package com.yby6.yby6pandorachatgpt.infrastructure.interceptor;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.ContentType;
import cn.hutool.http.Header;
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
/**
* сопределение OpenAI Перехватчик
*
* @author yangs
* @date 2024/01/18
*/
public class OpenAiInterceptor implements Interceptor {
/**
* OpenAi apiKey нуждатьсясуществовать Официальный сайт申请 */
private final String apiKey;
public OpenAiInterceptor(String apiKey) {
this.apiKey = apiKey;
}
/**
* Перехват окhttpпросить
* @param chain цепь
* @return да Нет, чтобы продолжить выполнение
*/
@NotNull
@Override
public Response intercept(Chain chain) throws IOException {
return chain.proceed(this.auth(apiKey, chain.request()));
}
/**
* строить Сертификацияпроситьобъект
*
* @param apiKey ключ API
* @param original сначала
* @return {@link Request}
*/
private Request auth(String apiKey,Запросить оригинал) {
HttpUrl.Builder builder = original.url().newBuilder();
// построить новыйпросить адрес
HttpUrl URL = builder.build();
// создатьпросить
вернуть оригинал.newBuilder()
.url(url.url())
.header(Header.AUTHORIZATION.getValue(), "Bearer " + apiKey)
.header(Header.CONTENT_TYPE.getValue(), ContentType.JSON.getValue())
.method(original.method(), original.body())
.build();
}
}
строить OkHttpClient И добавьте Перехватчик Конфигурацияпроситьпараметр
Базовая из Конфигурация Написание завершено,Следующий Даписать создавать API просить Служить, я们нуждатьсяиспользовать Retrofit 2 сотрудничать OKHTTP Тогда я представлю это подробно дальше Retrofit 2 Что такое да и его основное использование?
Retrofit2 даодин используется для Android и Java из Тип безопасностииз HTTP Клиент, он может легко восстановить RESTful API извызов
github адрес: https://github.com/square/retrofit
чиновникдокументиспользоватьметод адрес: https://square.github.io/retrofit/
Введение зависимости Retrofit2
<!-- http api изменять Java интерфейс -->
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>retrofit</artifactId>
<version>2.9.0</version>
</dependency>
<!-- Для сериализации -->
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>converter-jackson</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>adapter-rxjava2</artifactId>
<version>2.9.0</version>
</dependency>
Согласно вышеизложенномуизкартинасредиопределение Понятно GithubService интерфейс Мы тоже определение OpenAiService интерфейс ,существовать DDDАрхитектурасредииз应использоватьслой Новыйинтерфейс
/**
* ChatGPT проситьинтерфейс API
* Официальный сайт:<a href="https://platform.openai.com/playground">...</a>
*
* @author Yang Shuai
* Create By 2024/1/19
*/
public interface OpenAiService {
/**
* по умолчанию GPT-3.5 Модель вопросов и ответов
*
* @param chatGPTRequest проситьинформация * @return Возврат результатов
*/
@POST("v1/chat/completions")
Call<ChatGPTResponse> completions(@Body ChatGPTRequest chatGPTRequest);
}
/**
* Начать сеанс
*
* @return {@link OpenAiSession}
*/
@Override
public OpenAiSession openSession() {
// 1. бревно Конфигурация HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.NONE);
logger.info("OpenAi API Client Start");
// 2. включать Http клиент
OkHttpClient okHttpClient = new OkHttpClient
.Builder()
.addInterceptor(httpLoggingInterceptor)
.addInterceptor(new OpenAiInterceptor("youизapi key"))
.connectTimeout(450, TimeUnit.SECONDS)
.writeTimeout(450, TimeUnit.SECONDS)
.readTimeout(450, TimeUnit.SECONDS)
.build();
// 3. создавать API Служить
final Retrofit retrofit = new Retrofit.Builder()
.baseUrl("IP") // Вы из Pandora получаете доступ по IP
.client(okHttpClient)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(JacksonConverterFactory.create())
.build();
// создаватьпереписыватьсяпросить API
final OpenAiService openAiService = retrofit.create(OpenAiService.class);
// 传递Даватьпо умолчаниювыполнитьруководить触волосыпроситьвызов
return new DefaultOpenAiSession(openAiService);
}
ok инициализирован openSession писать完毕Следующий Давыполнитьпо умолчаниюизсессия支持,Долженметодсреди Даруководить业务слойвызовлогика обработки вещей(相当В service)
создаватьодинпо умолчаниюизсессия Приходитьвыполнить OpenAiSession интерфейсметодпоставлятьпроситьвызов
и положить session папкаall mobileприезжать domain , session Должен принадлежать domian Уровень домена корректирует бизнес
выполнитьпроситьволосы起
/**
* по умолчаниюиз OpenAI сессиявыполнитьOpenAiSession *
* @author Yang Shuai
* Create By 2024/1/19
*/
@RequiredArgsConstructor
public class DefaultOpenAiSession implements OpenAiSession {
private final OpenAiService openAiService;
/**
* по умолчанию GPT-3.5 Модель вопросов и ответов
*
* @param chatGPTRequest проситьинформация * @return Возврат результатов
*/
@Override
public ChatGPTResponse completions(ChatGPTRequest chatGPTRequest) throws IOException {
return openAiService.completions(chatGPTRequest).execute().body();
}
}
/**
* @author Yang Shuai
* {@code @create} 2024/1/16:17:48
* {@code @desc} |
**/
@Configuration
@RequiredArgsConstructor
public class initializeOpenAISession {
private final Logger logger = LoggerFactory.getLogger(initializeOpenAISession.class);
/**
* создание фабрики разговоров
*/
@Bean("openAiSession")
public OpenAiSession openAiSession() {
logger.info("инициализацияпросить Конфигурационный файл");
// 2. фабрика сеансов
OpenAiSessionFactory factory = new DefaultOpenAiSessionFactory();
// 3. Начать сеанс
logger.info("Начать сеанс openAiSession");
return factory.openSession();
}
}
существовать messageDto среди Новый Понятно Модель строителя
@NoArgsConstructor
@Data
public static class MessageDTO {
@JsonProperty("role")
private String role;
@JsonProperty("content")
private String content;
/**
* Конструктор создать роль, содержание
*/
private MessageDTO(MessageDTO.Builder builder) {
this.role = builder.role;
this.content = builder.content;
}
public static MessageDTO.Builder builder() {
return new MessageDTO.Builder();
}
/**
* Модель строителя
*/
public static final class Builder {
private String role;
private String content;
public Builder() {
}
public MessageDTO.Builder role(Constants.Role role) {
this.role = role.getCode();
return this;
}
public MessageDTO.Builder content(String content) {
this.content = content;
return this;
}
public MessageDTO build() {
return new MessageDTO(this);
}
}
}
Новый常量добрый Constants определениепросить Роль
/**
* 公использовать基础использоватьобъект
*/
public class Constants {
/**
* Роль
* Официальный сайт支持изпросить Рольдобрый型;system、user、assistant
* <a href="https://platform.openai.com/docs/guides/chat/introduction">...</a>
*/
@Getter
public enum Role {
/**
* система
*/
SYSTEM("system"),/**
* использовать者 */
USER("user"),
/**
* помощник
*/
ASSISTANT("assistant"),
;
/**
* пароль
*/
private final String code;
/**
* Роль
*
* @param code пароль
*/
Role(String code) {
this.code = code;
}
}
}
Вы можете удалить код sendChatGPT.
включатьпроникновение в интранет、включатьназад端Служить,тест Retrofit данетвызовуспех
Раннее утро 2 точка 30 Я так устала. Смотрите приезжать сюда. Пожалуйста, поставьте мне лайк и поддержите! Спасибо
ok, Теперь существовать и все готово! so easy to happy Это действительно похоже на нарезку овощей
Раннее утро 2 точка 30 Я так устала. Смотрите приезжать сюда. Пожалуйста, поставьте мне лайк и поддержите! Спасибо
Не думай, что это конец, Хотя да в настоящее время может быть нормальным, да если спрашивает обо всем GPT отвечатьиз很慢超过Понятно Вичатотвечатьиз На этапе повтора будет сообщено об ошибке.,Тогда вот корректировка нуждатьсясуществовать,Но это также очень просто,существоватьместный Новыйодинкэш,кэшсредируководить保存任务Future<String>,эти задачи управляются пулом потоков,После выполнения задачи возвращается строковый результат. Однако во время выполнения дасуществовать может возникнуть тайм-аут WeChat, поэтому мы нуждаемся в определении того, превысило ли да. WeChat повторяет попытку в общей сложности три раза по пять секунд каждый раз. Если количество повторений превысит три раза, пользователь будет возвращен, чтобы позволить ему ввести любой текст и продолжить предыдущую операцию.,Это как войти снова,Когда это существование определяет, что проблемная задача существуетэтот уже сохранена в одном слое, новая задача не будет ждать завершения предыдущей задачи и ее возврата пользователю.
🌊 сосредоточиться Я не растерялся. Если эта статья вам полезна, или если у вас есть какие-либо вопросы, оставьте сообщение в области комментариев. Я обычно отвечаю после прочтения. Всем пожалуйста поставьте лайк и поддержите~ 💗
картина