Skip to content

Commit 67fb2f8

Browse files
authored
Merge pull request #49 from ut-code/copilot/fix-d5cf4d00-3e37-42e3-8286-dffb889dcb0b
AIへの質問にターミナルのログを含める
2 parents 8fa5c64 + 07dbeb2 commit 67fb2f8

File tree

3 files changed

+75
-7
lines changed

3 files changed

+75
-7
lines changed

app/[docs_id]/chatForm.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,20 @@ import { useChatHistory, type Message } from "../hooks/useChathistory";
88
import useSWR from "swr";
99
import { getQuestionExample } from "../actions/questionExample";
1010
import { getLanguageName } from "../pagesList";
11+
import { ReplCommand, ReplOutput } from "../terminal/repl";
1112

1213
interface ChatFormProps {
1314
documentContent: string;
1415
sectionId: string;
16+
replOutputs: ReplCommand[];
17+
fileContents: Array<{
18+
name: string;
19+
content: string;
20+
}>;
21+
execResults: Record<string, ReplOutput[]>;
1522
}
1623

17-
export function ChatForm({ documentContent, sectionId }: ChatFormProps) {
24+
export function ChatForm({ documentContent, sectionId, replOutputs, fileContents, execResults }: ChatFormProps) {
1825
const [messages, updateChatHistory] = useChatHistory(sectionId);
1926
const [inputValue, setInputValue] = useState("");
2027
const [isLoading, setIsLoading] = useState(false);
@@ -56,6 +63,9 @@ export function ChatForm({ documentContent, sectionId }: ChatFormProps) {
5663
const result = await askAI({
5764
userQuestion,
5865
documentContent: documentContent,
66+
replOutputs,
67+
fileContents,
68+
execResults,
5969
});
6070

6171
if (result.error) {

app/[docs_id]/section.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,12 @@ interface SectionProps {
3131

3232
// 1つのセクションのタイトルと内容を表示する。内容はMarkdownとしてレンダリングする
3333
export function Section({ section, sectionId }: SectionProps) {
34-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
3534
const [replOutputs, setReplOutputs] = useState<ReplCommand[]>([]);
36-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
3735
const [execResults, setExecResults] = useState<Record<string, ReplOutput[]>>(
3836
{}
3937
);
4038
const [filenames, setFilenames] = useState<string[]>([]);
4139
const { files } = useFile();
42-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
4340
const fileContents: { name: string; content: string }[] = filenames.map(
4441
(name) => ({ name, content: files[name] || "" })
4542
);
@@ -76,7 +73,13 @@ export function Section({ section, sectionId }: SectionProps) {
7673
<div>
7774
<Heading level={section.level}>{section.title}</Heading>
7875
<StyledMarkdown content={section.content} />
79-
<ChatForm documentContent={section.content} sectionId={sectionId} />
76+
<ChatForm
77+
documentContent={section.content}
78+
sectionId={sectionId}
79+
replOutputs={replOutputs}
80+
fileContents={fileContents}
81+
execResults={execResults}
82+
/>
8083
</div>
8184
</SectionCodeContext.Provider>
8285
);

app/actions/chatActions.ts

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,21 @@ interface FormState {
1111
const ChatSchema = z.object({
1212
userQuestion: z.string().min(1, { message: "メッセージを入力してください。" }),
1313
documentContent: z.string().min(1, { message: "コンテキストとなるドキュメントがありません。"}),
14+
replOutputs: z.array(z.object({
15+
command: z.string(),
16+
output: z.array(z.object({
17+
type: z.enum(["stdout", "stderr", "error", "return", "trace", "system"]),
18+
message: z.string(),
19+
})),
20+
})).optional(),
21+
fileContents: z.array(z.object({
22+
name: z.string(),
23+
content: z.string(),
24+
})).optional(),
25+
execResults: z.record(z.string(), z.array(z.object({
26+
type: z.enum(["stdout", "stderr", "error", "return", "trace", "system"]),
27+
message: z.string(),
28+
}))).optional(),
1429
});
1530

1631
type ChatParams = z.input<typeof ChatSchema>;
@@ -25,22 +40,62 @@ export async function askAI(params: ChatParams): Promise<FormState> {
2540
};
2641
}
2742

28-
const { userQuestion, documentContent } = parseResult.data;
43+
const { userQuestion, documentContent, replOutputs, fileContents, execResults } = parseResult.data;
2944

3045
try {
46+
// ターミナルログの文字列を構築
47+
let terminalLogsSection = "";
48+
if (replOutputs && replOutputs.length > 0) {
49+
terminalLogsSection = "\n# ターミナルのログ(ユーザーが入力したコマンドとその実行結果)\n";
50+
for (const replCmd of replOutputs) {
51+
terminalLogsSection += `\n## コマンド: ${replCmd.command}\n`;
52+
terminalLogsSection += "```\n";
53+
for (const output of replCmd.output) {
54+
terminalLogsSection += `${output.message}\n`;
55+
}
56+
terminalLogsSection += "```\n";
57+
}
58+
}
59+
60+
// ファイルエディターの内容を構築
61+
let fileContentsSection = "";
62+
if (fileContents && fileContents.length > 0) {
63+
fileContentsSection = "\n# ファイルエディターの内容\n";
64+
for (const file of fileContents) {
65+
fileContentsSection += `\n## ファイル: ${file.name}\n`;
66+
fileContentsSection += "```\n";
67+
fileContentsSection += file.content;
68+
fileContentsSection += "\n```\n";
69+
}
70+
}
71+
72+
// ファイル実行結果を構築
73+
let execResultsSection = "";
74+
if (execResults && Object.keys(execResults).length > 0) {
75+
execResultsSection = "\n# ファイルの実行結果\n";
76+
for (const [filename, outputs] of Object.entries(execResults)) {
77+
execResultsSection += `\n## ファイル: ${filename}\n`;
78+
execResultsSection += "```\n";
79+
for (const output of outputs) {
80+
execResultsSection += `${output.message}\n`;
81+
}
82+
execResultsSection += "```\n";
83+
}
84+
}
3185

3286
const prompt = `
3387
以下のPythonチュートリアルのドキュメントの内容を正確に理解し、ユーザーからの質問に対して、初心者にも分かりやすく、丁寧な解説を提供してください。
3488
3589
# ドキュメント
3690
${documentContent}
37-
91+
${terminalLogsSection}${fileContentsSection}${execResultsSection}
3892
# ユーザーからの質問
3993
${userQuestion}
4094
4195
# 指示
4296
- 回答はMarkdown形式で記述し、コードブロックを適切に使用してください。
4397
- ドキュメントの内容に基づいて回答してください。
98+
- ユーザーが入力したターミナルのコマンドやファイルの内容、実行結果を参考にして回答してください。
4499
- ユーザーへの回答のみを出力してください。
45100
- 必要であれば、具体的なコード例を提示してください。
46101
-

0 commit comments

Comments
 (0)