-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathchatActions.ts
More file actions
167 lines (154 loc) · 5.47 KB
/
chatActions.ts
File metadata and controls
167 lines (154 loc) · 5.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
"use server";
// import { z } from "zod";
import { generateContent } from "./gemini";
import { DynamicMarkdownSection } from "../[lang]/[pageId]/pageContent";
import { ReplCommand, ReplOutput } from "@my-code/runtime/repl";
import { addChat, ChatWithMessages } from "@/lib/chatHistory";
type ChatResult =
| {
error: string;
}
| {
error: null;
// サーバー側でデータベースに新しく追加されたチャットデータ
chat: ChatWithMessages;
};
type ChatParams = {
userQuestion: string;
docsId: string;
documentContent: string;
sectionContent: DynamicMarkdownSection[];
replOutputs: Record<string, ReplCommand[]>;
files: Record<string, string>;
execResults: Record<string, ReplOutput[]>;
};
export async function askAI(params: ChatParams): Promise<ChatResult> {
// const parseResult = ChatSchema.safeParse(params);
// if (!parseResult.success) {
// return {
// response: "",
// error: parseResult.error.issues.map((e) => e.message).join(", "),
// };
// }
const {
userQuestion,
documentContent,
sectionContent,
replOutputs,
files,
execResults,
} = params;
const prompt: string[] = [];
prompt.push(
`以下のPythonチュートリアルのドキュメントの内容を正確に理解し、ユーザーからの質問に対して、初心者にも分かりやすく、丁寧な解説を提供してください。`
);
prompt.push(``);
const sectionTitlesInView = sectionContent
.filter((s) => s.inView)
.map((s) => s.title)
.join(", ");
prompt.push(
`ユーザーはドキュメント内の ${sectionTitlesInView} の付近のセクションを閲覧している際にこの質問を行っていると推測されます。`
);
prompt.push(
`質問に答える際には、ユーザーが閲覧しているセクションの内容を特に考慮してください。`
);
prompt.push(``);
prompt.push(`# ドキュメント`);
prompt.push(``);
prompt.push(documentContent);
prompt.push(``);
if (Object.keys(replOutputs).length > 0) {
prompt.push(
`# ターミナルのログ(ユーザーが入力したコマンドとその実行結果)`
);
prompt.push(``);
prompt.push(
"以下はドキュメント内で実行例を示した各コードブロックの内容に加えてユーザーが追加で実行したコマンドです。"
);
prompt.push(
"例えば ```python-repl:1 のコードブロックに対してユーザーが実行したログが ターミナル #1 です。"
);
prompt.push(``);
for (const [replId, replCommands] of Object.entries(replOutputs)) {
prompt.push(`## ターミナル #${replId}`);
for (const replCmd of replCommands) {
prompt.push(`\n- コマンド: ${replCmd.command}`);
prompt.push("```");
for (const output of replCmd.output) {
prompt.push(output.message);
}
prompt.push("```");
}
prompt.push(``);
}
}
if (Object.keys(files).length > 0) {
prompt.push("# ファイルエディターの内容");
prompt.push(``);
prompt.push(
"以下はドキュメント内でファイルの内容を示した各コードブロックの内容に加えてユーザーが編集を加えたものです。"
);
prompt.push(
"例えば ```python:foo.py のコードブロックに対してユーザーが編集した後の内容が ファイル: foo.py です。"
);
prompt.push(``);
for (const [filename, content] of Object.entries(files)) {
prompt.push(`## ファイル: ${filename}`);
prompt.push("```");
prompt.push(content);
prompt.push("```");
prompt.push(``);
}
}
if (Object.keys(execResults).length > 0) {
prompt.push("# ファイルの実行結果");
prompt.push(``);
for (const [filename, outputs] of Object.entries(execResults)) {
prompt.push(`## ファイル: ${filename}`);
prompt.push("```");
for (const output of outputs) {
prompt.push(output.message);
}
prompt.push("```");
prompt.push(``);
}
}
prompt.push("# ユーザーからの質問");
prompt.push(userQuestion);
prompt.push(``);
prompt.push("# 指示");
prompt.push(
"- 回答はMarkdown形式で記述し、コードブロックを適切に使用してください。"
);
prompt.push("- ドキュメントの内容に基づいて回答してください。");
prompt.push(
"- ユーザーが入力したターミナルのコマンドやファイルの内容、実行結果を参考にして回答してください。"
);
prompt.push("- ユーザーへの回答のみを出力してください。");
prompt.push("- 必要であれば、具体的なコード例を提示してください。");
console.log(prompt);
try {
const result = await generateContent(prompt.join("\n"));
const text = result.text;
if (!text) {
throw new Error("AIからの応答が空でした");
}
// TODO: どのセクションへの回答にするかをAIに決めさせる
const targetSectionId =
sectionContent.find((s) => s.inView)?.id || "";
const newChat = await addChat(params.docsId, targetSectionId, [
{ role: "user", content: userQuestion },
{ role: "ai", content: text },
]);
return {
error: null,
chat: newChat,
};
} catch (error: unknown) {
console.error("Error calling Generative AI:", error);
return {
error: String(error),
};
}
}