Пишем Java-скрипт, который собирает проект в один файл для контекста в чат DeepSeek или другие LLM. chatgpt.. chatgpt. deepseek.. chatgpt. deepseek. Developer Tools.. chatgpt. deepseek. Developer Tools. Java.. chatgpt. deepseek. Developer Tools. Java. llm.. chatgpt. deepseek. Developer Tools. Java. llm. Open source.. chatgpt. deepseek. Developer Tools. Java. llm. Open source. автоматизация.. chatgpt. deepseek. Developer Tools. Java. llm. Open source. автоматизация. искусственный интеллект.. chatgpt. deepseek. Developer Tools. Java. llm. Open source. автоматизация. искусственный интеллект. контекст.

У нейросетей есть ограничение на количество символов в чате или на число запросов. И бывает так, что лимит уже закончился, а разработка проекта — нет.

Тогда приходится открывать новый чат и заново напоминать контекст: что за проект, какая структура, какие файлы важны, где уже были изменения. Обычно это сводится к ручному копированию кода, а это долго и неудобно.

Отдельная проблема — DeepSeek не всегда понимает ссылки на репозиторий и не смотрит код по ним так, как хотелось бы. Зато если дать ему сам контекст кода текстом, он включает его в анализ.

Идея

Пишем скрипт, который не надо компилировать, а сразу можно выполнить. Нужна java не ниже 11 версии. Идея в том что мы в один файл собираем весь контекст который нужен для анализа.

Вместо ручного копирования десятков файлов получается одна операция.

java ScanProject.java

Я обычно кладу данный файлик в корень папки с проектами и вызываю уже в самом проекте примерно так:

# из папки проекта
java ../../ScanProject.java

Или так:

# из корня папки с проектами
java ScanProject.java .javascanner-profile result.txt
# Можно и для конкретной папки проекта, если нужен не весь код, а только часть.
java ScanProject.java .javascanner-profilesrcmainjavarumcsscannerprofiledomainmodel result.txt

Вам нужно лишь создать файл ScanProject.java и поместить следующий код:

import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.List;

public class ScanProject {
    private static final List<String> INCLUDED_EXTENSIONS = List.of(
        ".java", ".gradle", ".kt", ".kts", ".xml", ".yml", ".yaml", 
        ".properties", ".json", ".md", ".txt"
    );
    
    private static final List<String> EXCLUDED_DIRS = List.of(
        ".git", ".gradle", "build", "target", "out", "bin", ".idea", "node_modules"
    );
    
    public static void main(String[] args) {
        String projectRoot = args.length > 0 ? args[0] : ".";
        String outputFile = args.length > 1 ? args[1] : "project_code.txt";
        
        try {
            scanProject(projectRoot, outputFile);
            System.out.println("Project scanned successfully! Output: " + outputFile);
        } catch (IOException e) {
            System.err.println("Error scanning project: " + e.getMessage());
            e.printStackTrace();
        }
    }
    
    private static void scanProject(String rootPath, String outputFile) throws IOException {
        Path root = Paths.get(rootPath).toAbsolutePath();
        List<Path> files = new ArrayList<>();
        
        // Собираем все файлы
        Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
                String dirName = dir.getFileName().toString();
                if (EXCLUDED_DIRS.contains(dirName)) {
                    return FileVisitResult.SKIP_SUBTREE;
                }
                return FileVisitResult.CONTINUE;
            }
            
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
                if (isIncludedFile(file)) {
                    files.add(file);
                }
                return FileVisitResult.CONTINUE;
            }
        });
        
        // Сортируем файлы для удобства чтения
        files.sort((p1, p2) -> {
            int depthCompare = Integer.compare(p1.getNameCount(), p2.getNameCount());
            return depthCompare != 0 ? depthCompare : p1.compareTo(p2);
        });
        
        // Записываем в выходной файл
        try (PrintWriter writer = new PrintWriter(new FileWriter(outputFile))) {
            writer.println("PROJECT STRUCTURE:");
            writer.println("==================");
            for (Path file : files) {
                writer.println(root.relativize(file));
            }
            
            writer.println("nnSOURCE CODE:");
            writer.println("============");
            
            for (Path file : files) {
                writer.println("n" + "=".repeat(80));
                writer.println("FILE: " + root.relativize(file));
                writer.println("=".repeat(80));
                
                try {
                    List<String> lines = Files.readAllLines(file);
                    for (String line : lines) {
                        writer.println(line);
                    }
                } catch (IOException e) {
                    writer.println("ERROR READING FILE: " + e.getMessage());
                }
            }
        }
    }
    
    private static boolean isIncludedFile(Path file) {
        String fileName = file.getFileName().toString();
        return INCLUDED_EXTENSIONS.stream()
                .anyMatch(ext -> fileName.toLowerCase().endsWith(ext));
    }
}

Скрипт я писал под свой стек, но его легко изменить так как вам надо. Можно добавить например:

  • параметр для указания расширения фалов, которые вам нужны для обсуждения

  • параметр только для вывода структуры проекта

  • параметры для указания маски для выбора толко определныых файлов

Я этого не делал потому, что данный скрипт нужен, чтобы начать обсуждение проекта, а не постоянно собирать запрос для нейросети.

Что делает скрипт

  • рекурсивно обходит проект;

  • может исключать не нужные директории вроде .gitnode_modulesbuildtarget; (строчки 13-15)

  • Можно указать расширения файлов которые вам нужны (строчки 8-10)

  • собирает структуру проекта; (строчки 64-66)

  • добавляет содержимое нужных файлов в один итоговый .txt; (строчки 71-84)

В result.txt или project_code.txt будет примерно текст такого содержания:

  • структура проекта

  • исходники кода

Весь текст нет смысла показывать там много букв, но контекст будет примерно таким:

PROJECT STRUCTURE:
==================
build.gradle
docker-compose.yml
README.md
settings.gradle
datastats-data.json
gradlewrappergradle-wrapper.properties
srcmainresourcesapplication.properties
srcmainresourcesquestionsquestions_en.json
srcmainresourcesquestionsquestions_ru.json
srcmainresourcesquestionsquestions_zh.json
srcmainresourcestemplatesindex.html
srcmainresourcestemplateslencioni-test.html
srcmainresourcestemplatesresult.html
srcmainresourcestemplatessher-test.html
srcmainresourcestemplatesstats.html
srcmainresourcestemplateswelcome.html
....

SOURCE CODE:
============

================================================================================
FILE: build.gradle
================================================================================
<source code>

================================================================================
FILE: docker-compose.yml
================================================================================
<source code>

....

================================================================================
FILE: srcmainjavarumcsscannerprofileScannerProfileApplication.java
================================================================================
<source code>

================================================================================
FILE: srcmainjavarumcsscannerprofilecontrollerTestController.java
================================================================================
<source code>

================================================================================
FILE: srcmainjavarumcsscannerprofileserviceAiRecommendationService.java
================================================================================
<source code>

....

Зачем это вообще нужно

Многие могут возразить: а зачем, если есть GitHub Copilot, Codex или Claude, которые видят весь проект?

Отвечаю:

  • Стоимость. Copilot и Claude с доступом к репозиторию — платные. DeepSeek бесплатный и при этом хорошо работает с кодом.

  • Независимость от IDE. Скрипт работает из терминала. Никаких плагинов, расширений, привязки к VS Code или IDEA.

  • Работа с любой моделью. Сегодня DeepSeek, завтра — любая другая модель в браузере или API. Один файл подходит для всех.

  • Приватность. Ты видишь точно, что ты отдаёшь. Не «модель проиндексировала репозиторий», а конкретный текстовый файл, который можно открыть и проверить.

Для меня это способ быстро начать новый чат с нейросетью и напомнить ей, что уже было в прошлом обсуждении, без долгого ручного копирования файлов.

Не идеальный инструмент, а просто маленькая утилита, которая экономит время в реальной работе.

P.S. Надеюсь, скрипт окажется полезен кому-то ещё.

Автор: FilipLinx

Источник