mirror of
https://github.com/icereed/paperless-gpt.git
synced 2025-03-13 13:18:02 -05:00
Merge branch 'main' into hocr
This commit is contained in:
commit
f0a73ed263
5 changed files with 293 additions and 111 deletions
|
@ -82,7 +82,7 @@ RUN sed -i \
|
|||
RUN CGO_ENABLED=1 GOMAXPROCS=$(nproc) go build -tags musl -o paperless-gpt .
|
||||
|
||||
# Stage 3: Create a lightweight image with just the binary
|
||||
FROM alpine:latest
|
||||
FROM alpine:3.21.2
|
||||
|
||||
ENV GIN_MODE=release
|
||||
|
||||
|
|
58
README.md
58
README.md
|
@ -179,35 +179,35 @@ services:
|
|||
|
||||
# **Note:** When using Ollama, ensure that the Ollama server is running and accessible from the paperless-gpt container.
|
||||
|
||||
| Variable | Description | Required |
|
||||
| -------------------------------- | ---------------------------------------------------------------------------------------------------------------- | -------- |
|
||||
| `PAPERLESS_BASE_URL` | URL of your paperless-ngx instance (e.g. `http://paperless-ngx:8000`). | Yes |
|
||||
| `PAPERLESS_API_TOKEN` | API token for paperless-ngx. Generate one in paperless-ngx admin. | Yes |
|
||||
| `PAPERLESS_PUBLIC_URL` | Public URL for Paperless (if different from `PAPERLESS_BASE_URL`). | No |
|
||||
| `MANUAL_TAG` | Tag for manual processing. Default: `paperless-gpt`. | No |
|
||||
| `AUTO_TAG` | Tag for auto processing. Default: `paperless-gpt-auto`. | No |
|
||||
| `LLM_PROVIDER` | AI backend (`openai` or `ollama`). | Yes |
|
||||
| `LLM_MODEL` | AI model name, e.g. `gpt-4o`, `gpt-3.5-turbo`, `deepseek-r1:8b`. | Yes |
|
||||
| `OPENAI_API_KEY` | OpenAI API key (required if using OpenAI). | Cond. |
|
||||
| `OPENAI_BASE_URL` | OpenAI base URL (optional, if using a custom OpenAI compatible service like LiteLLM). | No |
|
||||
| `LLM_LANGUAGE` | Likely language for documents (e.g. `English`). Default: `English`. | No |
|
||||
| `OLLAMA_HOST` | Ollama server URL (e.g. `http://host.docker.internal:11434`). | No |
|
||||
| `OCR_PROVIDER` | OCR provider to use (`llm` or `google_docai`). Default: `llm`. | No |
|
||||
| `VISION_LLM_PROVIDER` | AI backend for LLM OCR (`openai` or `ollama`). Required if OCR_PROVIDER is `llm`. | Cond. |
|
||||
| `VISION_LLM_MODEL` | Model name for LLM OCR (e.g. `minicpm-v`). Required if OCR_PROVIDER is `llm`. | Cond. |
|
||||
| `GOOGLE_PROJECT_ID` | Google Cloud project ID. Required if OCR_PROVIDER is `google_docai`. | Cond. |
|
||||
| `GOOGLE_LOCATION` | Google Cloud region (e.g. `us`, `eu`). Required if OCR_PROVIDER is `google_docai`. | Cond. |
|
||||
| `GOOGLE_PROCESSOR_ID` | Document AI processor ID. Required if OCR_PROVIDER is `google_docai`. | Cond. |
|
||||
| `GOOGLE_APPLICATION_CREDENTIALS` | Path to the mounted Google service account key. Required if OCR_PROVIDER is `google_docai`. | Cond. |
|
||||
| `AUTO_OCR_TAG` | Tag for automatically processing docs with OCR. Default: `paperless-gpt-ocr-auto`. | No |
|
||||
| `LOG_LEVEL` | Application log level (`info`, `debug`, `warn`, `error`). Default: `info`. | No |
|
||||
| `LISTEN_INTERFACE` | Network interface to listen on. Default: `:8080`. | No |
|
||||
| `AUTO_GENERATE_TITLE` | Generate titles automatically if `paperless-gpt-auto` is used. Default: `true`. | No |
|
||||
| `AUTO_GENERATE_TAGS` | Generate tags automatically if `paperless-gpt-auto` is used. Default: `true`. | No |
|
||||
| `AUTO_GENERATE_CORRESPONDENTS` | Generate correspondents automatically if `paperless-gpt-auto` is used. Default: `true`. | No |
|
||||
| `OCR_LIMIT_PAGES` | Limit the number of pages for OCR. Set to `0` for no limit. Default: `5`. | No |
|
||||
| `TOKEN_LIMIT` | Maximum tokens allowed for prompts/content. Set to `0` to disable limit. Useful for smaller LLMs. | No |
|
||||
| `CORRESPONDENT_BLACK_LIST` | A comma-separated list of names to exclude from the correspondents suggestions. Example: `John Doe, Jane Smith`. | No |
|
||||
| Variable | Description | Required | Default |
|
||||
| -------------------------------- | ---------------------------------------------------------------------------------------------------------------- | -------- | ---------------------- |
|
||||
| `PAPERLESS_BASE_URL` | URL of your paperless-ngx instance (e.g. `http://paperless-ngx:8000`). | Yes | |
|
||||
| `PAPERLESS_API_TOKEN` | API token for paperless-ngx. Generate one in paperless-ngx admin. | Yes | |
|
||||
| `PAPERLESS_PUBLIC_URL` | Public URL for Paperless (if different from `PAPERLESS_BASE_URL`). | No | |
|
||||
| `MANUAL_TAG` | Tag for manual processing. | No | paperless-gpt |
|
||||
| `AUTO_TAG` | Tag for auto processing. | No | paperless-gpt-auto |
|
||||
| `LLM_PROVIDER` | AI backend (`openai` or `ollama`). | Yes | |
|
||||
| `LLM_MODEL` | AI model name, e.g. `gpt-4o`, `gpt-3.5-turbo`, `deepseek-r1:8b`. | Yes | |
|
||||
| `OPENAI_API_KEY` | OpenAI API key (required if using OpenAI). | Cond. | |
|
||||
| `OPENAI_BASE_URL` | OpenAI base URL (optional, if using a custom OpenAI compatible service like LiteLLM). | No | |
|
||||
| `LLM_LANGUAGE` | Likely language for documents (e.g. `English`). | No | English |
|
||||
| `OLLAMA_HOST` | Ollama server URL (e.g. `http://host.docker.internal:11434`). | No | |
|
||||
| `OCR_PROVIDER` | OCR provider to use (`llm` or `google_docai`). | No | llm |
|
||||
| `VISION_LLM_PROVIDER` | AI backend for LLM OCR (`openai` or `ollama`). Required if OCR_PROVIDER is `llm`. | Cond. | |
|
||||
| `VISION_LLM_MODEL` | Model name for LLM OCR (e.g. `minicpm-v`). Required if OCR_PROVIDER is `llm`. | Cond. | |
|
||||
| `GOOGLE_PROJECT_ID` | Google Cloud project ID. Required if OCR_PROVIDER is `google_docai`. | Cond. | |
|
||||
| `GOOGLE_LOCATION` | Google Cloud region (e.g. `us`, `eu`). Required if OCR_PROVIDER is `google_docai`. | Cond. | |
|
||||
| `GOOGLE_PROCESSOR_ID` | Document AI processor ID. Required if OCR_PROVIDER is `google_docai`. | Cond. | |
|
||||
| `GOOGLE_APPLICATION_CREDENTIALS` | Path to the mounted Google service account key. Required if OCR_PROVIDER is `google_docai`. | Cond. | |
|
||||
| `AUTO_OCR_TAG` | Tag for automatically processing docs with OCR. | No | paperless-gpt-ocr-auto |
|
||||
| `LOG_LEVEL` | Application log level (`info`, `debug`, `warn`, `error`). | No | info |
|
||||
| `LISTEN_INTERFACE` | Network interface to listen on. | No | 8080 |
|
||||
| `AUTO_GENERATE_TITLE` | Generate titles automatically if `paperless-gpt-auto` is used. | No | true |
|
||||
| `AUTO_GENERATE_TAGS` | Generate tags automatically if `paperless-gpt-auto` is used. | No | true |
|
||||
| `AUTO_GENERATE_CORRESPONDENTS` | Generate correspondents automatically if `paperless-gpt-auto` is used. | No | true |
|
||||
| `OCR_LIMIT_PAGES` | Limit the number of pages for OCR. Set to `0` for no limit. | No | 5 |
|
||||
| `TOKEN_LIMIT` | Maximum tokens allowed for prompts/content. Set to `0` to disable limit. Useful for smaller LLMs. | No | |
|
||||
| `CORRESPONDENT_BLACK_LIST` | A comma-separated list of names to exclude from the correspondents suggestions. Example: `John Doe, Jane Smith`. | No | |
|
||||
|
||||
### Custom Prompt Templates
|
||||
|
||||
|
|
59
main.go
59
main.go
|
@ -9,7 +9,8 @@ import (
|
|||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
"text/template"
|
||||
"time"
|
||||
|
@ -187,6 +188,21 @@ func main() {
|
|||
ocrProvider: ocrProvider,
|
||||
}
|
||||
|
||||
if app.isOcrEnabled() {
|
||||
fmt.Printf("Using %s as manual OCR tag\n", manualOcrTag)
|
||||
fmt.Printf("Using %s as auto OCR tag\n", autoOcrTag)
|
||||
rawLimitOcrPages := os.Getenv("OCR_LIMIT_PAGES")
|
||||
if rawLimitOcrPages == "" {
|
||||
limitOcrPages = 5
|
||||
} else {
|
||||
var err error
|
||||
limitOcrPages, err = strconv.Atoi(rawLimitOcrPages)
|
||||
if err != nil {
|
||||
log.Fatalf("Invalid OCR_LIMIT_PAGES value: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Start background process for auto-tagging
|
||||
go func() {
|
||||
minBackoffDuration := 10 * time.Second
|
||||
|
@ -197,7 +213,7 @@ func main() {
|
|||
for {
|
||||
processedCount, err := func() (int, error) {
|
||||
count := 0
|
||||
if isOcrEnabled() {
|
||||
if app.isOcrEnabled() {
|
||||
ocrCount, err := app.processAutoOcrTagDocuments()
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("error in processAutoOcrTagDocuments: %w", err)
|
||||
|
@ -256,7 +272,7 @@ func main() {
|
|||
|
||||
// Endpoint to see if user enabled OCR
|
||||
api.GET("/experimental/ocr", func(c *gin.Context) {
|
||||
enabled := isOcrEnabled()
|
||||
enabled := app.isOcrEnabled()
|
||||
c.JSON(http.StatusOK, gin.H{"enabled": enabled})
|
||||
})
|
||||
|
||||
|
@ -366,8 +382,8 @@ func initLogger() {
|
|||
})
|
||||
}
|
||||
|
||||
func isOcrEnabled() bool {
|
||||
return visionLlmModel != "" && visionLlmProvider != ""
|
||||
func (app *App) isOcrEnabled() bool {
|
||||
return app.ocrProvider != nil
|
||||
}
|
||||
|
||||
// validateOrDefaultEnvVars ensures all necessary environment variables are set
|
||||
|
@ -385,16 +401,10 @@ func validateOrDefaultEnvVars() {
|
|||
if manualOcrTag == "" {
|
||||
manualOcrTag = "paperless-gpt-ocr"
|
||||
}
|
||||
if isOcrEnabled() {
|
||||
fmt.Printf("Using %s as manual OCR tag\n", manualOcrTag)
|
||||
}
|
||||
|
||||
if autoOcrTag == "" {
|
||||
autoOcrTag = "paperless-gpt-ocr-auto"
|
||||
}
|
||||
if isOcrEnabled() {
|
||||
fmt.Printf("Using %s as auto OCR tag\n", autoOcrTag)
|
||||
}
|
||||
|
||||
if paperlessBaseURL == "" {
|
||||
log.Fatal("Please set the PAPERLESS_BASE_URL environment variable.")
|
||||
|
@ -420,19 +430,6 @@ func validateOrDefaultEnvVars() {
|
|||
log.Fatal("Please set the OPENAI_API_KEY environment variable for OpenAI provider.")
|
||||
}
|
||||
|
||||
if isOcrEnabled() {
|
||||
rawLimitOcrPages := os.Getenv("OCR_LIMIT_PAGES")
|
||||
if rawLimitOcrPages == "" {
|
||||
limitOcrPages = 5
|
||||
} else {
|
||||
var err error
|
||||
limitOcrPages, err = strconv.Atoi(rawLimitOcrPages)
|
||||
if err != nil {
|
||||
log.Fatalf("Invalid OCR_LIMIT_PAGES value: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize token limit from environment variable
|
||||
if limit := os.Getenv("TOKEN_LIMIT"); limit != "" {
|
||||
if parsed, err := strconv.Atoi(limit); err == nil {
|
||||
|
@ -466,7 +463,14 @@ func (app *App) processAutoTagDocuments() (int, error) {
|
|||
|
||||
log.Debugf("Found at least %d remaining documents with tag %s", len(documents), autoTag)
|
||||
|
||||
processedCount := 0
|
||||
for _, document := range documents {
|
||||
// Skip documents that have the autoOcrTag
|
||||
if slices.Contains(document.Tags, autoOcrTag) {
|
||||
log.Debugf("Skipping document %d as it has the OCR tag %s", document.ID, autoOcrTag)
|
||||
continue
|
||||
}
|
||||
|
||||
docLogger := documentLogger(document.ID)
|
||||
docLogger.Info("Processing document for auto-tagging")
|
||||
|
||||
|
@ -479,17 +483,18 @@ func (app *App) processAutoTagDocuments() (int, error) {
|
|||
|
||||
suggestions, err := app.generateDocumentSuggestions(ctx, suggestionRequest, docLogger)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("error generating suggestions for document %d: %w", document.ID, err)
|
||||
return processedCount, fmt.Errorf("error generating suggestions for document %d: %w", document.ID, err)
|
||||
}
|
||||
|
||||
err = app.Client.UpdateDocuments(ctx, suggestions, app.Database, false)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("error updating document %d: %w", document.ID, err)
|
||||
return processedCount, fmt.Errorf("error updating document %d: %w", document.ID, err)
|
||||
}
|
||||
|
||||
docLogger.Info("Successfully processed document")
|
||||
processedCount++
|
||||
}
|
||||
return len(documents), nil
|
||||
return processedCount, nil
|
||||
}
|
||||
|
||||
// processAutoOcrTagDocuments handles the background auto-tagging of OCR documents
|
||||
|
|
177
main_test.go
Normal file
177
main_test.go
Normal file
|
@ -0,0 +1,177 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"slices"
|
||||
"testing"
|
||||
"text/template"
|
||||
|
||||
"github.com/Masterminds/sprig/v3"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestProcessAutoTagDocuments(t *testing.T) {
|
||||
// Initialize required global variables
|
||||
autoTag = "paperless-gpt-auto"
|
||||
autoOcrTag = "paperless-gpt-ocr-auto"
|
||||
|
||||
// Initialize templates
|
||||
var err error
|
||||
titleTemplate, err = template.New("title").Funcs(sprig.FuncMap()).Parse("")
|
||||
require.NoError(t, err)
|
||||
tagTemplate, err = template.New("tag").Funcs(sprig.FuncMap()).Parse("")
|
||||
require.NoError(t, err)
|
||||
correspondentTemplate, err = template.New("correspondent").Funcs(sprig.FuncMap()).Parse("")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create test environment
|
||||
env := newTestEnv(t)
|
||||
defer env.teardown()
|
||||
|
||||
// Set up test cases
|
||||
testCases := []struct {
|
||||
name string
|
||||
documents []Document
|
||||
expectedCount int
|
||||
expectedError string
|
||||
updateResponse int // HTTP status code for update response
|
||||
}{
|
||||
{
|
||||
name: "Skip document with autoOcrTag",
|
||||
documents: []Document{
|
||||
{
|
||||
ID: 1,
|
||||
Title: "Doc with OCR tag",
|
||||
Tags: []string{autoTag, autoOcrTag},
|
||||
},
|
||||
{
|
||||
ID: 2,
|
||||
Title: "Doc without OCR tag",
|
||||
Tags: []string{autoTag},
|
||||
},
|
||||
{
|
||||
ID: 3,
|
||||
Title: "Doc with OCR tag",
|
||||
Tags: []string{autoTag, autoOcrTag},
|
||||
},
|
||||
},
|
||||
expectedCount: 1,
|
||||
updateResponse: http.StatusOK,
|
||||
},
|
||||
{
|
||||
name: "No documents to process",
|
||||
documents: []Document{},
|
||||
expectedCount: 0,
|
||||
updateResponse: http.StatusOK,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
// Mock the GetAllTags response
|
||||
env.setMockResponse("/api/tags/", func(w http.ResponseWriter, r *http.Request) {
|
||||
response := map[string]interface{}{
|
||||
"results": []map[string]interface{}{
|
||||
{"id": 1, "name": autoTag},
|
||||
{"id": 2, "name": autoOcrTag},
|
||||
{"id": 3, "name": "other-tag"},
|
||||
},
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(response)
|
||||
})
|
||||
|
||||
// Mock the GetDocumentsByTags response
|
||||
env.setMockResponse("/api/documents/", func(w http.ResponseWriter, r *http.Request) {
|
||||
response := GetDocumentsApiResponse{
|
||||
Results: make([]GetDocumentApiResponseResult, len(tc.documents)),
|
||||
}
|
||||
for i, doc := range tc.documents {
|
||||
tagIds := make([]int, len(doc.Tags))
|
||||
for j, tagName := range doc.Tags {
|
||||
switch tagName {
|
||||
case autoTag:
|
||||
tagIds[j] = 1
|
||||
case autoOcrTag:
|
||||
tagIds[j] = 2
|
||||
default:
|
||||
tagIds[j] = 3
|
||||
}
|
||||
}
|
||||
response.Results[i] = GetDocumentApiResponseResult{
|
||||
ID: doc.ID,
|
||||
Title: doc.Title,
|
||||
Tags: tagIds,
|
||||
Content: "Test content",
|
||||
}
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(response)
|
||||
})
|
||||
|
||||
// Mock the correspondent creation endpoint
|
||||
env.setMockResponse("/api/correspondents/", func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method == "POST" {
|
||||
// Mock successful correspondent creation
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||
"id": 3,
|
||||
"name": "test response",
|
||||
})
|
||||
} else {
|
||||
// Mock GET response for existing correspondents
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||
"results": []map[string]interface{}{
|
||||
{"id": 1, "name": "Alpha"},
|
||||
{"id": 2, "name": "Beta"},
|
||||
},
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// Create test app
|
||||
app := &App{
|
||||
Client: env.client,
|
||||
Database: env.db,
|
||||
LLM: &mockLLM{}, // Use mock LLM from app_llm_test.go
|
||||
}
|
||||
|
||||
// Set auto-generate flags
|
||||
autoGenerateTitle = "true"
|
||||
autoGenerateTags = "true"
|
||||
autoGenerateCorrespondents = "true"
|
||||
|
||||
// Mock the document update responses
|
||||
for _, doc := range tc.documents {
|
||||
if !slices.Contains(doc.Tags, autoOcrTag) {
|
||||
updatePath := fmt.Sprintf("/api/documents/%d/", doc.ID)
|
||||
env.setMockResponse(updatePath, func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(tc.updateResponse)
|
||||
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||
"id": doc.ID,
|
||||
"title": "Updated " + doc.Title,
|
||||
"tags": []int{1, 3}, // Mock updated tag IDs
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Run the test
|
||||
count, err := app.processAutoTagDocuments()
|
||||
|
||||
// Verify results
|
||||
if tc.expectedError != "" {
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), tc.expectedError)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tc.expectedCount, count)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
108
web-app/package-lock.json
generated
108
web-app/package-lock.json
generated
|
@ -1663,17 +1663,17 @@
|
|||
"integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw=="
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "8.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.23.0.tgz",
|
||||
"integrity": "sha512-vBz65tJgRrA1Q5gWlRfvoH+w943dq9K1p1yDBY2pc+a1nbBLZp7fB9+Hk8DaALUbzjqlMfgaqlVPT1REJdkt/w==",
|
||||
"version": "8.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.24.0.tgz",
|
||||
"integrity": "sha512-aFcXEJJCI4gUdXgoo/j9udUYIHgF23MFkg09LFz2dzEmU0+1Plk4rQWv/IYKvPHAtlkkGoB3m5e6oUp+JPsNaQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.10.0",
|
||||
"@typescript-eslint/scope-manager": "8.23.0",
|
||||
"@typescript-eslint/type-utils": "8.23.0",
|
||||
"@typescript-eslint/utils": "8.23.0",
|
||||
"@typescript-eslint/visitor-keys": "8.23.0",
|
||||
"@typescript-eslint/scope-manager": "8.24.0",
|
||||
"@typescript-eslint/type-utils": "8.24.0",
|
||||
"@typescript-eslint/utils": "8.24.0",
|
||||
"@typescript-eslint/visitor-keys": "8.24.0",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^5.3.1",
|
||||
"natural-compare": "^1.4.0",
|
||||
|
@ -1693,16 +1693,16 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "8.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.23.0.tgz",
|
||||
"integrity": "sha512-h2lUByouOXFAlMec2mILeELUbME5SZRN/7R9Cw2RD2lRQQY08MWMM+PmVVKKJNK1aIwqTo9t/0CvOxwPbRIE2Q==",
|
||||
"version": "8.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.24.0.tgz",
|
||||
"integrity": "sha512-MFDaO9CYiard9j9VepMNa9MTcqVvSny2N4hkY6roquzj8pdCBRENhErrteaQuu7Yjn1ppk0v1/ZF9CG3KIlrTA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.23.0",
|
||||
"@typescript-eslint/types": "8.23.0",
|
||||
"@typescript-eslint/typescript-estree": "8.23.0",
|
||||
"@typescript-eslint/visitor-keys": "8.23.0",
|
||||
"@typescript-eslint/scope-manager": "8.24.0",
|
||||
"@typescript-eslint/types": "8.24.0",
|
||||
"@typescript-eslint/typescript-estree": "8.24.0",
|
||||
"@typescript-eslint/visitor-keys": "8.24.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -1718,14 +1718,14 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "8.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.23.0.tgz",
|
||||
"integrity": "sha512-OGqo7+dXHqI7Hfm+WqkZjKjsiRtFUQHPdGMXzk5mYXhJUedO7e/Y7i8AK3MyLMgZR93TX4bIzYrfyVjLC+0VSw==",
|
||||
"version": "8.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.24.0.tgz",
|
||||
"integrity": "sha512-HZIX0UByphEtdVBKaQBgTDdn9z16l4aTUz8e8zPQnyxwHBtf5vtl1L+OhH+m1FGV9DrRmoDuYKqzVrvWDcDozw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.23.0",
|
||||
"@typescript-eslint/visitor-keys": "8.23.0"
|
||||
"@typescript-eslint/types": "8.24.0",
|
||||
"@typescript-eslint/visitor-keys": "8.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
|
@ -1736,14 +1736,14 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "8.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.23.0.tgz",
|
||||
"integrity": "sha512-iIuLdYpQWZKbiH+RkCGc6iu+VwscP5rCtQ1lyQ7TYuKLrcZoeJVpcLiG8DliXVkUxirW/PWlmS+d6yD51L9jvA==",
|
||||
"version": "8.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.24.0.tgz",
|
||||
"integrity": "sha512-8fitJudrnY8aq0F1wMiPM1UUgiXQRJ5i8tFjq9kGfRajU+dbPyOuHbl0qRopLEidy0MwqgTHDt6CnSeXanNIwA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/typescript-estree": "8.23.0",
|
||||
"@typescript-eslint/utils": "8.23.0",
|
||||
"@typescript-eslint/typescript-estree": "8.24.0",
|
||||
"@typescript-eslint/utils": "8.24.0",
|
||||
"debug": "^4.3.4",
|
||||
"ts-api-utils": "^2.0.1"
|
||||
},
|
||||
|
@ -1760,9 +1760,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "8.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.23.0.tgz",
|
||||
"integrity": "sha512-1sK4ILJbCmZOTt9k4vkoulT6/y5CHJ1qUYxqpF1K/DBAd8+ZUL4LlSCxOssuH5m4rUaaN0uS0HlVPvd45zjduQ==",
|
||||
"version": "8.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.24.0.tgz",
|
||||
"integrity": "sha512-VacJCBTyje7HGAw7xp11q439A+zeGG0p0/p2zsZwpnMzjPB5WteaWqt4g2iysgGFafrqvyLWqq6ZPZAOCoefCw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
|
@ -1774,14 +1774,14 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "8.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.23.0.tgz",
|
||||
"integrity": "sha512-LcqzfipsB8RTvH8FX24W4UUFk1bl+0yTOf9ZA08XngFwMg4Kj8A+9hwz8Cr/ZS4KwHrmo9PJiLZkOt49vPnuvQ==",
|
||||
"version": "8.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.24.0.tgz",
|
||||
"integrity": "sha512-ITjYcP0+8kbsvT9bysygfIfb+hBj6koDsu37JZG7xrCiy3fPJyNmfVtaGsgTUSEuTzcvME5YI5uyL5LD1EV5ZQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.23.0",
|
||||
"@typescript-eslint/visitor-keys": "8.23.0",
|
||||
"@typescript-eslint/types": "8.24.0",
|
||||
"@typescript-eslint/visitor-keys": "8.24.0",
|
||||
"debug": "^4.3.4",
|
||||
"fast-glob": "^3.3.2",
|
||||
"is-glob": "^4.0.3",
|
||||
|
@ -1827,16 +1827,16 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "8.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.23.0.tgz",
|
||||
"integrity": "sha512-uB/+PSo6Exu02b5ZEiVtmY6RVYO7YU5xqgzTIVZwTHvvK3HsL8tZZHFaTLFtRG3CsV4A5mhOv+NZx5BlhXPyIA==",
|
||||
"version": "8.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.24.0.tgz",
|
||||
"integrity": "sha512-07rLuUBElvvEb1ICnafYWr4hk8/U7X9RDCOqd9JcAMtjh/9oRmcfN4yGzbPVirgMR0+HLVHehmu19CWeh7fsmQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.4.0",
|
||||
"@typescript-eslint/scope-manager": "8.23.0",
|
||||
"@typescript-eslint/types": "8.23.0",
|
||||
"@typescript-eslint/typescript-estree": "8.23.0"
|
||||
"@typescript-eslint/scope-manager": "8.24.0",
|
||||
"@typescript-eslint/types": "8.24.0",
|
||||
"@typescript-eslint/typescript-estree": "8.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
|
@ -1851,13 +1851,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "8.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.23.0.tgz",
|
||||
"integrity": "sha512-oWWhcWDLwDfu++BGTZcmXWqpwtkwb5o7fxUIGksMQQDSdPW9prsSnfIOZMlsj4vBOSrcnjIUZMiIjODgGosFhQ==",
|
||||
"version": "8.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.24.0.tgz",
|
||||
"integrity": "sha512-kArLq83QxGLbuHrTMoOEWO+l2MwsNS2TGISEdx8xgqpkbytB07XmlQyQdNDrCc1ecSqx0cnmhGvpX+VBwqqSkg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.23.0",
|
||||
"@typescript-eslint/types": "8.24.0",
|
||||
"eslint-visitor-keys": "^4.2.0"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -2983,9 +2983,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/eslint": {
|
||||
"version": "9.20.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.20.0.tgz",
|
||||
"integrity": "sha512-aL4F8167Hg4IvsW89ejnpTwx+B/UQRzJPGgbIOl+4XqffWsahVVsLEWoZvnrVuwpWmnRd7XeXmQI1zlKcFDteA==",
|
||||
"version": "9.20.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.20.1.tgz",
|
||||
"integrity": "sha512-m1mM33o6dBUjxl2qb6wv6nGNwCAsns1eKtaQ4l/NPHeTvhiUPbtdfMyktxN4B3fgHIgsYh1VT3V9txblpQHq+g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
@ -4942,9 +4942,9 @@
|
|||
"license": "MIT"
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.7.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.0.tgz",
|
||||
"integrity": "sha512-DrfFnPzblFmNrIZzg5RzHegbiRWg7KMR7btwi2yjHwx06zsUbO5g613sVwEV7FTwmzJu+Io0lJe2GJ3LxqpvBQ==",
|
||||
"version": "7.7.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
|
||||
"integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
|
@ -5460,15 +5460,15 @@
|
|||
}
|
||||
},
|
||||
"node_modules/typescript-eslint": {
|
||||
"version": "8.23.0",
|
||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.23.0.tgz",
|
||||
"integrity": "sha512-/LBRo3HrXr5LxmrdYSOCvoAMm7p2jNizNfbIpCgvG4HMsnoprRUOce/+8VJ9BDYWW68rqIENE/haVLWPeFZBVQ==",
|
||||
"version": "8.24.0",
|
||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.24.0.tgz",
|
||||
"integrity": "sha512-/lmv4366en/qbB32Vz5+kCNZEMf6xYHwh1z48suBwZvAtnXKbP+YhGe8OLE2BqC67LMqKkCNLtjejdwsdW6uOQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "8.23.0",
|
||||
"@typescript-eslint/parser": "8.23.0",
|
||||
"@typescript-eslint/utils": "8.23.0"
|
||||
"@typescript-eslint/eslint-plugin": "8.24.0",
|
||||
"@typescript-eslint/parser": "8.24.0",
|
||||
"@typescript-eslint/utils": "8.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
|
|
Loading…
Reference in a new issue