Upload ChatIPCv2.cpp
Browse files- ChatIPCv2.cpp +713 -0
ChatIPCv2.cpp
ADDED
|
@@ -0,0 +1,713 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include <algorithm>
|
| 2 |
+
#include <cstdint>
|
| 3 |
+
#include <cstdio>
|
| 4 |
+
#include <fstream>
|
| 5 |
+
#include <iostream>
|
| 6 |
+
#include <mutex>
|
| 7 |
+
#include <optional>
|
| 8 |
+
#include <sstream>
|
| 9 |
+
#include <stdexcept>
|
| 10 |
+
#include <string>
|
| 11 |
+
#include <unordered_map>
|
| 12 |
+
#include <unordered_set>
|
| 13 |
+
#include <vector>
|
| 14 |
+
|
| 15 |
+
#ifdef _OPENMP
|
| 16 |
+
#include <omp.h>
|
| 17 |
+
#else
|
| 18 |
+
inline int omp_get_max_threads(){ return 1; }
|
| 19 |
+
#endif
|
| 20 |
+
|
| 21 |
+
using namespace std;
|
| 22 |
+
|
| 23 |
+
static vector<string> tokenize_whitespace(const string &s){
|
| 24 |
+
istringstream iss(s);
|
| 25 |
+
vector<string> out;
|
| 26 |
+
string t;
|
| 27 |
+
while (iss >> t) out.push_back(t);
|
| 28 |
+
return out;
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
using StrPtr = const string*;
|
| 32 |
+
using TokenId = uint32_t;
|
| 33 |
+
static constexpr TokenId TOKEN_ID_INVALID = 0xFFFFFFFFu;
|
| 34 |
+
|
| 35 |
+
static inline size_t popcount_u64(uint64_t x){
|
| 36 |
+
#if defined(_MSC_VER)
|
| 37 |
+
return static_cast<size_t>(__popcnt64(x));
|
| 38 |
+
#else
|
| 39 |
+
return static_cast<size_t>(__builtin_popcountll(static_cast<unsigned long long>(x)));
|
| 40 |
+
#endif
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
struct StringInterner {
|
| 44 |
+
unordered_set<string> pool;
|
| 45 |
+
unordered_map<string, TokenId> id_by_string;
|
| 46 |
+
vector<const string*> string_by_id;
|
| 47 |
+
mutable mutex m;
|
| 48 |
+
|
| 49 |
+
const string* intern(const string &s){
|
| 50 |
+
lock_guard<mutex> lk(m);
|
| 51 |
+
|
| 52 |
+
auto [it, inserted] = pool.emplace(s);
|
| 53 |
+
if (inserted){
|
| 54 |
+
const TokenId id = static_cast<TokenId>(string_by_id.size());
|
| 55 |
+
id_by_string.emplace(*it, id);
|
| 56 |
+
string_by_id.push_back(&*it);
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
return &*it;
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
TokenId id_of(const string &s) const {
|
| 63 |
+
lock_guard<mutex> lk(m);
|
| 64 |
+
|
| 65 |
+
auto it = id_by_string.find(s);
|
| 66 |
+
return (it == id_by_string.end()) ? TOKEN_ID_INVALID : it->second;
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
TokenId id_of(const string *p) const {
|
| 70 |
+
return p ? id_of(*p) : TOKEN_ID_INVALID;
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
size_t size() const {
|
| 74 |
+
lock_guard<mutex> lk(m);
|
| 75 |
+
return string_by_id.size();
|
| 76 |
+
}
|
| 77 |
+
};
|
| 78 |
+
|
| 79 |
+
static inline void bitset_set(uint64_t *bits, size_t words, TokenId id){
|
| 80 |
+
if (id == TOKEN_ID_INVALID) return;
|
| 81 |
+
const size_t idx = static_cast<size_t>(id >> 6);
|
| 82 |
+
if (idx >= words) return;
|
| 83 |
+
bits[idx] |= (1ULL << (id & 63u));
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
static inline size_t bitset_count(const uint64_t *bits, size_t words){
|
| 87 |
+
size_t total = 0;
|
| 88 |
+
for (size_t i = 0; i < words; ++i) total += popcount_u64(bits[i]);
|
| 89 |
+
return total;
|
| 90 |
+
}
|
| 91 |
+
|
| 92 |
+
using NextSet = vector<StrPtr>;
|
| 93 |
+
|
| 94 |
+
struct NgramHash {
|
| 95 |
+
size_t operator()(const vector<StrPtr>& v) const noexcept {
|
| 96 |
+
size_t seed = v.size();
|
| 97 |
+
for(auto& p : v) {
|
| 98 |
+
seed ^= hash<StrPtr>()(p) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
| 99 |
+
}
|
| 100 |
+
return seed;
|
| 101 |
+
}
|
| 102 |
+
};
|
| 103 |
+
|
| 104 |
+
struct KnowledgeBase {
|
| 105 |
+
StringInterner interner;
|
| 106 |
+
// Modified to use a vector of StrPtr (N-gram) as the key
|
| 107 |
+
unordered_map<vector<StrPtr>, NextSet, NgramHash> next;
|
| 108 |
+
mutable mutex m;
|
| 109 |
+
|
| 110 |
+
void add_ngram(const vector<StrPtr>& ctx, StrPtr v){
|
| 111 |
+
lock_guard<mutex> lk(m);
|
| 112 |
+
auto &vec = next[ctx];
|
| 113 |
+
for (auto p : vec) if (p == v) return;
|
| 114 |
+
vec.push_back(v);
|
| 115 |
+
}
|
| 116 |
+
|
| 117 |
+
optional<NextSet> lookup_ngram(const vector<StrPtr>& ctx) const {
|
| 118 |
+
lock_guard<mutex> lk(m);
|
| 119 |
+
auto it = next.find(ctx);
|
| 120 |
+
if (it == next.end()) return nullopt;
|
| 121 |
+
return it->second;
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
// Fast read-only lookup returning direct pointer to avoid mutex locking and vector copies
|
| 125 |
+
const NextSet* lookup_ngram_fast(const vector<StrPtr>& ctx) const {
|
| 126 |
+
auto it = next.find(ctx);
|
| 127 |
+
return (it != next.end()) ? &(it->second) : nullptr;
|
| 128 |
+
}
|
| 129 |
+
};
|
| 130 |
+
|
| 131 |
+
static void learn_tokens_ngram(KnowledgeBase &kb, const vector<string>& tokens, int n_gram_size) {
|
| 132 |
+
vector<StrPtr> window;
|
| 133 |
+
for (const auto& tok : tokens) {
|
| 134 |
+
StrPtr tp = kb.interner.intern(tok);
|
| 135 |
+
for (size_t j = 0; j < window.size(); ++j) {
|
| 136 |
+
vector<StrPtr> ctx(window.begin() + j, window.end());
|
| 137 |
+
kb.add_ngram(ctx, tp);
|
| 138 |
+
}
|
| 139 |
+
window.push_back(tp);
|
| 140 |
+
if (window.size() > static_cast<size_t>(n_gram_size)) window.erase(window.begin());
|
| 141 |
+
}
|
| 142 |
+
}
|
| 143 |
+
|
| 144 |
+
static vector<StrPtr>
|
| 145 |
+
intern_tokens(KnowledgeBase &kb, const vector<string> &tokens)
|
| 146 |
+
{
|
| 147 |
+
vector<StrPtr> out;
|
| 148 |
+
out.reserve(tokens.size());
|
| 149 |
+
for (const auto &t : tokens) out.push_back(kb.interner.intern(t));
|
| 150 |
+
return out;
|
| 151 |
+
}
|
| 152 |
+
|
| 153 |
+
|
| 154 |
+
static const NextSet* lookup_ngram_with_backoff(
|
| 155 |
+
const KnowledgeBase &kb,
|
| 156 |
+
const vector<StrPtr> &ctx_path,
|
| 157 |
+
int n_gram_size)
|
| 158 |
+
{
|
| 159 |
+
int cur_len = min(static_cast<int>(ctx_path.size()), n_gram_size);
|
| 160 |
+
while (cur_len > 0) {
|
| 161 |
+
vector<StrPtr> window(ctx_path.end() - cur_len, ctx_path.end());
|
| 162 |
+
const NextSet* res = kb.lookup_ngram_fast(window);
|
| 163 |
+
if (res && !res->empty()) {
|
| 164 |
+
return res;
|
| 165 |
+
}
|
| 166 |
+
cur_len--;
|
| 167 |
+
}
|
| 168 |
+
return nullptr;
|
| 169 |
+
}
|
| 170 |
+
|
| 171 |
+
struct CandState {
|
| 172 |
+
StrPtr orig_cand;
|
| 173 |
+
vector<vector<StrPtr>> frontier;
|
| 174 |
+
double total_score;
|
| 175 |
+
};
|
| 176 |
+
|
| 177 |
+
static string choose_candidate(
|
| 178 |
+
const NextSet &cands,
|
| 179 |
+
const vector<StrPtr> &history_ptrs,
|
| 180 |
+
const KnowledgeBase &kb,
|
| 181 |
+
const unordered_map<string, int> &recent_counts,
|
| 182 |
+
double repeat_penalty,
|
| 183 |
+
int n_gram_size)
|
| 184 |
+
{
|
| 185 |
+
if (cands.empty()) return string();
|
| 186 |
+
if (cands.size() == 1) return *cands[0];
|
| 187 |
+
|
| 188 |
+
// 1. Build historical context bitset once
|
| 189 |
+
const size_t words = max<size_t>(1, (kb.interner.size() + 63u) / 64u);
|
| 190 |
+
vector<uint64_t> agg_words(words, 0ULL);
|
| 191 |
+
|
| 192 |
+
for (StrPtr t : history_ptrs) {
|
| 193 |
+
TokenId tid = kb.interner.id_of(t);
|
| 194 |
+
if (tid != TOKEN_ID_INVALID) bitset_set(agg_words.data(), words, tid);
|
| 195 |
+
}
|
| 196 |
+
const size_t agg_count = bitset_count(agg_words.data(), words);
|
| 197 |
+
|
| 198 |
+
// Build base context tail from history (up to N-1 tokens)
|
| 199 |
+
vector<StrPtr> base_ctx;
|
| 200 |
+
int base_len = min(static_cast<int>(history_ptrs.size()), n_gram_size - 1);
|
| 201 |
+
if (base_len > 0) {
|
| 202 |
+
base_ctx.assign(history_ptrs.end() - base_len, history_ptrs.end());
|
| 203 |
+
}
|
| 204 |
+
|
| 205 |
+
// 2. Initialize iterative state for ALL original candidates
|
| 206 |
+
vector<CandState> tied_states(cands.size());
|
| 207 |
+
for (size_t i = 0; i < cands.size(); ++i) {
|
| 208 |
+
tied_states[i].orig_cand = cands[i];
|
| 209 |
+
|
| 210 |
+
// Initial frontier path for candidate = base_ctx + candidate
|
| 211 |
+
vector<StrPtr> init_path = base_ctx;
|
| 212 |
+
init_path.push_back(cands[i]);
|
| 213 |
+
if (init_path.size() > static_cast<size_t>(n_gram_size)) {
|
| 214 |
+
init_path.erase(init_path.begin(), init_path.end() - n_gram_size);
|
| 215 |
+
}
|
| 216 |
+
|
| 217 |
+
tied_states[i].frontier.push_back(move(init_path));
|
| 218 |
+
tied_states[i].total_score = 0.0;
|
| 219 |
+
}
|
| 220 |
+
|
| 221 |
+
// 3. Iterative deepening BFS up to n_gram_size across all candidates
|
| 222 |
+
for (int depth = 1; depth <= n_gram_size; ++depth) {
|
| 223 |
+
|
| 224 |
+
#ifdef _OPENMP
|
| 225 |
+
#pragma omp parallel for schedule(dynamic)
|
| 226 |
+
#endif
|
| 227 |
+
for (ptrdiff_t i = 0; i < static_cast<ptrdiff_t>(tied_states.size()); ++i) {
|
| 228 |
+
double depth_max_score = -1.0;
|
| 229 |
+
vector<vector<StrPtr>> next_frontier;
|
| 230 |
+
|
| 231 |
+
for (const auto &path : tied_states[i].frontier) {
|
| 232 |
+
// Perform n-gram backoff lookup using the full path context
|
| 233 |
+
const NextSet* opt_next = lookup_ngram_with_backoff(kb, path, n_gram_size);
|
| 234 |
+
if (!opt_next || opt_next->empty()) continue;
|
| 235 |
+
|
| 236 |
+
size_t count = 0;
|
| 237 |
+
size_t inter = 0;
|
| 238 |
+
|
| 239 |
+
// O(1) bitwise lookups bypass allocating new bitsets
|
| 240 |
+
for (StrPtr nxt : *opt_next) {
|
| 241 |
+
TokenId nid = kb.interner.id_of(nxt);
|
| 242 |
+
if (nid != TOKEN_ID_INVALID) {
|
| 243 |
+
count++;
|
| 244 |
+
if ((agg_words[nid >> 6] & (1ULL << (nid & 63u))) != 0) {
|
| 245 |
+
inter++;
|
| 246 |
+
}
|
| 247 |
+
}
|
| 248 |
+
}
|
| 249 |
+
|
| 250 |
+
const size_t uni = agg_count + count - inter;
|
| 251 |
+
const double score = uni ? static_cast<double>(inter) / static_cast<double>(uni) : 0.0;
|
| 252 |
+
|
| 253 |
+
if (score > depth_max_score) {
|
| 254 |
+
depth_max_score = score;
|
| 255 |
+
}
|
| 256 |
+
|
| 257 |
+
// Append new context paths to next frontier if under max depth
|
| 258 |
+
if (depth < n_gram_size) {
|
| 259 |
+
for (StrPtr nxt : *opt_next) {
|
| 260 |
+
vector<StrPtr> next_path = path;
|
| 261 |
+
next_path.push_back(nxt);
|
| 262 |
+
if (next_path.size() > static_cast<size_t>(n_gram_size)) {
|
| 263 |
+
next_path.erase(next_path.begin(), next_path.end() - n_gram_size);
|
| 264 |
+
}
|
| 265 |
+
next_frontier.push_back(move(next_path));
|
| 266 |
+
}
|
| 267 |
+
}
|
| 268 |
+
}
|
| 269 |
+
|
| 270 |
+
// Apply repetition penalty on the base token level at depth 1
|
| 271 |
+
if (depth == 1) {
|
| 272 |
+
const string &tok = *(tied_states[i].orig_cand);
|
| 273 |
+
auto rc_it = recent_counts.find(tok);
|
| 274 |
+
const int cnt = (rc_it == recent_counts.end()) ? 0 : rc_it->second;
|
| 275 |
+
if (depth_max_score > -0.5) {
|
| 276 |
+
depth_max_score -= repeat_penalty * static_cast<double>(cnt);
|
| 277 |
+
} else {
|
| 278 |
+
depth_max_score = -repeat_penalty * static_cast<double>(cnt);
|
| 279 |
+
}
|
| 280 |
+
} else {
|
| 281 |
+
if (depth_max_score < 0.0) {
|
| 282 |
+
depth_max_score = 0.0;
|
| 283 |
+
}
|
| 284 |
+
}
|
| 285 |
+
|
| 286 |
+
// Accumulate depth score into candidate's total score
|
| 287 |
+
tied_states[i].total_score += depth_max_score;
|
| 288 |
+
|
| 289 |
+
// Deduplicate next frontier to prevent exponential path expansion
|
| 290 |
+
if (next_frontier.size() > 1) {
|
| 291 |
+
sort(next_frontier.begin(), next_frontier.end());
|
| 292 |
+
next_frontier.erase(unique(next_frontier.begin(), next_frontier.end()), next_frontier.end());
|
| 293 |
+
}
|
| 294 |
+
tied_states[i].frontier = move(next_frontier);
|
| 295 |
+
}
|
| 296 |
+
}
|
| 297 |
+
|
| 298 |
+
// 4. Final Selection: Identify highest total score across all depths
|
| 299 |
+
double best_total = -1e9;
|
| 300 |
+
for (const auto &st : tied_states) {
|
| 301 |
+
if (st.total_score > best_total) {
|
| 302 |
+
best_total = st.total_score;
|
| 303 |
+
}
|
| 304 |
+
}
|
| 305 |
+
|
| 306 |
+
// Collect all candidates tied for the best total score
|
| 307 |
+
vector<StrPtr> tied_cands;
|
| 308 |
+
for (const auto &st : tied_states) {
|
| 309 |
+
if (st.total_score >= best_total - 1e-9) {
|
| 310 |
+
tied_cands.push_back(st.orig_cand);
|
| 311 |
+
}
|
| 312 |
+
}
|
| 313 |
+
|
| 314 |
+
// Break remaining ties alphabetically
|
| 315 |
+
string best_tok = *(tied_cands[0]);
|
| 316 |
+
for (size_t i = 1; i < tied_cands.size(); ++i) {
|
| 317 |
+
if (*(tied_cands[i]) < best_tok) {
|
| 318 |
+
best_tok = *(tied_cands[i]);
|
| 319 |
+
}
|
| 320 |
+
}
|
| 321 |
+
|
| 322 |
+
return best_tok;
|
| 323 |
+
}
|
| 324 |
+
|
| 325 |
+
static vector<string> construct_response(KnowledgeBase &kb,
|
| 326 |
+
const vector<string> &prompt_toks,
|
| 327 |
+
size_t response_maxlen,
|
| 328 |
+
double repeat_penalty,
|
| 329 |
+
int n_gram_size,
|
| 330 |
+
bool allow_path_loops)
|
| 331 |
+
{
|
| 332 |
+
vector<string> resp;
|
| 333 |
+
if (prompt_toks.empty() || response_maxlen == 0) return resp;
|
| 334 |
+
|
| 335 |
+
auto prompt_ptrs = intern_tokens(kb, prompt_toks);
|
| 336 |
+
unordered_map<string, int> recent_counts;
|
| 337 |
+
|
| 338 |
+
// The context combines prompt and generated text
|
| 339 |
+
vector<StrPtr> context = prompt_ptrs;
|
| 340 |
+
|
| 341 |
+
auto would_create_2_cycle = [&](const string &cand) -> bool {
|
| 342 |
+
if (resp.size() < 3) return false;
|
| 343 |
+
return cand == resp[resp.size() - 2] &&
|
| 344 |
+
resp.back() == resp[resp.size() - 3];
|
| 345 |
+
};
|
| 346 |
+
|
| 347 |
+
for (size_t step = 0; step < response_maxlen; ++step){
|
| 348 |
+
NextSet candidates;
|
| 349 |
+
bool found = false;
|
| 350 |
+
|
| 351 |
+
int current_n = min(static_cast<int>(context.size()), n_gram_size);
|
| 352 |
+
while (current_n > 0) {
|
| 353 |
+
vector<StrPtr> search_ctx(context.end() - current_n, context.end());
|
| 354 |
+
auto opt = kb.lookup_ngram(search_ctx);
|
| 355 |
+
if (opt && !opt->empty()) {
|
| 356 |
+
candidates = *opt;
|
| 357 |
+
found = true;
|
| 358 |
+
break;
|
| 359 |
+
}
|
| 360 |
+
current_n--;
|
| 361 |
+
}
|
| 362 |
+
|
| 363 |
+
if (!found || candidates.empty()) break;
|
| 364 |
+
|
| 365 |
+
if (candidates.size() == 1){
|
| 366 |
+
string only = *candidates[0];
|
| 367 |
+
if (!allow_path_loops && recent_counts[only] > 0) break;
|
| 368 |
+
resp.push_back(only);
|
| 369 |
+
StrPtr ptr = kb.interner.intern(only);
|
| 370 |
+
context.push_back(ptr);
|
| 371 |
+
recent_counts[only] += 1;
|
| 372 |
+
cout << only << ' ' << flush;
|
| 373 |
+
continue;
|
| 374 |
+
}
|
| 375 |
+
|
| 376 |
+
string chosen = choose_candidate(
|
| 377 |
+
candidates, context, kb, recent_counts, repeat_penalty, n_gram_size
|
| 378 |
+
);
|
| 379 |
+
|
| 380 |
+
if (chosen.empty()) break;
|
| 381 |
+
if (!allow_path_loops && would_create_2_cycle(chosen)) break;
|
| 382 |
+
|
| 383 |
+
resp.push_back(chosen);
|
| 384 |
+
StrPtr chosen_ptr = kb.interner.intern(chosen);
|
| 385 |
+
context.push_back(chosen_ptr);
|
| 386 |
+
recent_counts[chosen] += 1;
|
| 387 |
+
cout << chosen << ' ' << flush;
|
| 388 |
+
}
|
| 389 |
+
|
| 390 |
+
return resp;
|
| 391 |
+
}
|
| 392 |
+
|
| 393 |
+
static void learn_from_file(KnowledgeBase &kb, const string &fname, int n_gram_size){
|
| 394 |
+
ifstream ifs(fname);
|
| 395 |
+
if (!ifs) return;
|
| 396 |
+
vector<string> tokens;
|
| 397 |
+
string tok;
|
| 398 |
+
while (ifs >> tok) tokens.push_back(tok);
|
| 399 |
+
learn_tokens_ngram(kb, tokens, n_gram_size);
|
| 400 |
+
}
|
| 401 |
+
|
| 402 |
+
static void learn_files_parallel(KnowledgeBase &kb, const vector<string> &files, int n_gram_size){
|
| 403 |
+
#pragma omp parallel for schedule(dynamic)
|
| 404 |
+
for (ptrdiff_t i=0;i<static_cast<ptrdiff_t>(files.size());++i){
|
| 405 |
+
learn_from_file(kb, files[(size_t)i], n_gram_size);
|
| 406 |
+
}
|
| 407 |
+
}
|
| 408 |
+
|
| 409 |
+
static constexpr uint64_t KB_MAGIC = 0x434850434B535641ULL;
|
| 410 |
+
static constexpr uint64_t KB_VERSION = 2ULL;
|
| 411 |
+
|
| 412 |
+
static void write_u64(ostream &os, uint64_t v) {
|
| 413 |
+
do {
|
| 414 |
+
unsigned char byte = v & 0x7F;
|
| 415 |
+
v >>= 7;
|
| 416 |
+
if (v != 0) byte |= 0x80;
|
| 417 |
+
os.put(static_cast<char>(byte));
|
| 418 |
+
} while (v != 0);
|
| 419 |
+
if (!os) throw runtime_error("write_u64 failed");
|
| 420 |
+
}
|
| 421 |
+
|
| 422 |
+
static uint64_t read_u64(istream &is) {
|
| 423 |
+
uint64_t v = 0;
|
| 424 |
+
unsigned int shift = 0;
|
| 425 |
+
unsigned char byte;
|
| 426 |
+
do {
|
| 427 |
+
if (!is.read(reinterpret_cast<char*>(&byte), 1)) {
|
| 428 |
+
throw runtime_error("read_u64 failed");
|
| 429 |
+
}
|
| 430 |
+
v |= (static_cast<uint64_t>(byte & 0x7F) << shift);
|
| 431 |
+
shift += 7;
|
| 432 |
+
} while (byte & 0x80);
|
| 433 |
+
return v;
|
| 434 |
+
}
|
| 435 |
+
|
| 436 |
+
static void write_string(ostream &os, const string &s){
|
| 437 |
+
write_u64(os, static_cast<uint64_t>(s.size()));
|
| 438 |
+
if (!s.empty()){
|
| 439 |
+
os.write(s.data(), static_cast<streamsize>(s.size()));
|
| 440 |
+
if(!os) throw runtime_error("write_string failed");
|
| 441 |
+
}
|
| 442 |
+
}
|
| 443 |
+
|
| 444 |
+
static string read_string(istream &is){
|
| 445 |
+
uint64_t n = read_u64(is);
|
| 446 |
+
//if (n > (1ULL << 30)) throw runtime_error("save file is corrupted: string too large");
|
| 447 |
+
|
| 448 |
+
string s;
|
| 449 |
+
s.resize(static_cast<size_t>(n));
|
| 450 |
+
|
| 451 |
+
if (n != 0){
|
| 452 |
+
is.read(&s[0], static_cast<streamsize>(n));
|
| 453 |
+
if(!is) throw runtime_error("read_string failed");
|
| 454 |
+
}
|
| 455 |
+
return s;
|
| 456 |
+
}
|
| 457 |
+
|
| 458 |
+
static void save_kb_binary(const KnowledgeBase &kb, const string &fname){
|
| 459 |
+
const string temp = fname + ".tmp";
|
| 460 |
+
|
| 461 |
+
{
|
| 462 |
+
ofstream ofs(temp.c_str(), ios::binary | ios::trunc);
|
| 463 |
+
if (!ofs) throw runtime_error("cannot open temp save file");
|
| 464 |
+
|
| 465 |
+
vector<string> pool;
|
| 466 |
+
pool.reserve(kb.interner.pool.size());
|
| 467 |
+
for (const auto &s : kb.interner.pool) pool.push_back(s);
|
| 468 |
+
|
| 469 |
+
sort(pool.begin(), pool.end());
|
| 470 |
+
|
| 471 |
+
unordered_map<string, uint64_t> id;
|
| 472 |
+
id.reserve(pool.size());
|
| 473 |
+
for (uint64_t i = 0; i < static_cast<uint64_t>(pool.size()); ++i){
|
| 474 |
+
id.emplace(pool[(size_t)i], i);
|
| 475 |
+
}
|
| 476 |
+
|
| 477 |
+
write_u64(ofs, KB_MAGIC);
|
| 478 |
+
write_u64(ofs, KB_VERSION);
|
| 479 |
+
|
| 480 |
+
write_u64(ofs, static_cast<uint64_t>(pool.size()));
|
| 481 |
+
for (const auto &s : pool) write_string(ofs, s);
|
| 482 |
+
|
| 483 |
+
write_u64(ofs, static_cast<uint64_t>(kb.next.size()));
|
| 484 |
+
for (const auto &pr : kb.next){
|
| 485 |
+
write_u64(ofs, static_cast<uint64_t>(pr.first.size()));
|
| 486 |
+
for (StrPtr ctx_tok : pr.first){
|
| 487 |
+
write_u64(ofs, id.at(*ctx_tok));
|
| 488 |
+
}
|
| 489 |
+
write_u64(ofs, static_cast<uint64_t>(pr.second.size()));
|
| 490 |
+
for (StrPtr nxt : pr.second){
|
| 491 |
+
write_u64(ofs, id.at(*nxt));
|
| 492 |
+
}
|
| 493 |
+
}
|
| 494 |
+
|
| 495 |
+
ofs.flush();
|
| 496 |
+
if (!ofs) throw runtime_error("failed while writing temp save file");
|
| 497 |
+
}
|
| 498 |
+
|
| 499 |
+
remove(fname.c_str());
|
| 500 |
+
if (rename(temp.c_str(), fname.c_str()) != 0){
|
| 501 |
+
remove(temp.c_str());
|
| 502 |
+
throw runtime_error("failed to commit save file");
|
| 503 |
+
}
|
| 504 |
+
}
|
| 505 |
+
|
| 506 |
+
static void load_kb_binary(KnowledgeBase &kb, const string &fname){
|
| 507 |
+
ifstream ifs(fname, ios::binary);
|
| 508 |
+
if (!ifs) throw runtime_error("cannot open load file");
|
| 509 |
+
|
| 510 |
+
const uint64_t magic = read_u64(ifs);
|
| 511 |
+
if (magic != KB_MAGIC) throw runtime_error("bad save file magic");
|
| 512 |
+
|
| 513 |
+
const uint64_t version = read_u64(ifs);
|
| 514 |
+
if (version != KB_VERSION) throw runtime_error("unsupported save file version");
|
| 515 |
+
|
| 516 |
+
const uint64_t N = read_u64(ifs);
|
| 517 |
+
//if (N > (1ULL << 26)) throw runtime_error("save file is corrupted: pool too large");
|
| 518 |
+
|
| 519 |
+
vector<string> strings;
|
| 520 |
+
strings.reserve(static_cast<size_t>(N));
|
| 521 |
+
|
| 522 |
+
for (uint64_t i = 0; i < N; ++i){
|
| 523 |
+
strings.push_back(read_string(ifs));
|
| 524 |
+
}
|
| 525 |
+
|
| 526 |
+
kb.interner.pool.clear();
|
| 527 |
+
kb.interner.pool.reserve(static_cast<size_t>(N));
|
| 528 |
+
|
| 529 |
+
vector<StrPtr> ptrs;
|
| 530 |
+
ptrs.reserve(static_cast<size_t>(N));
|
| 531 |
+
for (const auto &s : strings){
|
| 532 |
+
ptrs.push_back(kb.interner.intern(s));
|
| 533 |
+
}
|
| 534 |
+
|
| 535 |
+
// Rebuild next
|
| 536 |
+
const uint64_t E = read_u64(ifs);
|
| 537 |
+
//if (E > (1ULL << 26)) throw runtime_error("save file is corrupted: graph too large");
|
| 538 |
+
|
| 539 |
+
{
|
| 540 |
+
lock_guard<mutex> lk(kb.m);
|
| 541 |
+
kb.next.clear();
|
| 542 |
+
kb.next.reserve(static_cast<size_t>(E));
|
| 543 |
+
}
|
| 544 |
+
|
| 545 |
+
for (uint64_t i = 0; i < E; ++i){
|
| 546 |
+
const uint64_t ctx_size = read_u64(ifs);
|
| 547 |
+
//if (ctx_size > (1ULL << 16)) throw runtime_error("save file is corrupted: n-gram context too large");
|
| 548 |
+
|
| 549 |
+
vector<StrPtr> ctx;
|
| 550 |
+
ctx.reserve(static_cast<size_t>(ctx_size));
|
| 551 |
+
for(uint64_t c = 0; c < ctx_size; ++c) {
|
| 552 |
+
const uint64_t c_idx = read_u64(ifs);
|
| 553 |
+
if (c_idx >= ptrs.size()) throw runtime_error("save file is corrupted: bad context key");
|
| 554 |
+
ctx.push_back(ptrs[(size_t)c_idx]);
|
| 555 |
+
}
|
| 556 |
+
|
| 557 |
+
const uint64_t M = read_u64(ifs);
|
| 558 |
+
//if (M > (1ULL << 26)) throw runtime_error("save file is corrupted: graph degree too large");
|
| 559 |
+
|
| 560 |
+
NextSet vec;
|
| 561 |
+
vec.reserve(static_cast<size_t>(M));
|
| 562 |
+
|
| 563 |
+
for (uint64_t j = 0; j < M; ++j){
|
| 564 |
+
const uint64_t v_idx = read_u64(ifs);
|
| 565 |
+
if (v_idx >= ptrs.size()) throw runtime_error("save file is corrupted: bad graph value");
|
| 566 |
+
vec.push_back(ptrs[(size_t)v_idx]);
|
| 567 |
+
}
|
| 568 |
+
|
| 569 |
+
{
|
| 570 |
+
lock_guard<mutex> lk(kb.m);
|
| 571 |
+
kb.next.emplace(move(ctx), move(vec));
|
| 572 |
+
}
|
| 573 |
+
}
|
| 574 |
+
}
|
| 575 |
+
|
| 576 |
+
static void print_kb_info(const string &fname) {
|
| 577 |
+
ifstream ifs(fname, ios::binary);
|
| 578 |
+
if (!ifs) {
|
| 579 |
+
cerr << "Error: cannot open knowledge-base file " << fname << "\n";
|
| 580 |
+
return;
|
| 581 |
+
}
|
| 582 |
+
|
| 583 |
+
cout << "Reckoning knowledge-base " << fname << " info. ";
|
| 584 |
+
|
| 585 |
+
try {
|
| 586 |
+
const uint64_t magic = read_u64(ifs);
|
| 587 |
+
if (magic != KB_MAGIC) throw runtime_error("bad save file magic");
|
| 588 |
+
|
| 589 |
+
const uint64_t version = read_u64(ifs);
|
| 590 |
+
if (version != KB_VERSION) throw runtime_error("unsupported save file version");
|
| 591 |
+
|
| 592 |
+
const uint64_t N = read_u64(ifs);
|
| 593 |
+
//if (N > (1ULL << 26)) throw runtime_error("save file is corrupted: pool too large");
|
| 594 |
+
|
| 595 |
+
// Dynamically read and skip strings since lengths are now variable-length encoded
|
| 596 |
+
for (uint64_t i = 0; i < N; ++i){
|
| 597 |
+
uint64_t len = read_u64(ifs);
|
| 598 |
+
//if (len > (1ULL << 30)) throw runtime_error("save file is corrupted: string too large");
|
| 599 |
+
if (len > 0) ifs.seekg(static_cast<streamoff>(len), ios_base::cur);
|
| 600 |
+
}
|
| 601 |
+
|
| 602 |
+
const uint64_t E = read_u64(ifs);
|
| 603 |
+
//if (E > (1ULL << 26)) throw runtime_error("save file is corrupted: graph too large");
|
| 604 |
+
|
| 605 |
+
uint64_t max_ngram = 0;
|
| 606 |
+
for (uint64_t i = 0; i < E; ++i){
|
| 607 |
+
const uint64_t ctx_size = read_u64(ifs);
|
| 608 |
+
//if (ctx_size > (1ULL << 16)) throw runtime_error("save file is corrupted: n-gram context too large");
|
| 609 |
+
|
| 610 |
+
if (ctx_size > max_ngram) max_ngram = ctx_size;
|
| 611 |
+
|
| 612 |
+
// Sequentially read (and skip) context keys using LEB128 stream parsing
|
| 613 |
+
for(uint64_t c = 0; c < ctx_size; ++c) {
|
| 614 |
+
read_u64(ifs);
|
| 615 |
+
}
|
| 616 |
+
|
| 617 |
+
const uint64_t M = read_u64(ifs);
|
| 618 |
+
//if (M > (1ULL << 26)) throw runtime_error("save file is corrupted: graph degree too large");
|
| 619 |
+
|
| 620 |
+
// Sequentially read (and skip) next-node values
|
| 621 |
+
for(uint64_t j = 0; j < M; ++j){
|
| 622 |
+
read_u64(ifs);
|
| 623 |
+
}
|
| 624 |
+
}
|
| 625 |
+
|
| 626 |
+
cout << "The " << fname << " n-gram max size is " << max_ngram << "\n";
|
| 627 |
+
|
| 628 |
+
} catch (const exception &e) {
|
| 629 |
+
cerr << "Error reading knowledge-base info: " << e.what() << "\n";
|
| 630 |
+
}
|
| 631 |
+
}
|
| 632 |
+
|
| 633 |
+
static void print_commands(const char *p){
|
| 634 |
+
cout << p << " command-line interface options:\n";
|
| 635 |
+
cout << " --response-max-length N Set maximum number of token(s) in a response. Default number is 500\n";
|
| 636 |
+
cout << " --save-kb FILE Save the knowledge-base graph to a binary file.\n";
|
| 637 |
+
cout << " --load-kb FILE Load a previously saved knowledge-base graph from a binary file.\n";
|
| 638 |
+
cout << " --info-kb FILE Show the dictionary-depth and n-gram max size of a knowledge-base file.\n";
|
| 639 |
+
cout << " --static-kb Disable learning prompt(s) and response(s) during interactive session.\n";
|
| 640 |
+
cout << " --n-gram-max-size N Set maximum size of the n-gram where N is the size. Default size is 3\n";
|
| 641 |
+
cout << " --learn f1 f2 ... Learn from text file(s) to update the knowledge-base graph.\n";
|
| 642 |
+
cout << " --repeat-penalty P Set penalty for repeated tokens in response. Default penalty is 0.7 (higher penalty reduce repetition).\n";
|
| 643 |
+
cout << " --allow-path-loops Allow finite loops when the knowledge-base graph contains a circular single-path reference.\n";
|
| 644 |
+
cout << " --activate-agi Activate the Artificial General Intelligence (AGI) features.\n";
|
| 645 |
+
cout << " --help Show " << p << " command-line interface options.\n";
|
| 646 |
+
}
|
| 647 |
+
|
| 648 |
+
int main(int argc, char **argv){
|
| 649 |
+
size_t response_maxlen = 500;
|
| 650 |
+
string savefile;
|
| 651 |
+
string load_kb;
|
| 652 |
+
int n_gram_size = 3;
|
| 653 |
+
double repeat_penalty = 0.7; // default λ
|
| 654 |
+
vector<string> learn_files;
|
| 655 |
+
bool learn_chat = true;
|
| 656 |
+
bool allow_path_loops = false;
|
| 657 |
+
|
| 658 |
+
for (int i=1;i<argc;++i){
|
| 659 |
+
string a = argv[i];
|
| 660 |
+
if (a=="--help"){ print_commands(argv[0]); return 0; }
|
| 661 |
+
if (a=="--response-max-length" && i+1<argc){ response_maxlen = stoul(argv[++i]); continue; }
|
| 662 |
+
if (a=="--save-kb" && i+1<argc){ savefile = argv[++i]; continue; }
|
| 663 |
+
if (a=="--load-kb" && i+1<argc){ load_kb = argv[++i]; continue; }
|
| 664 |
+
if (a=="--info-kb" && i+1<argc){ print_kb_info(argv[++i]); return 0; }
|
| 665 |
+
if (a=="--static-kb"){ learn_chat = false; continue; }
|
| 666 |
+
if (a=="--n-gram-max-size" && i+1<argc){ n_gram_size = max(1, stoi(argv[++i])); continue; }
|
| 667 |
+
if (a=="--learn"){ while(i+1<argc && argv[i+1][0] != '-') learn_files.push_back(argv[++i]); continue; }
|
| 668 |
+
if (a=="--repeat-penalty" && i+1<argc){ repeat_penalty = stod(argv[++i]); continue; }
|
| 669 |
+
if (a=="--allow-path-loops") { allow_path_loops = true; continue; }
|
| 670 |
+
if (a=="--activate-agi"){
|
| 671 |
+
cerr << "AGI subscription fee is $1,000 CAD per month. To pay the fee, contact Caleb Nwokocha via email cnwokocha@proton.me\n";
|
| 672 |
+
return 0;
|
| 673 |
+
}
|
| 674 |
+
|
| 675 |
+
cerr << "Error: Unknown or incomplete command-line option '" << a << "'\n";
|
| 676 |
+
print_commands(argv[0]);
|
| 677 |
+
return 1;
|
| 678 |
+
}
|
| 679 |
+
|
| 680 |
+
KnowledgeBase kb;
|
| 681 |
+
|
| 682 |
+
if (!load_kb.empty()){
|
| 683 |
+
try { print_kb_info(load_kb);
|
| 684 |
+
cerr << "Loading knowledge base " << load_kb << " using values from " << argv[0] << " command-line interface options: --n-gram-max-size " << n_gram_size <<
|
| 685 |
+
", --response-max-length " << response_maxlen << ", and --repeat-penalty " << repeat_penalty << "\n";
|
| 686 |
+
cerr << "To change the value(s), use " << argv[0] << " command-line interface option(s).\n";
|
| 687 |
+
load_kb_binary(kb, load_kb); cerr << "Loaded knowledge base: " << load_kb << "\n"; }
|
| 688 |
+
catch (const exception &e){ cerr << "Error: " << e.what() << "\n"; }
|
| 689 |
+
}
|
| 690 |
+
|
| 691 |
+
if (!learn_files.empty()){
|
| 692 |
+
cerr << "Learning from file/s (" << learn_files.size() << ") using threads=" << omp_get_max_threads() << "\n";
|
| 693 |
+
learn_files_parallel(kb, learn_files, n_gram_size);
|
| 694 |
+
}
|
| 695 |
+
|
| 696 |
+
string line;
|
| 697 |
+
cout << "Ready. Enter prompts.\n";
|
| 698 |
+
while (cout << "> " , getline(cin, line)){
|
| 699 |
+
if (line.empty()){ cout << "\n"; continue; }
|
| 700 |
+
auto prompt_toks = tokenize_whitespace(line);
|
| 701 |
+
if (learn_chat) {learn_tokens_ngram(kb, prompt_toks, n_gram_size);}
|
| 702 |
+
auto resp = construct_response(kb, prompt_toks, response_maxlen, repeat_penalty, n_gram_size, allow_path_loops);
|
| 703 |
+
cout << "\n";
|
| 704 |
+
if (!resp.empty() && learn_chat){learn_tokens_ngram(kb, resp, n_gram_size);}
|
| 705 |
+
if (!savefile.empty()){
|
| 706 |
+
try { cerr << "Saving knowledge base: " << savefile << "\n";
|
| 707 |
+
save_kb_binary(kb, savefile); cerr << "Saved knowledge base: " << savefile << "\n"; }
|
| 708 |
+
catch (const exception &e){ cerr << "Error: " << e.what() << "\n"; }
|
| 709 |
+
}
|
| 710 |
+
}
|
| 711 |
+
|
| 712 |
+
return 0;
|
| 713 |
+
}
|