Writing documentation
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Struchkov Mark 2023-03-15 22:55:51 +03:00
parent 818c0e595f
commit 5decc2b675
Signed by: upagge
GPG Key ID: D3018BE7BA428CA6
10 changed files with 422 additions and 10 deletions

View File

@ -0,0 +1,85 @@
---
title: Personal ChatGPT Telegram Bot
hide:
- navigation
---
# Personal ChatGPT Telegram Bot
> Introducing the ultimate AI-powered chatbot for Telegram - the perfect companion for anyone looking for quick, accurate answers to their questions. Our bot uses state-of-the-art machine learning technology powered by the ChatGPT model, allowing it to understand natural language inputs and respond with human-like precision.
>
> With our bot, you can ask anything you want, from simple queries to complex questions. Whether you're looking for information on the latest news, need help with a math problem, or just want to chat with a virtual friend, our bot has you covered.
>
> What's more, our bot is designed to be easy to use and user-friendly. Simply type in your question or query, and the bot will do the rest, providing you with a quick and accurate response in seconds. No more scrolling through endless search results or struggling to find the information you need - our bot does all the hard work for you.
>
> So why wait? Try out our ChatGPT-powered Telegram bot today and experience the future of AI-powered chatbots for yourself!
>
> (с) Generated by ChatGPT
But seriously, the project uses your ChatGPT token to access the ChatGPT API and let you chat with ChatGPT directly in Telegram.
## Work example
## Privacy
See my last name in the domain? [I'm a developer](https://mark.struchkov.dev), [blogger](https://struchkov.dev/blog/ru/), and publicly active. I don't have the benefit of getting dirty under my own name. I assure you that your data is not transferred to third parties, even I do not know about your requests to ChatGPT. You can see for yourself by examining the code, it's opensource.
## Preparing
* You must have [Docker installed](https://docs.docker.com/engine/install/). You can run the project both on the PC and on the server.
* You must [register a bot in Telegram](https://t.me/BotFather) and get an access token.
* You also need [ChatGPT access token](https://platform.openai.com/account/api-keys).
* You must know your telegramId. [You can find it out here.](https://t.me/myidbot).
## Docker Run
``` bash
docker run --name chatgpt-telegram-bot upagge/chatgpt-telegram-bot:develop \
-e TELEGRAM_BOT_TOKEN= \
-e TELEGRAM_BOT_USERNAME= \ # (1)!
-e TELEGRAM_PERSON_ID= \
-e CHAT_GPT_TOKEN=
```
1. Specify a name with the ending bot here, not a public name.
### Telegram Proxy
If you have Telegram blocked, you can specify proxy settings to connect.
``` bash
docker run --name chatgpt-telegram-bot upagge/chatgpt-telegram-bot:develop \
-e TELEGRAM_BOT_TOKEN= \
-e TELEGRAM_BOT_USERNAME= \
-e TELEGRAM_PERSON_ID= \
-e CHAT_GPT_TOKEN= \
-e TELEGRAM_PROXY_ENABLE=true \
-e TELEGRAM_PROXY_HOST= \
-e TELEGRAM_PROXY_PORT= \
-e TELEGRAM_PROXY_TYPE=SOCKS5 \ # (1)!
-e TELEGRAM_PROXY_USERNAME= \ # (2)!
-e TELEGRAM_PROXY_PASSWORD= # (2)!
```
1. Available options `SOCKS5`, `SOCKS4`, `HTTP`.
2. Optional. If there is no authorization, you can leave it blank.
## :heart:{ .heart } Support Develop
Sponsorship makes a project sustainable because it pays for the time of the maintainers of that project, a very scarce resource that is spent on developing new features, fixing bugs, improving stability, solving problems, and general support. The biggest bottleneck in Open Source is time.
- Bank card for residents of the Russian Federation: [https://www.tinkoff.ru/cf/4iU6NB3uzqx](https://www.tinkoff.ru/cf/4iU6NB3uzqx)
- Crypto:
* TON: `struchkov-mark.ton`
* BTC (Taproot): `bc1pt49vnp43c4mktk6309zlq3020dzd0p89gc8d90zzn4sgjvck56xs0t86vy`
* ETH: `0x7668C802Bd71Be965671D4Bbb1AD90C7f7f32921`
* USDT (ERC-20): `0x7668C802Bd71Be965671D4Bbb1AD90C7f7f32921`
* DAI (ERC-20): `0x7668C802Bd71Be965671D4Bbb1AD90C7f7f32921`
* BNB: `0xDa41aC95f606850f2E01ba775e521Cd385AA7D03`
* USD: `0xDa41aC95f606850f2E01ba775e521Cd385AA7D03`
* DAI: `0xDa41aC95f606850f2E01ba775e521Cd385AA7D03`
## FAQ
??? question "What model is used?"
For now the `gpt-3.5-turbo` model is used. In future versions you will be able to choose the model.

View File

@ -0,0 +1,77 @@
.md-typeset .admonition, .md-typeset details {
font-size: 0.75rem;
}
.md-typeset h1, .md-typeset h2 {
font-weight: 500;
}
.md-typeset h2 {
margin-top: 4rem;
}
.md-typeset h3 {
margin-top: 2.2rem;
}
.md-typeset mark {
background-color: #fff3bc;
margin: -4px -4px -6px;
padding: 4px 4px 6px;
}
@keyframes heart {
0%, 40%, 80%, 100% {
transform: scale(1);
}
20%, 60% {
transform: scale(1.15);
}
}
.heart {
animation: heart 1000ms infinite;
}
@keyframes ninja-disappear {
0% {
opacity: 1;
}
50% {
opacity: 0.3;
}
100% {
opacity: 1;
}
}
.ninja-disappear {
animation: ninja-disappear 3000ms infinite;
animation-delay: 1500ms;
}
@keyframes jingle-bell-swing {
0% {
transform: rotate(0deg);
}
50% {
transform: rotate(10deg);
}
100% {
transform: rotate(0deg);
}
}
.jingle-bell {
animation: jingle-bell-swing 2s ease-in-out infinite;
transform-origin: center;
}
@media(min-width: 768px) {
.frontpage-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
column-gap: 2em;
row-gap: 1em;
}
}

119
documentation/en/mkdocs.yml Normal file
View File

@ -0,0 +1,119 @@
site_name: ChatGPT Telegram Bot
site_url: https://docs.struchkov.dev/chatgpt-telegram-bot/en
repo_url: https://github.com/uPagge/openai-chatgpt-telegram-bot
repo_name: uPagge/openai-chatgpt-telegram-bot
#edit_uri: edit/master/documentation/docs
nav:
- Home:
- index.md
theme:
name: material
custom_dir: overrides
language: en
# favicon: assets/favicon.ico
icon:
logo: simple/openai
repo: fontawesome/brands/github
palette:
- media: "(prefers-color-scheme)"
primary: deep purple
accent: indigo
scheme: default
toggle:
icon: material/brightness-auto
name: Switch to light mode
- media: "(prefers-color-scheme: light)"
primary: deep purple
accent: indigo
toggle:
icon: material/brightness-7
name: Switch to dark mode
- media: "(prefers-color-scheme: dark)"
scheme: slate
toggle:
icon: material/brightness-4
name: Switch to system preference
features:
- navigation.instant
- navigation.indexes
- navigation.sections
- navigation.tracking
- navigation.footer
- navigation.tabs.sticky
- navigation.prune
# - search
# - search.suggest
# - search.highlight
# - content.action.edit
- content.code.copy
- content.code.annotate
- content.tooltips
- toc.follow
# - toc.integrate
plugins:
- social
- typeset
# - blog:
# blog_toc: true
# post_date_format: short
# post_url_format: "{slug}"
# archive_toc: true
# categories: false
# authors: false
# - optimize:
# optimize_jpg_quality: 90
# - tags
# - search:
# lang: ru
markdown_extensions:
- pymdownx.details
- pymdownx.superfences
- pymdownx.inlinehilite
- pymdownx.snippets:
auto_append:
- includes/abbreviations.md
- pymdownx.critic
- pymdownx.caret
- pymdownx.keys
- pymdownx.mark
- pymdownx.tilde
- attr_list
- def_list
- pymdownx.tasklist:
custom_checkbox: true
- pymdownx.highlight:
anchor_linenums: true
line_spans: __span
pygments_lang_class: true
- pymdownx.tabbed:
alternate_style: true
- pymdownx.emoji:
emoji_index: !!python/name:materialx.emoji.twemoji
emoji_generator: !!python/name:materialx.emoji.to_svg
- admonition
- abbr
- md_in_html
- footnotes
- toc:
toc_depth: 3
title: Table of content
permalink: ⚓︎
extra_css:
- stylesheets/extra.css
extra:
generator: false
analytics:
provider: custom
property: foobar
version:
provider: mike
# alternate:
# - name: Русский
# link: /ru/
# lang: ru

View File

@ -0,0 +1,17 @@
{% if "comments" in page.meta.hide %}
{% else %}
<h2 id="__comments" >{{ lang.t("meta.comments") }}</h2>
<div id="remark42"></div>
<script>
var remark_config = {
host: "https://comments.struchkov.dev",
site_id: 'docs',
components: ['embed'],
locale: 'en',
theme: localStorage.theme,
show_email_subscription: true,
simple_view: false
};
</script>
<script>!function(e,n){for(var o=0;o<e.length;o++){var r=n.createElement("script"),c=".js",d=n.head||n.body;"noModule"in r?(r.type="module",c=".mjs"):r.async=!0,r.defer=!0,r.src=remark_config.host+"/web/"+e[o]+c,d.appendChild(r)}}(remark_config.components||["embed"],document);</script>
{% endif %}

View File

@ -0,0 +1,16 @@
<!-- Yandex.Metrika counter -->
<script type="text/javascript" >
(function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
m[i].l=1*new Date();
for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }}
k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})
(window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym");
ym(92567341, "init", {
clickmap:true,
trackLinks:true,
accurateTrackBounce:true
});
</script>
<noscript><div><img src="https://mc.yandex.ru/watch/92567215" style="position:absolute; left:-9999px;" alt="" /></div></noscript>
<!-- /Yandex.Metrika counter -->

View File

@ -6,12 +6,14 @@ import dev.struchkov.example.bot.util.UnitName;
import dev.struchkov.godfather.main.domain.annotation.Unit;
import dev.struchkov.godfather.main.domain.content.Attachment;
import dev.struchkov.godfather.main.domain.content.Mail;
import dev.struchkov.godfather.main.domain.keyboard.button.SimpleButton;
import dev.struchkov.godfather.simple.domain.BoxAnswer;
import dev.struchkov.godfather.simple.domain.unit.AnswerText;
import dev.struchkov.godfather.telegram.domain.ChatAction;
import dev.struchkov.godfather.telegram.domain.ClientBotCommand;
import dev.struchkov.godfather.telegram.domain.attachment.ButtonClickAttachment;
import dev.struchkov.godfather.telegram.domain.attachment.CommandAttachment;
import dev.struchkov.godfather.telegram.domain.keyboard.InlineKeyBoard;
import dev.struchkov.godfather.telegram.main.context.MailPayload;
import dev.struchkov.godfather.telegram.main.core.util.Attachments;
import dev.struchkov.godfather.telegram.simple.context.service.TelegramSending;
@ -29,6 +31,7 @@ import dev.struchkov.openai.domain.response.GptResponse;
import jakarta.annotation.PostConstruct;
import org.springframework.stereotype.Component;
import java.text.MessageFormat;
import java.util.List;
import java.util.Optional;
@ -36,6 +39,7 @@ import static dev.struchkov.example.bot.util.UnitName.CLEAR_CONTEXT;
import static dev.struchkov.example.bot.util.UnitName.GPT_UNIT;
import static dev.struchkov.godfather.simple.domain.BoxAnswer.boxAnswer;
import static dev.struchkov.godfather.simple.domain.BoxAnswer.replaceBoxAnswer;
import static dev.struchkov.godfather.telegram.main.context.BoxAnswerPayload.DISABLE_WEB_PAGE_PREVIEW;
@Component
public class PersonalChatGPTUnit implements PersonUnitConfiguration {
@ -108,7 +112,15 @@ public class PersonalChatGPTUnit implements PersonUnitConfiguration {
@Unit(value = GPT_UNIT, main = true)
public AnswerText<Mail> chatGpt() {
return AnswerText.<Mail>builder()
.triggerCheck(mail -> mail.getFromPersonId().equals(appProperty.getTelegramId()))
.triggerCheck(mail -> {
if (mail.getFromPersonId().equals(appProperty.getTelegramId())) {
final Optional<CommandAttachment> firstCommand = Attachments.findFirstCommand(mail.getAttachments());
if (firstCommand.isPresent()) {
return !firstCommand.get().getCommandType().equals("/start");
}
}
return false;
})
.answer(message -> {
telegramService.executeAction(message.getFromPersonId(), ChatAction.TYPING);
@ -157,6 +169,44 @@ public class PersonalChatGPTUnit implements PersonUnitConfiguration {
.build();
}
@Unit(value = UnitName.START, main = true)
public AnswerText<Mail> startMessage() {
return AnswerText.<Mail>builder()
.triggerCheck(
mail -> {
if (mail.getFromPersonId().equals(appProperty.getTelegramId())) {
final List<Attachment> attachments = mail.getAttachments();
final Optional<CommandAttachment> optCommand = Attachments.findFirstCommand(attachments);
if (optCommand.isPresent()) {
final CommandAttachment command = optCommand.get();
return Cmd.START.equals(command.getCommandType());
}
}
return false;
}
)
.answer(message -> {
return BoxAnswer.builder()
.message(MessageFormat.format(
"""
Hello 👋
Your personal ChatGPT bot has been successfully launched.
Use the help command to find out about the possibilities 🚀
-- -- -- -- --
🤘 Version: {0}
👨💻 Developer: [Struchkov Mark](https://mark.struchkov.dev/)
💊 Docs: https://docs.struchkov.dev/chatgpt-telegram-bot
""",
appProperty.getVersion()
))
.keyBoard(InlineKeyBoard.inlineKeyBoard(SimpleButton.simpleButton("❤️ Support Develop", "support")))
.payload(DISABLE_WEB_PAGE_PREVIEW, true)
.build();
})
.build();
}
@Unit(value = UnitName.PROMPT, main = true)
public AnswerText<Mail> prompt() {
return AnswerText.<Mail>builder()
@ -222,6 +272,8 @@ public class PersonalChatGPTUnit implements PersonUnitConfiguration {
Sponsorship makes a project sustainable because it pays for the time of the maintainers of that project, a very scarce resource that is spent on developing new features, fixing bugs, improving stability, solving problems, and general support. *The biggest bottleneck in Open Source is time.*
Bank card (Russia): [https://www.tinkoff.ru/cf/4iU6NB3uzqx](https://www.tinkoff.ru/cf/4iU6NB3uzqx)
TON: `struchkov-mark.ton`
BTC:

View File

@ -3,21 +3,33 @@ package dev.struchkov.example.bot.unit;
import dev.struchkov.example.bot.conf.AppProperty;
import dev.struchkov.godfather.main.domain.keyboard.button.SimpleButton;
import dev.struchkov.godfather.simple.domain.BoxAnswer;
import dev.struchkov.godfather.simple.domain.SentBox;
import dev.struchkov.godfather.telegram.domain.keyboard.InlineKeyBoard;
import dev.struchkov.godfather.telegram.simple.context.service.TelegramSending;
import dev.struchkov.godfather.telegram.simple.context.service.TelegramService;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.springframework.stereotype.Component;
import java.text.MessageFormat;
import java.util.Optional;
import static dev.struchkov.godfather.telegram.main.context.BoxAnswerPayload.DISABLE_WEB_PAGE_PREVIEW;
import static dev.struchkov.haiti.utils.Checker.checkNotBlank;
@Slf4j
@Component
@RequiredArgsConstructor
public class StartNotify {
private final OkHttpClient client = new OkHttpClient();
private final TelegramSending sending;
private final TelegramService telegramService;
private final AppProperty appProperty;
@PostConstruct
@ -31,7 +43,7 @@ public class StartNotify {
Use the help command to find out about the possibilities 🚀
-- -- -- -- --
🤘 Version: {0}
👨💻 Developer: [https://mark.struchkov.dev/](Struchkov Mark)
👨💻 Developer: [Struchkov Mark](https://mark.struchkov.dev/)
💊 Docs: https://docs.struchkov.dev/chatgpt-telegram-bot
""",
appProperty.getVersion()
@ -41,6 +53,36 @@ public class StartNotify {
.build();
boxAnswer.setRecipientIfNull(appProperty.getTelegramId());
sending.send(boxAnswer);
sendNotice();
}
/**
* Используется для уведомления пользователя о выходе новой версии.
*/
private void sendNotice() {
final String requestUrl = "https://metrika.struchkov.dev/gitlab-notify/start-notice/chatgpt?version=" + appProperty.getVersion();
final Request request = new Request.Builder().get().url(requestUrl).build();
try {
final Response response = client.newCall(request).execute();
if (response.code() == 200) {
final String noticeMessage = response.body().string();
if (checkNotBlank(noticeMessage)) {
final BoxAnswer notice = BoxAnswer.builder()
.message(noticeMessage)
.recipientPersonId(appProperty.getTelegramId())
.payload(DISABLE_WEB_PAGE_PREVIEW, true)
.build();
final Optional<SentBox> optSentBox = sending.send(notice);
if (optSentBox.isPresent()) {
final SentBox sentBox = optSentBox.get();
final String messageId = sentBox.getMessageId();
telegramService.pinMessage(appProperty.getTelegramId(), messageId);
}
}
}
} catch (Exception e) {
log.warn(e.getMessage());
}
}
}

View File

@ -10,5 +10,6 @@ public class Cmd {
public static final String GPT = "gpt";
public static final String HELP = "help";
public static final String SUPPORT_DEV = "support";
public static final String START = "start";
}

View File

@ -10,7 +10,8 @@ public class UnitName {
public static final String HELP = "HELP";
public static final String PROMPT = "PROMPT";
public static final String ACCESS_ERROR = "ACCESS_ERROR";
public static final String SUPPORT = "SUPPORT";
public static final String START = "START";
}

View File

@ -1,16 +1,18 @@
app:
telegram-id: ${TELEGRAM_ID}
telegram-id: ${TELEGRAM_PERSON_ID}
version: 0.0.1-SNAPShOT
telegram:
bot:
username: ${TELEGRAM_BOT_USERNAME}
token: ${TELEGRAM_BOT_TOKEN}
autoresponder:
threads: ${AUTORESPONDER_THREADS:8}
proxy:
enable: ${PROXY_ENABLE:false}
host: ${PROXY_HOST:}
port: ${PROXY_PORT:}
type: ${PROXY_TYPE:SOCKS5}
user: ${PROXY_USERNAME:}
password: ${PROXY_PASSWORD:}
enable: ${TELEGRAM_PROXY_ENABLE:false}
host: ${TELEGRAM_PROXY_HOST:}
port: ${TELEGRAM_PROXY_PORT:}
type: ${TELEGRAM_PROXY_TYPE:SOCKS5}
user: ${TELEGRAM_PROXY_USERNAME:}
password: ${TELEGRAM_PROXY_PASSWORD:}
openai:
token: ${CHAT_GPT_TOKEN}