"Что? У вас еще нет своего 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из Концепции и методы Также есть статья брата Сяо Фу. Я также следил за братом Сяо Фу (руководителем JD.com), чтобы учиться из этой статьи. От 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 повторяет попытку в общей сложности три раза по пять секунд каждый раз. Если оно превысит три раза, он вернется к пользователю и попросит его ввести любой текст и продолжить предыдущую операцию.,Это как войти снова,Когда это существование определяет, что проблемная задача существуетэтот уже сохранена в одном слое, новая задача не будет ждать, пока предыдущая задача не будет завершена и возвращена пользователю.
🌊 сосредоточиться Я не растерялся. Если эта статья вам полезна, или если у вас есть какие-либо вопросы, оставьте сообщение в области комментариев. Я обычно отвечаю после прочтения. Всем пожалуйста поставьте лайк и поддержите~ 💗
картина