@@ -72,4 +72,120 @@ export async function requestGeminiSuggestions({ answers, name }) {
7272 clearTimeout ( timeoutId ) ;
7373 return { ok : false , reason : error . message || '네트워크 오류' } ;
7474 }
75+ }
76+
77+ // requestInitialQuestions 및 requestNextQuestion 함수는 이제 사용되지 않으므로 제거하거나 주석 처리합니다.
78+ /*
79+ export async function requestInitialQuestions(name) { ... }
80+ export async function requestNextQuestion(name, previousQuestion, previousAnswer) { ... }
81+ */
82+
83+ /**
84+ * Gemini API에 이전 대화 내용과 기본 질문, 그리고 개선 지침을 전달하여
85+ * 맥락에 맞게 개선된 다음 질문 하나를 받아옵니다.
86+ * @param {string } name - 친구 이름
87+ * @param {string } baseQuestionToRefine - 개선의 기반이 될 기본 질문 템플릿
88+ * @param {string } immediatePreviousQuestionText - 바로 이전에 물었던 실제 질문 내용
89+ * @param {string } immediatePreviousAnswerText - 이전 질문에 대한 사용자의 답변
90+ * @param {string } refinementPromptVariable - 질문 개선 방식에 대한 사용자 정의 지침
91+ * @param {string | null } firstQuestionText - (옵셔널) 첫 번째 질문의 실제 텍스트 (Q3+ 생성 시 제공)
92+ * @param {string | null } firstAnswerText - (옵셔널) 첫 번째 질문에 대한 답변 (Q3+ 생성 시 제공)
93+ * @returns {Promise<{ok: true, refinedQuestion: string} | {ok: false, reason: string}> }
94+ */
95+ export async function requestRefinedQuestion ( name , baseQuestionToRefine , immediatePreviousQuestionText , immediatePreviousAnswerText , refinementPromptVariable , firstQuestionText , firstAnswerText ) {
96+ const controller = new AbortController ( ) ;
97+ const timeoutId = setTimeout ( ( ) => controller . abort ( ) , REQUEST_TIMEOUT_MS ) ;
98+
99+ let firstInteractionContext = "" ;
100+ if ( firstQuestionText && firstAnswerText ) {
101+ firstInteractionContext = `
102+ [Initial Conversation Context]
103+ First question: ${ firstQuestionText }
104+ First answer: ${ firstAnswerText }
105+ ` ;
106+ }
107+
108+ // 시스템 프롬프트를 영어 중심으로 수정, 최종 질문 영어로 명시
109+ const systemPrompt = `You are an AI conversation designer tasked with making a user's chat with their friend (${ name } ) more natural and meaningful.
110+
111+ User's friend's name: "${ name } "
112+ ${ firstInteractionContext }
113+ [Previous turn in the conversation]
114+ Previous question to ${ name } : ${ immediatePreviousQuestionText }
115+ User's answer regarding ${ name } : ${ immediatePreviousAnswerText }
116+
117+ [Base intent for the next question]:
118+ ${ baseQuestionToRefine }
119+
120+ [Guideline for refining the question]:
121+ ${ refinementPromptVariable } // This is already in English as per QuestionScreen.js
122+
123+ Considering all the information above (especially "Initial Conversation Context" and "Previous turn"), generate ONE new question based on the "Base intent for the next question".
124+ This new question must follow the "Guideline for refining the question" and should naturally continue the conversation from the previous turn.
125+ It must include the friend's name, "${ name } ".
126+ **The refined question must be in English.**
127+
128+ Please provide the response ONLY in the following JSON format, with no other text:
129+ { "refinedQuestion": "The final refined question content (in English)" }
130+
131+ Example (the actual content will vary greatly based on input, but the response must be in English):
132+ { "refinedQuestion": "So, ${ name } , what were some of the specific feelings or thoughts you had during that experience?" }` ;
133+
134+ const url = `${ GEMINI_API_URL } ?key=${ GEMINI_API_KEY } ` ;
135+
136+ try {
137+ const response = await fetch ( url , {
138+ method : 'POST' ,
139+ headers : { 'Content-Type' : 'application/json' } ,
140+ body : JSON . stringify ( {
141+ contents : [
142+ {
143+ role : 'user' ,
144+ parts : [ { text : systemPrompt } ] ,
145+ } ,
146+ ] ,
147+ generationConfig : {
148+ responseMimeType : "application/json" ,
149+ }
150+ } ) ,
151+ signal : controller . signal ,
152+ } ) ;
153+ clearTimeout ( timeoutId ) ;
154+
155+ if ( ! response . ok ) {
156+ const errorText = await response . text ( ) ;
157+ console . error ( `Gemini API Error (RefinedQuestion): ${ response . status } ${ response . statusText } - ${ errorText } ` ) ;
158+ return {
159+ ok : false ,
160+ reason : `Gemini API 오류: ${ response . status } ${ errorText } ` ,
161+ } ;
162+ }
163+
164+ const data = await response . json ( ) ;
165+ let rawJsonText = data . candidates ?. [ 0 ] ?. content ?. parts ?. [ 0 ] ?. text ;
166+
167+ if ( ! rawJsonText ) {
168+ return { ok : false , reason : 'API로부터 유효한 다음 질문 데이터를 받지 못했습니다 (No text part).' } ;
169+ }
170+
171+ rawJsonText = rawJsonText . replace ( / ^ ` ` ` j s o n \s * / , '' ) . replace ( / \s * ` ` ` $ / , '' ) ;
172+
173+ try {
174+ const parsedResponse = JSON . parse ( rawJsonText ) ;
175+ if ( parsedResponse && typeof parsedResponse . refinedQuestion === 'string' && parsedResponse . refinedQuestion . trim ( ) !== '' ) {
176+ return { ok : true , refinedQuestion : parsedResponse . refinedQuestion } ;
177+ } else {
178+ console . warn ( "Parsed data is not a valid refined question object:" , parsedResponse ) ;
179+ return { ok : false , reason : 'API 응답이 유효한 다음 질문 형식이 아닙니다.' } ;
180+ }
181+ } catch ( parseError ) {
182+ console . error ( "Error parsing refined question JSON:" , parseError , "Raw text:" , rawJsonText ) ;
183+ return { ok : false , reason : `다음 질문 파싱 오류: ${ parseError . message } ` } ;
184+ }
185+
186+ } catch ( error ) {
187+ clearTimeout ( timeoutId ) ;
188+ console . error ( "Error in requestRefinedQuestion:" , error ) ;
189+ return { ok : false , reason : error . message || '네트워크 오류 또는 알 수 없는 다음 질문 생성 오류' } ;
190+ }
75191}
0 commit comments