package rewrite import ( "bytes" "compress/flate" "compress/gzip" "fmt" "io" "log" "net/http" "regexp" "strings" "git.gulenok.ru/greenhaze/gaslight/internal/cheating" "git.gulenok.ru/greenhaze/gaslight/internal/latex" "git.gulenok.ru/greenhaze/gaslight/internal/openrouter" ) var questionTestDivRe = regexp.MustCompile(`(?is)]*\bid\s*=\s*["'][^"']*\bQuestionTest\b[^"']*["'][^>]*>`) type HTMLHook func(req *http.Request, html []byte) ([]byte, error) type Processor struct { hook HTMLHook } func NewProcessor(hook HTMLHook) *Processor { return &Processor{hook: hook} } func tryExtractLinks(text string) []string { aiResponce, err := openrouter.AskOpenRouter(fmt.Sprintf("Ты - умный парсер для веб страниц. Данная страница представляет из себя тестовое задание и тебе нужно проанализировать страницу, найти блок в котором находится задание, и если внутри этого блока есть изображения - достать их и вернуть в виде JSON массива со строками на эти изображения. ВОЗВРАЩАЙ ТОЛЬКО И ТОЛЬКО JSON обьект, БЕЗ КАКИХ ЛИБО ДОПОЛНИТЕЛЬНЫХ СЛОВ, ФРАЗ, СИМВОЛОВ etc. В ФОРМАТЕ {\"images\":[\"test", "test\"]}", string(text))) if err != nil { log.Printf("openrouter failed %s", err) return []string{} } log.Println(aiResponce) return []string{} } func DefaultQuestionTestHook(_ *http.Request, html []byte) ([]byte, error) { switch cheating.DetermineQuestionType(string(html)) { case cheating.FullTextQuestion: { //log.Println(tryExtractLinks(string(html))) aiResponce, err := openrouter.AskOpenRouter(fmt.Sprintf("прочитай задание и выпиши достаточно подробный список формул/гайд по решению которые могут помочь при решении задач ИЛИ ЕСЛИ МОЖЕШЬ СРАЗУ ДАТЬ ОТВЕТ - ответы списком: %s. пиши без latex обычным читаемым текстом и максимально кратко. учти что это работа за 10 класс российской школы", string(html))) if err != nil { log.Printf("openrouter failed %s", err) return html, nil } return []byte(strings.ReplaceAll(string(html), "generated", fmt.Sprintf("generated", latex.ConvertLaTeXToASCII(aiResponce)))), nil } case cheating.QuestionWithPicture: { } } return []byte(strings.ReplaceAll(string(html), "generated", "pwned")), nil } func IsHTMLResponse(contentType string) bool { contentType = strings.ToLower(contentType) return strings.Contains(contentType, "text/html") || strings.Contains(contentType, "application/xhtml+xml") } func (p *Processor) RewriteIfNeeded(req *http.Request, contentEncoding string, body []byte) ([]byte, error) { decoded, err := decodeBody(contentEncoding, body) if err != nil { return nil, err } if !questionTestDivRe.Match(decoded) { return body, nil } modifiedDecoded, err := p.hook(req, decoded) if err != nil { return nil, err } return encodeBody(contentEncoding, modifiedDecoded) } func decodeBody(encoding string, body []byte) ([]byte, error) { switch strings.ToLower(strings.TrimSpace(encoding)) { case "", "identity": return body, nil case "gzip": r, err := gzip.NewReader(bytes.NewReader(body)) if err != nil { return nil, err } defer r.Close() return io.ReadAll(r) case "deflate": r := flate.NewReader(bytes.NewReader(body)) defer r.Close() return io.ReadAll(r) default: return nil, fmt.Errorf("unsupported content-encoding: %s", encoding) } } func encodeBody(encoding string, decoded []byte) ([]byte, error) { switch strings.ToLower(strings.TrimSpace(encoding)) { case "", "identity": return decoded, nil case "gzip": var buf bytes.Buffer w := gzip.NewWriter(&buf) if _, err := w.Write(decoded); err != nil { _ = w.Close() return nil, err } if err := w.Close(); err != nil { return nil, err } return buf.Bytes(), nil case "deflate": var buf bytes.Buffer w, err := flate.NewWriter(&buf, flate.DefaultCompression) if err != nil { return nil, err } if _, err := w.Write(decoded); err != nil { _ = w.Close() return nil, err } if err := w.Close(); err != nil { return nil, err } return buf.Bytes(), nil default: return nil, fmt.Errorf("unsupported content-encoding: %s", encoding) } }