-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathc_query_console_bot.cs
178 lines (148 loc) · 6.16 KB
/
c_query_console_bot.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
using System;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Reflection;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
namespace LM_Manual_Bot
{
class Program
{
private static readonly string PineconeIndexName = "";
private static readonly string EmbeddingModel = "";
private static readonly string OpenAIApiKey = "";
private static readonly string PineconeApiKey = "";
private static readonly string PineconeProject = "";
private static readonly string PineconeEnvironment = "";
private static HttpClient httpClient = new HttpClient();
static async Task Main(string[] args)
{
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", OpenAIApiKey);
httpClient.DefaultRequestHeaders.Add("Api-Key", PineconeApiKey);
while (true)
{
Console.Write("Enter your query: ");
string query = Console.ReadLine();
if (query.ToLower() == "quit")
{
break;
}
string answer = await Answer(query);
Console.WriteLine($"Answer: {answer}\n");
}
}
static async Task<string[]> RetrieveContext(string query)
{
string openaiUrl = "https://api.openai.com/v1/embeddings";
var payload = new
{
input = query,
model = EmbeddingModel
};
var content = new StringContent(JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync(openaiUrl, content);
var jsonResponse = await response.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<OpenAIEmbedResponse>(jsonResponse);
float[] xq = result.data[0].embedding;
string pineconeUrl = $"https://{PineconeIndexName}-{PineconeProject}.svc.{PineconeEnvironment}.pinecone.io/query";
int topK = 3;
bool includeValues = true;
var pineconeResponse = await SendPineconeQuery(pineconeUrl, xq, topK, includeValues);
var pineconeResult = JsonSerializer.Deserialize<PineconeQueryResponse>(pineconeResponse);
var contexts = pineconeResult.matches.Select(x => x.metadata.GetProperty("text").ToString()).ToArray();
return contexts;
}
static async Task<string> SendPineconeQuery(string url, float[] vector, int topK, bool includeValues)
{
var payload = new
{
vector = vector,
topK = topK,
includeValues = includeValues,
includeMetadata = true
};
var content = new StringContent(JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync(url, content);
var jsonResponse = await response.Content.ReadAsStringAsync();
return jsonResponse;
}
static async Task<string> Complete(string prompt)
{
string openaiUrl = "https://api.openai.com/v1/engines/text-davinci-003/completions";
var payload = new
{
prompt = prompt,
temperature = 0,
max_tokens = 400,
top_p = 1,
frequency_penalty = 0,
presence_penalty = 0
};
var content = new StringContent(JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json");
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", OpenAIApiKey);
var response = await httpClient.PostAsync(openaiUrl, content);
var jsonResponse = await response.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<OpenAICompletionResponse>(jsonResponse);
return result.choices[0].text.Trim();
}
static string BuildPrompt(string query, string[] context)
{
int contextLimit = 3750;
string promptStart = "Answer the question using only the context provided.\n\n" +
"Format instructions as an ordered list when possible.\n\n" +
"If you do not know the answer, respond with: I'm sorry, I don't have an answer for that.\n\n" +
"Context:\n";
string promptEnd = $"\n\nQuestion: {query}\nAnswer:\n";
string prompt = null;
for (int i = 1; i < context.Length; i++)
{
if (string.Join("\n\n---\n\n", context.Take(i)).Length >= contextLimit)
{
prompt = promptStart + string.Join("\n\n---\n\n", context.Take(i - 1)) + promptEnd;
break;
}
else if (i == context.Length - 1)
{
prompt = promptStart + string.Join("\n\n---\n\n", context) + promptEnd;
}
}
return prompt;
}
static async Task<string> Answer(string query)
{
string[] context = await RetrieveContext(query);
string prompt = BuildPrompt(query, context);
string answer = await Complete(prompt);
return answer;
}
}
// Helper classes for deserializing JSON responses
public class OpenAIEmbedResponse
{
public OpenAIEmbedData[] data { get; set; }
}
public class OpenAIEmbedData
{
public float[] embedding { get; set; }
}
public class PineconeQueryResponse
{
public PineconeQueryMatch[] matches { get; set; }
}
public class PineconeQueryMatch
{
public float score { get; set; }
public string id { get; set; }
public JsonElement metadata { get; set; }
}
public class OpenAICompletionResponse
{
public OpenAICompletionChoice[] choices { get; set; }
}
public class OpenAICompletionChoice
{
public string text { get; set; }
}
}