diff --git a/documentation/en/docs/index.md b/documentation/en/docs/index.md
new file mode 100644
index 0000000..c0f7462
--- /dev/null
+++ b/documentation/en/docs/index.md
@@ -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.
\ No newline at end of file
diff --git a/documentation/en/docs/stylesheets/extra.css b/documentation/en/docs/stylesheets/extra.css
new file mode 100644
index 0000000..841f6aa
--- /dev/null
+++ b/documentation/en/docs/stylesheets/extra.css
@@ -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;
+ }
+}
\ No newline at end of file
diff --git a/documentation/en/mkdocs.yml b/documentation/en/mkdocs.yml
new file mode 100644
index 0000000..94ba6e9
--- /dev/null
+++ b/documentation/en/mkdocs.yml
@@ -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
\ No newline at end of file
diff --git a/documentation/en/overrides/partials/comments.html b/documentation/en/overrides/partials/comments.html
new file mode 100644
index 0000000..11806e0
--- /dev/null
+++ b/documentation/en/overrides/partials/comments.html
@@ -0,0 +1,17 @@
+{% if "comments" in page.meta.hide %}
+{% else %}
+
{{ lang.t("meta.comments") }}
+
+
+
+{% endif %}
\ No newline at end of file
diff --git a/documentation/en/overrides/partials/integrations/analytics/custom.html b/documentation/en/overrides/partials/integrations/analytics/custom.html
new file mode 100644
index 0000000..b4e0e91
--- /dev/null
+++ b/documentation/en/overrides/partials/integrations/analytics/custom.html
@@ -0,0 +1,16 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/dev/struchkov/example/bot/unit/PersonalChatGPTUnit.java b/src/main/java/dev/struchkov/example/bot/unit/PersonalChatGPTUnit.java
index 09e43b5..4753e80 100644
--- a/src/main/java/dev/struchkov/example/bot/unit/PersonalChatGPTUnit.java
+++ b/src/main/java/dev/struchkov/example/bot/unit/PersonalChatGPTUnit.java
@@ -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 chatGpt() {
return AnswerText.builder()
- .triggerCheck(mail -> mail.getFromPersonId().equals(appProperty.getTelegramId()))
+ .triggerCheck(mail -> {
+ if (mail.getFromPersonId().equals(appProperty.getTelegramId())) {
+ final Optional 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 startMessage() {
+ return AnswerText.builder()
+ .triggerCheck(
+ mail -> {
+ if (mail.getFromPersonId().equals(appProperty.getTelegramId())) {
+ final List attachments = mail.getAttachments();
+ final Optional 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 prompt() {
return AnswerText.builder()
@@ -221,6 +271,8 @@ public class PersonalChatGPTUnit implements PersonUnitConfiguration {
❤️ *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 (Russia): [https://www.tinkoff.ru/cf/4iU6NB3uzqx](https://www.tinkoff.ru/cf/4iU6NB3uzqx)
TON: `struchkov-mark.ton`
diff --git a/src/main/java/dev/struchkov/example/bot/unit/StartNotify.java b/src/main/java/dev/struchkov/example/bot/unit/StartNotify.java
index e432945..8fc6111 100644
--- a/src/main/java/dev/struchkov/example/bot/unit/StartNotify.java
+++ b/src/main/java/dev/struchkov/example/bot/unit/StartNotify.java
@@ -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 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());
+ }
}
}
diff --git a/src/main/java/dev/struchkov/example/bot/util/Cmd.java b/src/main/java/dev/struchkov/example/bot/util/Cmd.java
index df0594e..aee71ff 100644
--- a/src/main/java/dev/struchkov/example/bot/util/Cmd.java
+++ b/src/main/java/dev/struchkov/example/bot/util/Cmd.java
@@ -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";
}
diff --git a/src/main/java/dev/struchkov/example/bot/util/UnitName.java b/src/main/java/dev/struchkov/example/bot/util/UnitName.java
index 4d1e0e2..6199bc8 100644
--- a/src/main/java/dev/struchkov/example/bot/util/UnitName.java
+++ b/src/main/java/dev/struchkov/example/bot/util/UnitName.java
@@ -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";
+
}
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index e051fe0..e77c66d 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -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}
\ No newline at end of file