mirror of
https://github.com/kou029w/daraz-llm.git
synced 2025-01-18 08:05:12 +00:00
Groq/Denoに変更!
- Groq … OpenAI互換API・安価 - Deno … Deno Deployへの簡単デプロイ
This commit is contained in:
parent
2d80377e87
commit
90b8873e2f
10 changed files with 110 additions and 7866 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,2 +0,0 @@
|
|||
.vercel
|
||||
node_modules
|
35
README.md
35
README.md
|
@ -1,42 +1,19 @@
|
|||
# だらずさん GPT
|
||||
# だらずさん LLM
|
||||
|
||||
GPT 版だらずさん
|
||||
LLM 版だらずさん
|
||||
|
||||
## インストール
|
||||
|
||||
Step 1
|
||||
: Slack アプリの作成
|
||||
|
||||
[Slack Applications](https://api.slack.com/apps) → Create New App → From an app manifest
|
||||
|
||||
下記の Manifest をコピペして、Slack アプリを作成
|
||||
|
||||
```yaml
|
||||
display_information:
|
||||
name: daraz-gpt
|
||||
features:
|
||||
bot_user:
|
||||
display_name: daraz-gpt
|
||||
oauth_config:
|
||||
scopes:
|
||||
bot:
|
||||
- app_mentions:read
|
||||
- chat:write
|
||||
settings:
|
||||
event_subscriptions:
|
||||
request_url: https://daraz-gpt.vercel.app/api/slack/events
|
||||
bot_events:
|
||||
- app_mention
|
||||
```
|
||||
[Create New Slack App](https://api.slack.com/apps?new_app=1&manifest_yaml={display_information:%20{name:%20darazllm},%20features:%20{bot_user:%20{display_name:%20darazllm}},%20oauth_config:%20{scopes:%20{bot:%20[%27channels:history%27,%20%27chat:write%27]}},%20settings:%20{event_subscriptions:%20{request_url:%20%27https://darazllm.deno.dev/slack/events%27,%20bot_events:%20[message.channels]}}}) > Select a workspace > Create > Install to Workspace
|
||||
|
||||
Step 2
|
||||
: Vercel へのデプロイ
|
||||
: [Fork to Edit](https://dash.deno.com/playground/darazllm) > Settings > Environment Variables
|
||||
|
||||
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fkou029w%2Fdaraz-gpt&env=SLACK_BOT_TOKEN,SLACK_SIGNING_SECRET,OPENAI_API_KEY)
|
||||
|
||||
- `SLACK_BOT_TOKEN` ... [Slack Applications](https://api.slack.com/apps) → "daraz-gpt" → Permissions ページにある `xoxb-` から始まるボットトークン
|
||||
- `SLACK_SIGNING_SECRET` ... [Slack Applications](https://api.slack.com/apps) → "daraz-gpt" → Basic Information ページにある Signing Secret
|
||||
- `OPENAI_API_KEY` … [OpenAI API Key](https://beta.openai.com/account/api-keys)
|
||||
Step 3
|
||||
: [Slack Applications](https://api.slack.com/apps) > "darazllm" > Event Subscriptions ページの URL を Deno Deploy の URL (例: `https://darazllm.deno.dev/slack/events`) に変更
|
||||
|
||||
## ライセンス
|
||||
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
import { App, AwsLambdaReceiver } from "@slack/bolt";
|
||||
import type { AwsHandler } from "@slack/bolt/dist/receivers/AwsLambdaReceiver";
|
||||
|
||||
const openaiApiKey = process.env.OPENAI_API_KEY ?? "";
|
||||
|
||||
async function gpt(prompt: string): Promise<string> {
|
||||
const endpoint = "https://api.openai.com/v1/completions";
|
||||
const body = {
|
||||
model: "text-davinci-003",
|
||||
prompt,
|
||||
temperature: 0.5,
|
||||
max_tokens: 2048,
|
||||
};
|
||||
const res = await fetch(endpoint, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
authorization: `Bearer ${openaiApiKey}`,
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
const json = await res.json();
|
||||
return json.choices[0].text.trim();
|
||||
}
|
||||
|
||||
const token = process.env.SLACK_BOT_TOKEN ?? "";
|
||||
const signingSecret = process.env.SLACK_SIGNING_SECRET ?? "";
|
||||
const receiver = new AwsLambdaReceiver({ signingSecret });
|
||||
const awsHandler = receiver.toHandler();
|
||||
const app = new App({ token, receiver });
|
||||
|
||||
// required app_mentions:read chat:write
|
||||
app.event("app_mention", async ({ event, say }) => {
|
||||
const prompt = `語尾を「にゃん」にして質問にこたえる
|
||||
Q:${event.text.replace(/^<@[0-9A-Z]+>/, "").trim()}
|
||||
A:`;
|
||||
const text = await gpt(prompt);
|
||||
await say(text);
|
||||
});
|
||||
|
||||
export const handler: AwsHandler = async (event, context, callback) => {
|
||||
// AWS Lambda ウォームアップ時に発生しうるタイムアウトを無視
|
||||
if (event.headers["x-slack-retry-reason"] === "http_timeout") {
|
||||
return { statusCode: 200, body: "OK" };
|
||||
}
|
||||
return await awsHandler(event, context, callback);
|
||||
};
|
6
deno.json
Normal file
6
deno.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"imports": {
|
||||
"@slack/bolt": "npm:@slack/bolt@^3.17.1",
|
||||
"groq-sdk": "npm:groq-sdk@^0.3.2"
|
||||
}
|
||||
}
|
98
main.ts
Normal file
98
main.ts
Normal file
|
@ -0,0 +1,98 @@
|
|||
// SPDX-License-Identifier: WTFPL
|
||||
|
||||
const {
|
||||
/** https://console.groq.com/docs/api-keys */
|
||||
GROQ_API_KEY,
|
||||
/** https://api.slack.com/apps → Basic Information ページにある Signing Secret */
|
||||
SLACK_SIGNING_SECRET = "",
|
||||
/** https://api.slack.com/apps → Permissions ページにある `xoxb-` から始まるボットトークン */
|
||||
SLACK_BOT_TOKEN = "",
|
||||
} = Deno.env.toObject();
|
||||
|
||||
const system = `\
|
||||
あなたは「だらずさん」です。
|
||||
賢い猫。少しだらしない。趣味はさんぽとねんね。
|
||||
全て鳥取弁で語尾が「にゃん」。`;
|
||||
|
||||
const n = 3;
|
||||
const usage = `\
|
||||
https://dash.deno.com/playground/darazllm
|
||||
|
||||
使い方:
|
||||
@darazllm <prompt> (または1/${n}の確率で)応答
|
||||
@darazllm /bye すべて忘れる
|
||||
@darazllm /help このテキストを表示
|
||||
|
||||
システムプロンプト:
|
||||
|
||||
${system}`;
|
||||
|
||||
import bolt from "npm:@slack/bolt";
|
||||
import { Groq } from "npm:groq-sdk";
|
||||
|
||||
type Messages = Array<Groq.Chat.CompletionCreateParams.Message>;
|
||||
|
||||
const model = "llama3-70b-8192";
|
||||
const groq = new Groq({
|
||||
apiKey: GROQ_API_KEY,
|
||||
timeout: 10_000,
|
||||
});
|
||||
const kv = await Deno.openKv();
|
||||
|
||||
async function chat(messages: Messages): Promise<string> {
|
||||
const res = await groq.chat.completions.create({
|
||||
model,
|
||||
messages: [{ role: "system", content: system }, ...messages],
|
||||
});
|
||||
|
||||
return res.choices[0].message.content;
|
||||
}
|
||||
|
||||
const app = new bolt.App({
|
||||
token: SLACK_BOT_TOKEN,
|
||||
signingSecret: SLACK_SIGNING_SECRET,
|
||||
});
|
||||
|
||||
app.message(async (c) => {
|
||||
if (!("text" in c.message) || c.message.text === undefined) return;
|
||||
|
||||
const mention = `<@${c.context.botUserId}>`;
|
||||
const isMention = c.message.text.includes(mention);
|
||||
const prompt = c.message.text.replace(mention, "").trim();
|
||||
|
||||
if (isMention && prompt === "/help") {
|
||||
await c.say(usage);
|
||||
return;
|
||||
}
|
||||
|
||||
// すべてを忘れる
|
||||
if (isMention && prompt === "/bye") {
|
||||
await kv.delete(["channel", c.message.channel]);
|
||||
await c.say("にゃーん");
|
||||
return;
|
||||
}
|
||||
|
||||
const kve = await kv.get<Messages>(["channel", c.message.channel]);
|
||||
const messages = kve.value ?? [];
|
||||
|
||||
if (prompt) messages.push({ role: "user", content: prompt });
|
||||
|
||||
if (isMention || Math.floor(Math.random() * n) === 0) {
|
||||
try {
|
||||
const res = await chat(messages);
|
||||
|
||||
if (!res) throw new Error("Empty response");
|
||||
|
||||
messages.push({ role: "assistant", content: res });
|
||||
await c.say(res);
|
||||
} catch (error) {
|
||||
await kv.delete(["channel", c.message.channel]);
|
||||
await c.say(`${error} にゃーん`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
await kv.set(["channel", c.message.channel], messages);
|
||||
});
|
||||
|
||||
await app.start();
|
7762
package-lock.json
generated
7762
package-lock.json
generated
File diff suppressed because it is too large
Load diff
11
package.json
11
package.json
|
@ -1,11 +0,0 @@
|
|||
{
|
||||
"name": "daraz-gpt",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@slack/bolt": "^3.12.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vercel": "^34.0.0"
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
OK
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": ["config:base", "config:semverAllMonthly", ":automergeMinor"]
|
||||
}
|
10
vercel.json
10
vercel.json
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"build": {
|
||||
"env": {
|
||||
"NODEJS_AWS_HANDLER_NAME": "handler"
|
||||
}
|
||||
},
|
||||
"github": {
|
||||
"silent": true
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue