package com.jibanez.clgeneratoraiservice;

import com.jibanez.clgeneratoraiservice.service.CoverLetterAiService;
import com.jibanez.clgeneratoraiservice.service.JobDetailsExtractorAiService;
import com.jibanez.clgeneratoraiservice.util.AiDemoService;
import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.DocumentSplitter;
import dev.langchain4j.data.document.parser.TextDocumentParser;
import dev.langchain4j.data.document.splitter.DocumentSplitters;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.embedding.AllMiniLmL6V2EmbeddingModel;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.rag.content.retriever.ContentRetriever;
import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.EmbeddingStoreIngestor;
import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;

import java.io.IOException;

import static dev.langchain4j.data.document.loader.FileSystemDocumentLoader.loadDocument;

@SpringBootApplication
public class ClGeneratorAiServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(ClGeneratorAiServiceApplication.class, args);
    }

    @Bean
    AiDemoService aiDemoService(ChatLanguageModel chatLanguageModel,
//                                              BookingTools bookingTools,
                                ContentRetriever contentRetriever) {
        return AiServices.builder(AiDemoService.class)
                .chatLanguageModel(chatLanguageModel)
                .chatMemory(MessageWindowChatMemory.withMaxMessages(20))
//                .tools(bookingTools)
                .contentRetriever(contentRetriever)
                .build();
    }

    @Bean
    CoverLetterAiService coverLetterAiService(ChatLanguageModel chatLanguageModel,
//                                              BookingTools bookingTools,
                                              ContentRetriever contentRetriever) {
        return AiServices.builder(CoverLetterAiService.class)
                .chatLanguageModel(chatLanguageModel)
                .chatMemory(MessageWindowChatMemory.withMaxMessages(20))
//                .tools(bookingTools)
                .contentRetriever(contentRetriever)
                .build();
    }

    @Bean
    JobDetailsExtractorAiService jobDetailsExtractorAiService(ChatLanguageModel chatLanguageModel) {
        return AiServices.builder(JobDetailsExtractorAiService.class)
                .chatLanguageModel(chatLanguageModel)
                .build();
    }

    @Bean
    ContentRetriever contentRetriever(EmbeddingStore<TextSegment> embeddingStore, EmbeddingModel embeddingModel) {

        // You will need to adjust these parameters to find the optimal setting, which will depend on two main factors:
        // - The nature of your data
        // - The embedding model you are using
        int maxResults = 10;
        double minScore = 0.6;

        return EmbeddingStoreContentRetriever.builder()
                .embeddingStore(embeddingStore)
                .embeddingModel(embeddingModel)
                .maxResults(maxResults)
                .minScore(minScore)
                .build();
    }


    @Bean
    EmbeddingModel embeddingModel() {
        return new AllMiniLmL6V2EmbeddingModel();
    }

    @Bean
    EmbeddingStore<TextSegment> embeddingStore(EmbeddingModel embeddingModel, ResourceLoader resourceLoader) throws IOException {

        // Normally, you would already have your embedding store filled with your data.
        // However, for the purpose of this demonstration, we will:

        // 1. Create an in-memory embedding store
        EmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();

        // 2. Load a document with user data
        Resource resource = resourceLoader.getResource("classpath:user-data.txt");
        Document document = loadDocument(resource.getFile().toPath(), new TextDocumentParser());

        // 3. Split the document into segments 300 tokens each
        // 4. Convert segments into embeddings
        // 5. Store embeddings into embedding store
        // All this can be done manually, but we will use EmbeddingStoreIngestor to automate this:
        DocumentSplitter documentSplitter = DocumentSplitters.recursive(300, 0);
        EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
                .documentSplitter(documentSplitter)
                .embeddingModel(embeddingModel)
                .embeddingStore(embeddingStore)
                .build();
        ingestor.ingest(document);

        return embeddingStore;
    }

}

dev.langchain4j.store.embedding.EmbeddingStoreIngestor.builder dev.langchain4j.service.AiServices.builder dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever.builder
[((1966, 2248), 'dev.langchain4j.service.AiServices.builder'), ((1966, 2223), 'dev.langchain4j.service.AiServices.builder'), ((1966, 2132), 'dev.langchain4j.service.AiServices.builder'), ((1966, 2059), 'dev.langchain4j.service.AiServices.builder'), ((2523, 2812), 'dev.langchain4j.service.AiServices.builder'), ((2523, 2787), 'dev.langchain4j.service.AiServices.builder'), ((2523, 2696), 'dev.langchain4j.service.AiServices.builder'), ((2523, 2623), 'dev.langchain4j.service.AiServices.builder'), ((2947, 3080), 'dev.langchain4j.service.AiServices.builder'), ((2947, 3055), 'dev.langchain4j.service.AiServices.builder'), ((3495, 3732), 'dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever.builder'), ((3495, 3707), 'dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever.builder'), ((3495, 3671), 'dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever.builder'), ((3495, 3631), 'dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever.builder'), ((3495, 3583), 'dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever.builder'), ((4891, 5096), 'dev.langchain4j.store.embedding.EmbeddingStoreIngestor.builder'), ((4891, 5071), 'dev.langchain4j.store.embedding.EmbeddingStoreIngestor.builder'), ((4891, 5023), 'dev.langchain4j.store.embedding.EmbeddingStoreIngestor.builder'), ((4891, 4975), 'dev.langchain4j.store.embedding.EmbeddingStoreIngestor.builder')]