diff --git a/app/[docs_id]/chatForm.tsx b/app/[docs_id]/chatForm.tsx index f8939c2..c16a87c 100644 --- a/app/[docs_id]/chatForm.tsx +++ b/app/[docs_id]/chatForm.tsx @@ -8,13 +8,20 @@ import { useChatHistory, type Message } from "../hooks/useChathistory"; import useSWR from "swr"; import { getQuestionExample } from "../actions/questionExample"; import { getLanguageName } from "../pagesList"; +import { ReplCommand, ReplOutput } from "../terminal/repl"; interface ChatFormProps { documentContent: string; sectionId: string; + replOutputs: ReplCommand[]; + fileContents: Array<{ + name: string; + content: string; + }>; + execResults: Record; } -export function ChatForm({ documentContent, sectionId }: ChatFormProps) { +export function ChatForm({ documentContent, sectionId, replOutputs, fileContents, execResults }: ChatFormProps) { const [messages, updateChatHistory] = useChatHistory(sectionId); const [inputValue, setInputValue] = useState(""); const [isLoading, setIsLoading] = useState(false); @@ -56,6 +63,9 @@ export function ChatForm({ documentContent, sectionId }: ChatFormProps) { const result = await askAI({ userQuestion, documentContent: documentContent, + replOutputs, + fileContents, + execResults, }); if (result.error) { diff --git a/app/[docs_id]/section.tsx b/app/[docs_id]/section.tsx index 9399c4a..d06cfdc 100644 --- a/app/[docs_id]/section.tsx +++ b/app/[docs_id]/section.tsx @@ -31,15 +31,12 @@ interface SectionProps { // 1つのセクションのタイトルと内容を表示する。内容はMarkdownとしてレンダリングする export function Section({ section, sectionId }: SectionProps) { - // eslint-disable-next-line @typescript-eslint/no-unused-vars const [replOutputs, setReplOutputs] = useState([]); - // eslint-disable-next-line @typescript-eslint/no-unused-vars const [execResults, setExecResults] = useState>( {} ); const [filenames, setFilenames] = useState([]); const { files } = useFile(); - // eslint-disable-next-line @typescript-eslint/no-unused-vars const fileContents: { name: string; content: string }[] = filenames.map( (name) => ({ name, content: files[name] || "" }) ); @@ -76,7 +73,13 @@ export function Section({ section, sectionId }: SectionProps) {
{section.title} - +
); diff --git a/app/actions/chatActions.ts b/app/actions/chatActions.ts index 1eed26b..773e7f5 100644 --- a/app/actions/chatActions.ts +++ b/app/actions/chatActions.ts @@ -11,6 +11,21 @@ interface FormState { 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; @@ -25,22 +40,62 @@ export async function askAI(params: ChatParams): Promise { }; } - const { userQuestion, documentContent } = parseResult.data; + 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形式で記述し、コードブロックを適切に使用してください。 - ドキュメントの内容に基づいて回答してください。 +- ユーザーが入力したターミナルのコマンドやファイルの内容、実行結果を参考にして回答してください。 - ユーザーへの回答のみを出力してください。 - 必要であれば、具体的なコード例を提示してください。 -