|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"use strict"; |
|
const MAX_PROMPT_LENGTH = 1024 * 80; |
|
|
|
const PROMPT_DECR = 1024 * 2; |
|
|
|
const TIMEOUT = 60000; |
|
|
|
function wait(seconds) { |
|
return new Promise((resolve) => setTimeout(resolve, seconds * 1000)); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const truncInput = (txt, decr) => { |
|
const tl = txt.length; |
|
const lim = tl - decr; |
|
const s = txt.substring(0, lim); |
|
return s; |
|
}; |
|
|
|
|
|
const setMaxLen = (s) => { |
|
const lim = MAX_PROMPT_LENGTH - 1000; |
|
return s.substring(0, lim); |
|
}; |
|
|
|
const getPartSize = (doc, prompt, decr) => { |
|
const limitWIthPoint = (s, free_len) => { |
|
const idx = s.indexOf(".", free_len); |
|
let lim = (idx != -1 ? idx : free_len) + 1; |
|
if (lim > free_len + 100) { |
|
lim = free_len; |
|
} |
|
return lim; |
|
}; |
|
const dpl = doc.length + prompt.length; |
|
const free_len = MAX_PROMPT_LENGTH - decr; |
|
let size = 0; |
|
if (dpl < free_len) { |
|
size = doc.length; |
|
} else { |
|
size = limitWIthPoint(doc, free_len); |
|
} |
|
return size; |
|
}; |
|
|
|
const getPartDoc = (pRgt, partSize) => { |
|
const pLft = pRgt.substring(0, partSize); |
|
pRgt = pRgt.substring(partSize).trim(); |
|
return [pLft, pRgt]; |
|
}; |
|
|
|
const ragLog = (msg, lftL, rgtL, answers) => { |
|
const maxl = MAX_PROMPT_LENGTH; |
|
const rspsL = answers.reduce((acc, cur) => { |
|
return acc + cur.length; |
|
}, 0); |
|
let s = `${msg} mx:${maxl} lft:${lftL} rgt:${rgtL} arr:${rspsL}`; |
|
xlog(s); |
|
const row = formatRow([msg, lftL, rgtL, rspsL], [8, -7, -7, -7]); |
|
UaLog.log(row); |
|
}; |
|
|
|
const Rag = { |
|
|
|
ragContext: "", |
|
|
|
ragQuery: "", |
|
|
|
ragAnswer: "", |
|
answers: [], |
|
docContextLst: [], |
|
prompts: [], |
|
doc: "", |
|
doc_part: "", |
|
init() { |
|
this.readRespsFromDb(); |
|
this.readFromDb(); |
|
}, |
|
returnOk() { |
|
const ok = this.ragContext.length > 10; |
|
return ok; |
|
}, |
|
saveToDb() { |
|
const js = { |
|
context: this.ragContext, |
|
ragquery: this.ragQuery, |
|
raganswer: this.ragAnswer, |
|
}; |
|
UaDb.saveJson(ID_RAG, js); |
|
UaDb.saveArray(ID_THREAD, ThreadMgr.rows); |
|
}, |
|
readFromDb() { |
|
const js = UaDb.readJson(ID_RAG); |
|
this.ragContext = js.context || ""; |
|
this.ragQuery = js.ragquery || ""; |
|
this.ragAnswer = js.raganswer || ""; |
|
ThreadMgr.rows = UaDb.readArray(ID_THREAD); |
|
}, |
|
saveRespToDb() { |
|
UaDb.saveArray(ID_RESPONSES, this.answers); |
|
}, |
|
readRespsFromDb() { |
|
this.answers = UaDb.readArray(ID_RESPONSES); |
|
}, |
|
|
|
|
|
|
|
|
|
async requestDocsRAG(query) { |
|
DataMgr.deleteJsonDati(); |
|
DataMgr.readDbDocNames(); |
|
DataMgr.readDbDocs(); |
|
this.ragQuery = query; |
|
this.saveToDb(); |
|
let ndoc = 0; |
|
try { |
|
let j = 1; |
|
for (let i = 0; i < DataMgr.docs.length; i++) { |
|
let doc = DataMgr.docs[i]; |
|
if (doc.trim() == "") continue; |
|
const docName = DataMgr.doc_names[i]; |
|
const doc_entire_len = doc.length; |
|
xlog(`${docName} (${doc_entire_len}) `); |
|
UaLog.log(`${docName} (${doc_entire_len}) `); |
|
++ndoc; |
|
let npart = 1; |
|
let decr = 0; |
|
let prompt = ""; |
|
let lft = ""; |
|
let rgt = ""; |
|
let answer = ""; |
|
let docAnswersLst = []; |
|
|
|
while (true) { |
|
let partSize = getPartSize(doc, promptDoc("", query, ""), decr); |
|
if (partSize < 10) { |
|
break; |
|
} |
|
[lft, rgt] = getPartDoc(doc, partSize); |
|
ragLog(`${j}) ${ndoc},${npart}`, lft.length, rgt.length, this.answers); |
|
prompt = promptDoc(lft, query, docName); |
|
const payload = getPayloadDoc(prompt); |
|
|
|
try { |
|
answer = await HfRequest.post(payload, TIMEOUT); |
|
if (!answer) return ""; |
|
} catch (err) { |
|
console.error(`RR1)\n`, err); |
|
const ei = getErrorInfo(err); |
|
if (ei.errorType === ERROR_TOKENS) { |
|
UaLog.log(`Error tokens Doc ${prompt.length}`); |
|
decr += PROMPT_DECR; |
|
continue; |
|
} else if (ei.errorType === TIMEOUT_ERROR) { |
|
UaLog.log(`Error timeout Doc`); |
|
continue; |
|
} else { |
|
UaLog.log(`Error ${err}`); |
|
answer = `ERROR \n${err}\n`; |
|
|
|
} |
|
} |
|
|
|
|
|
|
|
npart++; |
|
j++; |
|
doc = rgt; |
|
answer = cleanResponse(answer); |
|
docAnswersLst.push(answer); |
|
const s = `DOCUMENTO : ${docName}_${npart}\n${answer}`; |
|
this.answers.push(s); |
|
} |
|
|
|
const docAnswersLen = docAnswersLst.length; |
|
let docAnswresTxt = docAnswersLst.join("\n\n"); |
|
let docContext = ""; |
|
|
|
while (true) { |
|
prompt = promptBuildContext(docAnswresTxt, this.ragQuery); |
|
const payload = getPayloadBuildContext(prompt); |
|
try { |
|
docContext = await HfRequest.post(payload, TIMEOUT); |
|
if (!docContext) return ""; |
|
} catch (err) { |
|
console.error(`RR2)`, err); |
|
const ei = getErrorInfo(err); |
|
if (ei.errorType === ERROR_TOKENS) { |
|
UaLog.log(`Error tokens build Context ${prompt.length}`); |
|
docAnswresTxt = truncInput(docAnswresTxt, PROMPT_DECR); |
|
docAnswresTxt = setMaxLen(docAnswresTxt); |
|
continue; |
|
} else if (ei.errorType === TIMEOUT_ERROR) { |
|
UaLog.log(`Error timeout build Context`); |
|
|
|
continue; |
|
} else { |
|
throw err; |
|
} |
|
} |
|
break; |
|
} |
|
UaLog.log(`context ${docAnswersLen} => ${docContext.length}`); |
|
docContext = `\n### DOCUMENTO: ${docName}\n ${docContext}`; |
|
this.docContextLst.push(docContext); |
|
} |
|
} catch (err) { |
|
console.error(err); |
|
throw err; |
|
} |
|
this.ragContext = this.docContextLst.join("\n\n"); |
|
this.saveToDb(); |
|
|
|
|
|
{ |
|
let answer = ""; |
|
let context = this.ragContext; |
|
try { |
|
while (true) { |
|
let prompt = promptWithContext(context, query); |
|
const payload = getPayloadWithContext(prompt); |
|
try { |
|
answer = await HfRequest.post(payload, TIMEOUT); |
|
if (!answer) return ""; |
|
} catch (err) { |
|
console.error(`RR3)`, err); |
|
const ei = getErrorInfo(err); |
|
if (ei.errorType === ERROR_TOKENS) { |
|
UaLog.log(`Error tokens with Context ${prompt.length}`); |
|
context = truncInput(context, PROMPT_DECR); |
|
context = setMaxLen(context); |
|
continue; |
|
} else if (ei.errorType === TIMEOUT_ERROR) { |
|
UaLog.log(`Error timeout with Context`); |
|
|
|
continue; |
|
} else { |
|
throw err; |
|
} |
|
} |
|
break; |
|
} |
|
answer = cleanResponse(answer); |
|
this.ragAnswer = answer; |
|
this.saveRespToDb(); |
|
ThreadMgr.init(); |
|
this.saveToDb(); |
|
UaLog.log(`Risposta (${this.ragAnswer.length})`); |
|
} catch (err) { |
|
console.error(err); |
|
answer = `${err}`; |
|
throw err; |
|
} finally { |
|
return answer; |
|
} |
|
} |
|
}, |
|
|
|
|
|
async requestContext(query) { |
|
let text = ""; |
|
if (!this.ragContext) { |
|
const ok = await confirm("Contesto vuoto. Vuoi continuare?"); |
|
if (!ok) return ""; |
|
|
|
this.ragContext = "Sei un assitente AI dispoibile a soddisfare tutte le mi richieste"; |
|
} |
|
if (ThreadMgr.isFirst()) { |
|
ThreadMgr.init(); |
|
try { |
|
let context = this.ragContext; |
|
let thread = ThreadMgr.getThread(); |
|
|
|
while (true) { |
|
prompt = promptThread(context, thread, query); |
|
const payload = getPayloadThread(prompt); |
|
try { |
|
text = await HfRequest.post(payload, TIMEOUT); |
|
if (!text) return ""; |
|
} catch (err) { |
|
console.error(`RR4)`, err); |
|
const ei = getErrorInfo(err); |
|
if (ei.errorType === ERROR_TOKENS) { |
|
UaLog.log(`Error tokens Thread Init ${prompt.length}`); |
|
thread = truncInput(thread, PROMPT_DECR); |
|
context = setMaxLen(context); |
|
continue; |
|
} else if (ei.errorType === TIMEOUT_ERROR) { |
|
UaLog.log(`Error timeout Thread Init`); |
|
continue; |
|
} else { |
|
throw err; |
|
} |
|
} |
|
break; |
|
} |
|
text = cleanResponse(text); |
|
ThreadMgr.add(query, text); |
|
text = ThreadMgr.getThread(); |
|
UaLog.log(`Inizio Conversazione (${prompt.length})`); |
|
} catch (err) { |
|
console.error(err); |
|
text = `${err}`; |
|
throw err; |
|
} finally { |
|
return text; |
|
} |
|
} else { |
|
try { |
|
let context = this.ragContext; |
|
let thread = ThreadMgr.getThread(); |
|
let prompt = ""; |
|
while (true) { |
|
prompt = promptThread(context, thread, query); |
|
const payload = getPayloadThread(prompt); |
|
try { |
|
text = await HfRequest.post(payload, TIMEOUT); |
|
if (!text) return ""; |
|
} catch (err) { |
|
console.error(`RR5)`, err); |
|
const ei = getErrorInfo(err); |
|
if (ei.errorType === ERROR_TOKENS) { |
|
UaLog.log(`Error tokens Thread ${prompt.length}`); |
|
thread = truncInput(thread, PROMPT_DECR); |
|
continue; |
|
} else if (ei.errorType === TIMEOUT_ERROR) { |
|
UaLog.log(`Error timeout Thread`); |
|
continue; |
|
} else { |
|
throw err; |
|
} |
|
} |
|
break; |
|
} |
|
text = cleanResponse(text); |
|
ThreadMgr.add(query, text); |
|
text = ThreadMgr.getThread(); |
|
UaLog.log(`Conversazione (${prompt.length})`); |
|
} catch (err) { |
|
console.error(err); |
|
text = `${err}`; |
|
throw err; |
|
} finally { |
|
return text; |
|
} |
|
} |
|
}, |
|
}; |
|
|
|
const LLM = "## Assistant:"; |
|
const USER = "## User:"; |
|
|
|
const ThreadMgr = { |
|
rows: [], |
|
init() { |
|
this.rows = []; |
|
if (!!Rag.ragAnswer) { |
|
this.add(Rag.ragQuery, Rag.ragAnswer); |
|
} else { |
|
this.add("", ""); |
|
} |
|
}, |
|
add(query, resp) { |
|
const row = [query, resp]; |
|
this.rows.push(row); |
|
UaDb.saveArray(ID_THREAD, ThreadMgr.rows); |
|
}, |
|
getThread() { |
|
const rows = []; |
|
for (const ua of this.rows) { |
|
const u = ua[0]; |
|
const a = ua[1]; |
|
rows.push(`${USER}\n${u}\n${LLM}\n${a}\n`); |
|
} |
|
return rows.join("\n\n"); |
|
}, |
|
isFirst() { |
|
return this.rows.length < 2; |
|
}, |
|
}; |
|
|