@@ -12,11 +12,18 @@ const ChatSchema = z.object({
1212 userQuestion : z
1313 . string ( )
1414 . min ( 1 , { message : "メッセージを入力してください。" } ) ,
15- splitMdContent : z
16- . string ( )
17- . min ( 1 , { message : "コンテキストとなるドキュメントがありません。" } ) ,
18- replOutputs : z
19- . array (
15+ documentContent : z . string ( ) ,
16+ splitMdContent : z . array (
17+ z . object ( {
18+ level : z . number ( ) ,
19+ title : z . string ( ) ,
20+ content : z . string ( ) ,
21+ } )
22+ ) ,
23+ sectionInView : z . array ( z . boolean ( ) ) ,
24+ replOutputs : z . record (
25+ z . string ( ) ,
26+ z . array (
2027 z . object ( {
2128 command : z . string ( ) ,
2229 output : z . array (
@@ -34,33 +41,24 @@ const ChatSchema = z.object({
3441 ) ,
3542 } )
3643 )
37- . optional ( ) ,
38- fileContents : z
39- . array (
44+ ) ,
45+ files : z . record ( z . string ( ) , z . string ( ) . optional ( ) ) ,
46+ execResults : z . record (
47+ z . string ( ) ,
48+ z . array (
4049 z . object ( {
41- name : z . string ( ) ,
42- content : z . string ( ) ,
50+ type : z . enum ( [
51+ "stdout" ,
52+ "stderr" ,
53+ "error" ,
54+ "return" ,
55+ "trace" ,
56+ "system" ,
57+ ] ) ,
58+ message : z . string ( ) ,
4359 } )
4460 )
45- . optional ( ) ,
46- execResults : z
47- . record (
48- z . string ( ) ,
49- z . array (
50- z . object ( {
51- type : z . enum ( [
52- "stdout" ,
53- "stderr" ,
54- "error" ,
55- "return" ,
56- "trace" ,
57- "system" ,
58- ] ) ,
59- message : z . string ( ) ,
60- } )
61- )
62- )
63- . optional ( ) ,
61+ ) ,
6462} ) ;
6563
6664type ChatParams = z . input < typeof ChatSchema > ;
@@ -78,19 +76,26 @@ export async function askAI(params: ChatParams): Promise<FormState> {
7876 const {
7977 userQuestion,
8078 documentContent,
79+ splitMdContent,
80+ sectionInView,
8181 replOutputs,
82- fileContents ,
82+ files ,
8383 execResults,
8484 } = parseResult . data ;
8585
8686 try {
8787 // ターミナルログの文字列を構築
8888 let terminalLogsSection = "" ;
89- if ( replOutputs && replOutputs . length > 0 ) {
90- terminalLogsSection =
91- "\n# ターミナルのログ(ユーザーが入力したコマンドとその実行結果)\n" ;
92- for ( const replCmd of replOutputs ) {
93- terminalLogsSection += `\n## コマンド: ${ replCmd . command } \n` ;
89+ terminalLogsSection =
90+ "\n# ターミナルのログ(ユーザーが入力したコマンドとその実行結果)\n" ;
91+ terminalLogsSection +=
92+ "\n以下はドキュメント内で実行例を示した各コードブロックの内容に加えてユーザーが追加で実行したコマンドです。\n" ;
93+ terminalLogsSection +=
94+ "例えば ```python-repl:1 のコードブロックに対してユーザーが実行したログが ターミナル #1 です。\n" ;
95+ for ( const [ replId , replInstance ] of Object . entries ( replOutputs ) ) {
96+ terminalLogsSection += `\n## ターミナル #${ replId } \n` ;
97+ for ( const replCmd of replInstance ) {
98+ terminalLogsSection += `\n- コマンド: ${ replCmd . command } \n` ;
9499 terminalLogsSection += "```\n" ;
95100 for ( const output of replCmd . output ) {
96101 terminalLogsSection += `${ output . message } \n` ;
@@ -101,19 +106,21 @@ export async function askAI(params: ChatParams): Promise<FormState> {
101106
102107 // ファイルエディターの内容を構築
103108 let fileContentsSection = "" ;
104- if ( fileContents && fileContents . length > 0 ) {
105- fileContentsSection = "\n# ファイルエディターの内容\n" ;
106- for ( const file of fileContents ) {
107- fileContentsSection += `\n## ファイル: ${ file . name } \n` ;
108- fileContentsSection += "```\n" ;
109- fileContentsSection += file . content ;
110- fileContentsSection += "\n```\n" ;
111- }
109+ fileContentsSection = "\n# ファイルエディターの内容\n" ;
110+ fileContentsSection +=
111+ "\n以下はドキュメント内でファイルの内容を示した各コードブロックの内容に加えてユーザーが編集を加えたものです。\n" ;
112+ fileContentsSection +=
113+ "例えば ```python:foo.py のコードブロックに対してユーザーが編集した後の内容が ファイル: foo.py です。\n" ;
114+ for ( const [ filename , content ] of Object . entries ( files ) ) {
115+ fileContentsSection += `\n## ファイル: ${ filename } \n` ;
116+ fileContentsSection += "```\n" ;
117+ fileContentsSection += content ;
118+ fileContentsSection += "\n```\n" ;
112119 }
113120
114121 // ファイル実行結果を構築
115122 let execResultsSection = "" ;
116- if ( execResults && Object . keys ( execResults ) . length > 0 ) {
123+ if ( execResults ) {
117124 execResultsSection = "\n# ファイルの実行結果\n" ;
118125 for ( const [ filename , outputs ] of Object . entries ( execResults ) ) {
119126 execResultsSection += `\n## ファイル: ${ filename } \n` ;
@@ -125,12 +132,21 @@ export async function askAI(params: ChatParams): Promise<FormState> {
125132 }
126133 }
127134
135+ const sectionTitlesInView = splitMdContent . filter ( ( _ , index ) => sectionInView [ index ] ) . map ( section => section . title ) . join ( ", " ) ;
136+
128137 const prompt = `
129138以下のPythonチュートリアルのドキュメントの内容を正確に理解し、ユーザーからの質問に対して、初心者にも分かりやすく、丁寧な解説を提供してください。
130139
140+ ユーザーはドキュメント内の ${ sectionTitlesInView } の付近のセクションを閲覧している際にこの質問を行っていると推測されます。
141+ 質問に答える際には、ユーザーが閲覧しているセクションの内容を特に考慮してください。
142+
131143# ドキュメント
132144${ documentContent }
133- ${ terminalLogsSection } ${ fileContentsSection } ${ execResultsSection }
145+
146+ ${ terminalLogsSection }
147+ ${ fileContentsSection }
148+ ${ execResultsSection }
149+
134150# ユーザーからの質問
135151${ userQuestion }
136152
@@ -143,6 +159,7 @@ ${userQuestion}
143159-
144160
145161` ;
162+ console . log ( prompt )
146163 const result = await generateContent ( prompt ) ;
147164 const text = result . text ;
148165 if ( ! text ) {
0 commit comments