-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcortexChat.js
127 lines (114 loc) · 5.04 KB
/
cortexChat.js
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
class CortexChat {
constructor(jwt, agentUrl, model, searchService, semanticModels) {
this.jwt = jwt;
this.agentUrl = agentUrl;
this.model = model;
this.searchService = searchService;
this.semanticModels = semanticModels;
}
async _retrieveResponse(query, limit = 1) {
const headers = {
'X-Snowflake-Authorization-Token-Type': 'KEYPAIR_JWT',
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': `Bearer ${this.jwt}`
};
const data = {
model: this.model,
messages: [{ role: "user", content: [{ type: "text", text: query }] }],
tools: [
{ tool_spec: { type: "cortex_search", name: "vehicles_info_search" } },
{ tool_spec: { type: "cortex_analyst_text_to_sql", name: "support" } },
{ tool_spec: { type: "cortex_analyst_text_to_sql", name: "supply_chain" } }
],
tool_resources: {
vehicles_info_search: {
name: this.searchService,
max_results: limit,
title_column: "title",
id_column: "relative_path"
},
support: { semantic_model_file: this.semanticModels[0] },
supply_chain: { semantic_model_file: this.semanticModels[1] }
}
};
try {
const response = await fetch(this.agentUrl, { method: "POST", headers, body: JSON.stringify(data) });
if (!response.ok) throw new Error(`Response status: ${response.status}`);
return await this._parseResponse(response);
} catch (error) {
console.error("Error fetching response:", error);
return { text: "An error occurred." };
}
}
async _parseResponse(response) {
const reader = response.body.getReader();
const decoder = new TextDecoder();
let accumulated = { text: "", tool_results: [] };
let done = false;
while (!done) {
const { value, done: readerDone } = await reader.read();
if (value) {
const chunk = decoder.decode(value, { stream: true });
const result = this._processSSELine(chunk);
if (result.type === "message") {
accumulated.text += result.content.text;
accumulated.tool_results.push(...result.content.tool_results);
}
}
done = readerDone;
}
let text = accumulated.text;
let sql = "";
let citations = "";
// Process tool_results which contains objects with 'content' array
if (Array.isArray(accumulated.tool_results)) {
accumulated.tool_results.forEach(result => {
if (result.content && Array.isArray(result.content)) {
result.content.forEach(contentItem => {
if (contentItem.json) {
// Check for SQL in the json object
if (contentItem.json.sql) {
sql = contentItem.json.sql;
}
// Check for searchResults in the json object
if (contentItem.json.searchResults) {
contentItem.json.searchResults.forEach(searchResult => {
citations += `${searchResult.text}`;
text = text.replace(/【†[1-3]†】/g, "").replace(" .", ".") + "+";
citations = ` \n\r ${citations} \n\n[Source: ${searchResult.doc_id}]`;
});
}
}
});
} else {
console.warn("Unexpected structure in content:", result.content);
}
});
} else {
console.warn("tool_results is not an array:", accumulated.tool_results);
}
return { text, sql, citations };
}
_processSSELine(line) {
try {
const jsonStr = line.split("\n")[1]?.slice(6)?.trim();
if (!jsonStr || jsonStr === "[DONE]") return { type: "done" };
const data = JSON.parse(jsonStr);
if (data.object === "message.delta" && data.delta.content) {
return { type: "message", content: this._parseDeltaContent(data.delta.content) };
}
return { type: "other", data };
} catch (error) {
return { type: "error", message: `Failed to parse: ${line}` };
}
}
_parseDeltaContent(content) {
return content.reduce((acc, entry) => {
if (entry.type === "text") acc.text += entry.text;
else if (entry.type === "tool_results") acc.tool_results.push(entry.tool_results);
return acc;
}, { text: "", tool_results: [] });
}
}
module.exports = CortexChat;