-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathchatActions.ts
More file actions
117 lines (103 loc) · 4.23 KB
/
chatActions.ts
File metadata and controls
117 lines (103 loc) · 4.23 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
'use server';
import { z } from "zod";
import { generateContent } from "./gemini";
interface FormState {
response: string;
error: string | null;
}
const ChatSchema = z.object({
userQuestion: z.string().min(1, { message: "メッセージを入力してください。" }),
documentContent: z.string().min(1, { message: "コンテキストとなるドキュメントがありません。"}),
replOutputs: z.array(z.object({
command: z.string(),
output: z.array(z.object({
type: z.enum(["stdout", "stderr", "error", "return", "trace", "system"]),
message: z.string(),
})),
})).optional(),
fileContents: z.array(z.object({
name: z.string(),
content: z.string(),
})).optional(),
execResults: z.record(z.string(), z.array(z.object({
type: z.enum(["stdout", "stderr", "error", "return", "trace", "system"]),
message: z.string(),
}))).optional(),
});
type ChatParams = z.input<typeof ChatSchema>;
export async function askAI(params: ChatParams): Promise<FormState> {
const parseResult = ChatSchema.safeParse(params);
if (!parseResult.success) {
return {
response: "",
error: parseResult.error.issues.map((e) => e.message).join(", "),
};
}
const { userQuestion, documentContent, replOutputs, fileContents, execResults } = parseResult.data;
try {
// ターミナルログの文字列を構築
let terminalLogsSection = "";
if (replOutputs && replOutputs.length > 0) {
terminalLogsSection = "\n# ターミナルのログ(ユーザーが入力したコマンドとその実行結果)\n";
for (const replCmd of replOutputs) {
terminalLogsSection += `\n## コマンド: ${replCmd.command}\n`;
terminalLogsSection += "```\n";
for (const output of replCmd.output) {
terminalLogsSection += `${output.message}\n`;
}
terminalLogsSection += "```\n";
}
}
// ファイルエディターの内容を構築
let fileContentsSection = "";
if (fileContents && fileContents.length > 0) {
fileContentsSection = "\n# ファイルエディターの内容\n";
for (const file of fileContents) {
fileContentsSection += `\n## ファイル: ${file.name}\n`;
fileContentsSection += "```\n";
fileContentsSection += file.content;
fileContentsSection += "\n```\n";
}
}
// ファイル実行結果を構築
let execResultsSection = "";
if (execResults && Object.keys(execResults).length > 0) {
execResultsSection = "\n# ファイルの実行結果\n";
for (const [filename, outputs] of Object.entries(execResults)) {
execResultsSection += `\n## ファイル: ${filename}\n`;
execResultsSection += "```\n";
for (const output of outputs) {
execResultsSection += `${output.message}\n`;
}
execResultsSection += "```\n";
}
}
const prompt = `
以下のPythonチュートリアルのドキュメントの内容を正確に理解し、ユーザーからの質問に対して、初心者にも分かりやすく、丁寧な解説を提供してください。
# ドキュメント
${documentContent}
${terminalLogsSection}${fileContentsSection}${execResultsSection}
# ユーザーからの質問
${userQuestion}
# 指示
- 回答はMarkdown形式で記述し、コードブロックを適切に使用してください。
- ドキュメントの内容に基づいて回答してください。
- ユーザーが入力したターミナルのコマンドやファイルの内容、実行結果を参考にして回答してください。
- ユーザーへの回答のみを出力してください。
- 必要であれば、具体的なコード例を提示してください。
-
`;
const result = await generateContent(prompt);
const text = result.text;
if (!text) {
throw new Error("AIからの応答が空でした");
}
return { response: text, error: null };
} catch (error: unknown) {
console.error("Error calling Generative AI:", error);
if (error instanceof Error) {
return { response: '', error: `AIへのリクエスト中にエラーが発生しました: ${error.message}` };
}
return { response: '', error: '予期せぬエラーが発生しました。' };
}
}