1
+ // Copyright (c) 2024
2
+ // Author : Bruno Capuano
3
+ // Change Log :
4
+ // - Sample console application to use a local model hosted in ollama and semantic memory for search
5
+ //
6
+ // The MIT License (MIT)
7
+ //
8
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ // of this software and associated documentation files (the "Software"), to deal
10
+ // in the Software without restriction, including without limitation the rights
11
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ // copies of the Software, and to permit persons to whom the Software is
13
+ // furnished to do so, subject to the following conditions:
14
+ //
15
+ // The above copyright notice and this permission notice shall be included in
16
+ // all copies or substantial portions of the Software.
17
+ //
18
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ // THE SOFTWARE.
25
+
26
+ #pragma warning disable SKEXP0001 , SKEXP0003 , SKEXP0010 , SKEXP0011 , SKEXP0050 , SKEXP0052 , SKEXP0070
27
+
28
+ using Microsoft . KernelMemory ;
29
+ using Microsoft . KernelMemory . AI . Ollama ;
30
+ using Microsoft . SemanticKernel ;
31
+
32
+ var ollamaEndpoint = "http://localhost:11434" ;
33
+ //var modelIdChat = "phi";
34
+ var modelIdChat = "deepseek-r1" ;
35
+ var modelIdEmbeddings = "all-minilm" ;
36
+
37
+ // questions
38
+ var questionEn = "What is Bruno's favourite super hero?" ;
39
+ var questionEn2 = "How many people watched Venom 3?" ;
40
+ var question = questionEn2 ;
41
+
42
+ // intro
43
+ SpectreConsoleOutput . DisplayTitle ( modelIdChat ) ;
44
+ SpectreConsoleOutput . DisplayTitleH2 ( $ "This program will answer the following question:") ;
45
+ SpectreConsoleOutput . DisplayTitleH3 ( question ) ;
46
+ SpectreConsoleOutput . DisplayTitleH2 ( $ "Approach:") ;
47
+ SpectreConsoleOutput . DisplayTitleH3 ( $ "1st approach will be to ask the question directly to the { modelIdChat } model.") ;
48
+ SpectreConsoleOutput . DisplayTitleH3 ( "2nd approach will be to add facts to a semantic memory and ask the question again" ) ;
49
+
50
+ SpectreConsoleOutput . DisplayTitleH2 ( $ "{ modelIdChat } response (no memory).") ;
51
+
52
+ // Create a kernel with Azure OpenAI chat completion
53
+ var builder = Kernel . CreateBuilder ( ) . AddOllamaChatCompletion (
54
+ modelId : modelIdChat ,
55
+ endpoint : new Uri ( ollamaEndpoint ) ) ;
56
+
57
+ Kernel kernel = builder . Build ( ) ;
58
+ var response = kernel . InvokePromptStreamingAsync ( question ) ;
59
+ await foreach ( var result in response )
60
+ {
61
+ SpectreConsoleOutput . WriteGreen ( result . ToString ( ) ) ;
62
+ }
63
+
64
+ // separator
65
+ Console . WriteLine ( "" ) ;
66
+ SpectreConsoleOutput . DisplaySeparator ( ) ;
67
+
68
+ var configOllamaKernelMemory = new OllamaConfig
69
+ {
70
+ Endpoint = ollamaEndpoint ,
71
+ TextModel = new OllamaModelConfig ( modelIdChat ) ,
72
+ EmbeddingModel = new OllamaModelConfig ( modelIdEmbeddings , 2048 )
73
+ } ;
74
+ var memory = new KernelMemoryBuilder ( )
75
+ . WithOllamaTextGeneration ( configOllamaKernelMemory )
76
+ . WithOllamaTextEmbeddingGeneration ( configOllamaKernelMemory )
77
+ . Build ( ) ;
78
+
79
+ var informationList = new List < string >
80
+ {
81
+ "Gisela's favourite super hero is Batman" ,
82
+ "Gisela watched Venom 3 2 weeks ago" ,
83
+ "Bruno's favourite super hero is Invincible" ,
84
+ "Bruno went to the cinema to watch Venom 3" ,
85
+ "Bruno doesn't like the super hero movie: Eternals" ,
86
+ "ACE and Goku watched the movies Venom 3 and Eternals" ,
87
+ } ;
88
+
89
+ SpectreConsoleOutput . DisplayTitleH2 ( $ "Information List") ;
90
+
91
+ int docId = 1 ;
92
+ foreach ( var info in informationList )
93
+ {
94
+ SpectreConsoleOutput . WriteYellow ( $ "Adding docId: { docId } - information: { info } ", true ) ;
95
+ await memory . ImportTextAsync ( info , docId . ToString ( ) ) ;
96
+ docId ++ ;
97
+ }
98
+
99
+ SpectreConsoleOutput . DisplayTitleH3 ( $ "Asking question with memory: { question } ") ;
100
+ var answer = memory . AskStreamingAsync ( question ) ;
101
+ await foreach ( var result in answer )
102
+ {
103
+ SpectreConsoleOutput . WriteGreen ( $ "{ result . Result } ") ;
104
+ SpectreConsoleOutput . DisplayNewLine ( ) ;
105
+ SpectreConsoleOutput . DisplayNewLine ( ) ;
106
+ SpectreConsoleOutput . WriteYellow ( $ "Token Usage", true ) ;
107
+ foreach ( var token in result . TokenUsage )
108
+ {
109
+ SpectreConsoleOutput . WriteYellow ( $ "\t >> Tokens IN: { token . TokenizerTokensIn } ", true ) ;
110
+ SpectreConsoleOutput . WriteYellow ( $ "\t >> Tokens OUT: { token . TokenizerTokensOut } ", true ) ;
111
+ }
112
+
113
+ SpectreConsoleOutput . DisplayNewLine ( ) ;
114
+ SpectreConsoleOutput . WriteYellow ( $ "Sources", true ) ;
115
+ foreach ( var source in result . RelevantSources )
116
+ {
117
+ SpectreConsoleOutput . WriteYellow ( $ "\t >> Content Type: { source . SourceContentType } ", true ) ;
118
+ SpectreConsoleOutput . WriteYellow ( $ "\t >> Document Id: { source . DocumentId } ", true ) ;
119
+ SpectreConsoleOutput . WriteYellow ( $ "\t >> 1st Partition Text: { source . Partitions . FirstOrDefault ( ) . Text } ", true ) ;
120
+ SpectreConsoleOutput . WriteYellow ( $ "\t >> 1st Partition Relevance: { source . Partitions . FirstOrDefault ( ) . Relevance } ", true ) ;
121
+ SpectreConsoleOutput . DisplayNewLine ( ) ;
122
+ }
123
+
124
+
125
+ }
126
+
127
+ Console . WriteLine ( $ "" ) ;
0 commit comments