2026-07-05 02:06:37 +00:00
package antigravity
import (
"bytes"
"context"
"fmt"
"os/exec"
"strings"
)
// StudyElement represents the extracted study content from a question.
type StudyElement struct {
QuestionID int `json:"questionId"`
Source string `json:"source"`
Category string `json:"category"`
Content string `json:"content"` // Markdown content containing formulas, charts, etc.
}
// GeneratedQuestion matches the structure to be saved in QuizQuestions DB.
type GeneratedQuestion struct {
2026-07-05 08:45:54 +00:00
QuestionText string `json:"questionText"`
Choice1 string `json:"choice1"`
Choice2 string `json:"choice2"`
Choice3 string `json:"choice3"`
Choice4 string `json:"choice4"`
CorrectAnswer int `json:"correctAnswer"`
CorrectAnswerStr string `json:"correctAnswerStr"`
Explanation string `json:"explanation"`
Difficulty string `json:"difficulty"`
Subject string `json:"subject"`
2026-07-05 02:06:37 +00:00
}
// CallAgy runs the agy CLI with the given prompt.
func CallAgy ( ctx context . Context , prompt string ) ( string , error ) {
cmd := exec . CommandContext ( ctx , "agy" , "--dangerously-skip-permissions" , "--print" , prompt )
var stdout , stderr bytes . Buffer
cmd . Stdout = & stdout
cmd . Stderr = & stderr
err := cmd . Run ()
if err != nil {
return "" , fmt . Errorf ( "agy error: %v, stderr: %s" , err , stderr . String ())
}
return strings . TrimSpace ( stdout . String ()), nil
}
// ExtractStudyElement requests the AI to generate a comprehensive study sheet/note for a specific quiz question.
func ExtractStudyElement ( ctx context . Context , questionText , choice1 , choice2 , choice3 , choice4 , correctAnswer , explanation string ) ( string , error ) {
prompt := fmt . Sprintf ( "아래 기출문제의 문제, 보기, 정답, 해설을 철저히 분석하여 핵심 개념을 담은 \"학습요소(개념 정리)\"를 작성해 주세요.\n" +
"이 학습요소는 사용자가 이 문제를 완벽하게 이해하고 관련된 이론적 배경까지 학습할 수 있도록 돕는 학습 노트입니다.\n\n" +
"[기출문제]\n" +
"문제: %s\n" +
"보기 1: %s\n" +
"보기 2: %s\n" +
"보기 3: %s\n" +
"보기 4: %s\n" +
"정답: %s\n" +
"해설: %s\n\n" +
"[작성 지침]\n" +
2026-07-05 08:45:54 +00:00
"1. **매우 중요**: 문서의 가장 첫 번째 줄은 반드시 핵심 학습개념/키워드를 설명하는 제목으로 시작해 주세요. (예: `# AES 암호화 알고리즘` 또는 `# OSI 7계층과 캡슐화`)\n" +
" - 첫 줄 외에 다른 서두(예: \"네, 아래는 개념 정리입니다\" 등)는 일절 포함하지 마십시오.\n" +
"2. 단순 정답 해설을 넘어, 문제에 포함된 핵심 개념의 정의, 특징, 작동 방식, 장단점을 일목요연하게 정리해 주세요. (표, 리스트 적극 활용)\n" +
"3. **KaTeX 문법 규칙**: 수식 작성 시 파싱 오류를 철저히 방지하세요. 괄호 매칭을 완벽히 지키고, 수식 내부에 한글을 포함해야 하는 경우 반드시 `\\text{한글}` 형식을 사용하세요. 인라인 수식은 `$수식$`, 디스플레이 수식은 `$$수식$$`로만 작성하세요.\n" +
"4. **Mermaid 문법 규칙**: Mermaid 버전 10.9.6 문법을 엄격히 지켜 `syntax error in text mermaid` 에러를 예방하세요.\n" +
" - `subgraph` 이름(타이틀)에는 공백이나 한글, 괄호가 들어가므로 **반드시** 쌍따옴표로 감싸서 선언하세요. (예: `subgraph \"정상 스택 (Normal)\"`)\n" +
" - 화살표 연결선의 텍스트 라벨 `|설명|` 안에는 괄호 `()`, 슬래시 `/`, 백슬래시 `\\` 등의 특수문자를 절대 쓰지 마세요. (예: `-->|SMTP 프로토콜 포트 25|` 로 표현)\n" +
" - 노드 내부에 한글, 공백, 기호, 괄호가 포함되는 경우 **반드시** 쌍따옴표로 감싸서 선언하세요 (예: `A[\"AES 암호화\"] --> B[\"키 생성\"]`).\n" +
" - 연결 화살표 기호는 오직 `-->` 또는 `-.->` 만 사용해야 하며, `->` 나 `- >` 처럼 깨진 형식을 쓰지 마세요.\n" +
" - 서브그래프(subgraph)를 열었다면 반드시 `end`로 닫아 마감하세요.\n" +
" - 백슬래시(`\\`)는 이스케이프 오류 방지를 위해 두 번(`\\\\`) 겹쳐 적으세요.\n" +
"5. 다른 불필요한 설명은 제외하고, 오직 첫 줄 개념명(# ...)으로 시작하는 마크다운 본문만 반환해 주세요." ,
2026-07-05 02:06:37 +00:00
questionText , choice1 , choice2 , choice3 , choice4 , correctAnswer , explanation )
2026-07-05 08:45:54 +00:00
return prompt , nil
2026-07-05 02:06:37 +00:00
}
// GenerateDescriptiveQuestion generates a new descriptive/practical exam question based on given reference questions.
func GenerateDescriptiveQuestion ( ctx context . Context , referenceExams [] string ) ( * GeneratedQuestion , error ) {
2026-07-05 08:45:54 +00:00
// We will create the prompt text in quiz_service.go using callAIEngine.
// This function is kept for backwards compatibility but we will format the prompt inside quiz_service to leverage both API and agy engines.
return nil , fmt . Errorf ( "use the prompt constructor and callAIEngine helper instead" )
2026-07-05 02:06:37 +00:00
}