Skip to content

Commit

Permalink
feat: recreate ChatGPT logic (#122)
Browse files Browse the repository at this point in the history
  • Loading branch information
m1sk9 authored Oct 23, 2023
1 parent 4aa0f67 commit 699810b
Show file tree
Hide file tree
Showing 20 changed files with 323 additions and 406 deletions.
40 changes: 36 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,18 @@ dotenvy = { version = "0.15" }
once_cell = { version = "1.18" }
tracing = { version = "0.1" }
tracing-subscriber = { version = "0.3" }
envy = { version = "0.4.2" }
typed-builder = { version = "0.18.0" }

[dependencies.serenity]
version = "0.11"
features = ["client", "gateway", "model", "cache", "rustls_backend"]
default-features = false

[dependencies.serde]
version = "1.0.189"
features = ["derive"]

[dependencies.tokio]
version = "1.33"
features = ["macros", "rt-multi-thread", "time"]
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ docker pull ghcr.io/approvers/ichiyo_ai:vX.Y.Z

設定の例は [.env.example](./.env.example) で確認できます。

| Key | Description | Default |
|---------------------|-------------------|---------|
| `DISCORD_API_TOKEN` | Discord API のトークン | - |
| `OPENAI_API_KEY` | OpenAI API のトークン | - |
| `GUILD_ID` | 限界開発鯖の ID | - |
| `SUBSCRIBER_ROLE_ID` | 購読者ロールの ID | - |
| Key | Description | required |
|---------------------|-------------------|----------|
| `DISCORD_API_TOKEN` | Discord API のトークン | `Yes` |
| `OPENAI_API_KEY` | OpenAI API のトークン | `Yes` |
| `GUILD_ID` | 限界開発鯖の ID | `Yes` |
| `TAXPAYER_ROLE_ID` | 購読者ロールの ID | `No` |
52 changes: 52 additions & 0 deletions src/adapters/chatgpt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
use crate::model::chatgpt::{RequestMessageModel, ResponseCompletionResultModel};
use anyhow::Context;
use async_openai::config::OpenAIConfig;
use async_openai::types::CreateChatCompletionRequestArgs;
use async_openai::Client;
use std::time::Duration;
use tokio::time::timeout;

pub static SYSTEM_CONTEXT: &str = "回答時は以下のルールに従うこと.\n- 1900文字以内に収めること。";
static TIMEOUT_DURATION: Duration = Duration::from_secs(180);

async fn create_chatgpt_client() -> anyhow::Result<Client<OpenAIConfig>> {
Ok(Client::new())
}

pub async fn request_chatgpt_message(
request: RequestMessageModel,
) -> anyhow::Result<ResponseCompletionResultModel> {
let client = create_chatgpt_client().await?;

let client_request = CreateChatCompletionRequestArgs::default()
.max_tokens(512u16)
.model(request.model)
.messages(request.replies)
.build()?;

let response = timeout(TIMEOUT_DURATION, client.chat().create(client_request))
.await
.context("Timeout. Please try again.")??;

let choice = response
.choices
.get(0)
.context("No response message found.")?;
let (input_token, output_token, total_token) = response
.usage
.map(|usage| {
(
usage.prompt_tokens,
usage.completion_tokens,
usage.total_tokens,
)
})
.unwrap_or_default();

Ok(ResponseCompletionResultModel::builder()
.response_message(choice.message.content.clone().unwrap_or_default())
.input_token(input_token)
.output_token(output_token)
.total_token(total_token)
.build())
}
23 changes: 23 additions & 0 deletions src/adapters/discord.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use crate::model::chatgpt::{usage_pricing, ResponseCompletionResultModel};
use crate::model::discord::DiscordReplyMessageModel;
use anyhow::Context;

pub async fn reply_completion_result(
reply_message: DiscordReplyMessageModel,
) -> anyhow::Result<()> {
reply_message
.target_message
.reply_ping(reply_message.http, reply_message.formatted_result)
.await
.context("Failed to reply.")?;

Ok(())
}

pub fn format_result(result: ResponseCompletionResultModel, model: &str) -> String {
let pricing = usage_pricing(result.input_token, result.output_token, model);
format!(
"{}\n\n`利用料金: ¥{:.2}` - `合計トークン: {}` - `使用モデル: {}`",
result.response_message, pricing, result.total_token, model
)
}
3 changes: 3 additions & 0 deletions src/adapters/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod chatgpt;

pub mod discord;
16 changes: 5 additions & 11 deletions src/client/discord.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
use crate::model::EvHandler;
use anyhow::Context;
use serenity::{prelude::GatewayIntents, Client};

pub struct EvHandler;

pub async fn start_discord_client(token: &str) -> anyhow::Result<()> {
// メッセージ内容の取得とギルドメッセージの取得を有効化
pub async fn create_discord_client(token: &str) -> anyhow::Result<Client> {
let intents = GatewayIntents::GUILD_MESSAGES | GatewayIntents::MESSAGE_CONTENT;

let mut client = Client::builder(token, intents)
let client = Client::builder(token, intents)
.event_handler(EvHandler)
.await
.context("クライアントの作成に失敗しました.")?;
.context("Failed to create discord client")?;

client
.start()
.await
.context("クライアントの起動に失敗しました.")
Ok(client)
}
1 change: 0 additions & 1 deletion src/client/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
pub mod discord;
pub mod openai;
151 changes: 0 additions & 151 deletions src/client/openai.rs

This file was deleted.

13 changes: 0 additions & 13 deletions src/env.rs

This file was deleted.

Loading

0 comments on commit 699810b

Please sign in to comment.