gthinking 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +283 -0
- package/analysis.ts +986 -0
- package/creativity.ts +1002 -0
- package/dist/analysis.d.ts +52 -0
- package/dist/analysis.d.ts.map +1 -0
- package/dist/analysis.js +792 -0
- package/dist/analysis.js.map +1 -0
- package/dist/creativity.d.ts +80 -0
- package/dist/creativity.d.ts.map +1 -0
- package/dist/creativity.js +778 -0
- package/dist/creativity.js.map +1 -0
- package/dist/engine.d.ts +76 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +675 -0
- package/dist/engine.js.map +1 -0
- package/dist/examples.d.ts +7 -0
- package/dist/examples.d.ts.map +1 -0
- package/dist/examples.js +506 -0
- package/dist/examples.js.map +1 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +126 -0
- package/dist/index.js.map +1 -0
- package/dist/learning.d.ts +72 -0
- package/dist/learning.d.ts.map +1 -0
- package/dist/learning.js +615 -0
- package/dist/learning.js.map +1 -0
- package/dist/planning.d.ts +58 -0
- package/dist/planning.d.ts.map +1 -0
- package/dist/planning.js +824 -0
- package/dist/planning.js.map +1 -0
- package/dist/reasoning.d.ts +72 -0
- package/dist/reasoning.d.ts.map +1 -0
- package/dist/reasoning.js +792 -0
- package/dist/reasoning.js.map +1 -0
- package/dist/search-discovery.d.ts +73 -0
- package/dist/search-discovery.d.ts.map +1 -0
- package/dist/search-discovery.js +505 -0
- package/dist/search-discovery.js.map +1 -0
- package/dist/types.d.ts +535 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +77 -0
- package/dist/types.js.map +1 -0
- package/engine.ts +928 -0
- package/examples.ts +717 -0
- package/index.ts +106 -0
- package/learning.ts +779 -0
- package/package.json +51 -0
- package/planning.ts +1028 -0
- package/reasoning.ts +1019 -0
- package/search-discovery.ts +654 -0
- package/tsconfig.json +25 -0
- package/types.ts +674 -0
package/dist/analysis.js
ADDED
|
@@ -0,0 +1,792 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Analysis Module
|
|
4
|
+
* Deep content analysis with multi-dimensional insights extraction
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.analysisEngine = exports.AnalysisEngine = void 0;
|
|
8
|
+
const types_1 = require("./types");
|
|
9
|
+
const events_1 = require("events");
|
|
10
|
+
class SentimentAnalyzer {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.positiveWords = new Set([
|
|
13
|
+
'excellent', 'great', 'amazing', 'wonderful', 'fantastic', 'good', 'best',
|
|
14
|
+
'love', 'like', 'happy', 'success', 'benefit', 'advantage', 'improve',
|
|
15
|
+
'progress', 'achieve', 'win', 'positive', 'effective', 'efficient'
|
|
16
|
+
]);
|
|
17
|
+
this.negativeWords = new Set([
|
|
18
|
+
'bad', 'terrible', 'awful', 'worst', 'hate', 'dislike', 'sad', 'fail',
|
|
19
|
+
'problem', 'issue', 'disadvantage', 'worse', 'decline', 'lose', 'negative',
|
|
20
|
+
'ineffective', 'inefficient', 'difficult', 'challenging', 'concern'
|
|
21
|
+
]);
|
|
22
|
+
}
|
|
23
|
+
analyze(text) {
|
|
24
|
+
const words = text.toLowerCase().match(/\b\w+\b/g) || [];
|
|
25
|
+
let positive = 0;
|
|
26
|
+
let negative = 0;
|
|
27
|
+
let neutral = 0;
|
|
28
|
+
words.forEach(word => {
|
|
29
|
+
if (this.positiveWords.has(word))
|
|
30
|
+
positive++;
|
|
31
|
+
else if (this.negativeWords.has(word))
|
|
32
|
+
negative++;
|
|
33
|
+
else
|
|
34
|
+
neutral++;
|
|
35
|
+
});
|
|
36
|
+
const total = words.length || 1;
|
|
37
|
+
const compound = (positive - negative) / total;
|
|
38
|
+
return {
|
|
39
|
+
positive: positive / total,
|
|
40
|
+
negative: negative / total,
|
|
41
|
+
neutral: neutral / total,
|
|
42
|
+
compound
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
getSentimentLabel(score) {
|
|
46
|
+
if (score.compound > 0.5)
|
|
47
|
+
return 'very_positive';
|
|
48
|
+
if (score.compound > 0.1)
|
|
49
|
+
return 'positive';
|
|
50
|
+
if (score.compound < -0.5)
|
|
51
|
+
return 'very_negative';
|
|
52
|
+
if (score.compound < -0.1)
|
|
53
|
+
return 'negative';
|
|
54
|
+
return 'neutral';
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
class EntityExtractor {
|
|
58
|
+
constructor() {
|
|
59
|
+
this.entityPatterns = new Map([
|
|
60
|
+
['person', [/\b[A-Z][a-z]+ [A-Z][a-z]+\b/g, /\b(Mr|Mrs|Ms|Dr|Prof)\.? [A-Z][a-z]+\b/g]],
|
|
61
|
+
['organization', [/\b[A-Z][a-z]* (Inc|Corp|Ltd|LLC|Company|Organization)\b/g]],
|
|
62
|
+
['location', [/\b(in|at|from) ([A-Z][a-z]+( [A-Z][a-z]+)?)\b/g]],
|
|
63
|
+
['product', [/\b[A-Z][a-z]*[0-9]+\b/g, /\b(the|a|an) ([A-Z][a-z]+ (Pro|Max|Ultra|Plus))\b/gi]]
|
|
64
|
+
]);
|
|
65
|
+
}
|
|
66
|
+
extract(text) {
|
|
67
|
+
const entities = new Map();
|
|
68
|
+
const words = text.split(/\s+/);
|
|
69
|
+
// Simple entity extraction based on patterns and capitalization
|
|
70
|
+
words.forEach((word, index) => {
|
|
71
|
+
// Check for capitalized words (potential proper nouns)
|
|
72
|
+
if (/^[A-Z][a-z]+$/.test(word) && word.length > 2) {
|
|
73
|
+
const context = words.slice(Math.max(0, index - 3), index + 4).join(' ');
|
|
74
|
+
const type = this.classifyEntity(word, context);
|
|
75
|
+
if (entities.has(word)) {
|
|
76
|
+
const existing = entities.get(word);
|
|
77
|
+
existing.mentions++;
|
|
78
|
+
existing.confidence = Math.min(0.95, existing.confidence + 0.1);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
entities.set(word, {
|
|
82
|
+
name: word,
|
|
83
|
+
type,
|
|
84
|
+
confidence: 0.6,
|
|
85
|
+
mentions: 1
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
return Array.from(entities.values()).sort((a, b) => b.mentions - a.mentions);
|
|
91
|
+
}
|
|
92
|
+
classifyEntity(word, context) {
|
|
93
|
+
const contextLower = context.toLowerCase();
|
|
94
|
+
if (/\b(said|stated|announced|CEO|founder|president)\b/i.test(contextLower)) {
|
|
95
|
+
return 'person';
|
|
96
|
+
}
|
|
97
|
+
if (/\b(company|organization|firm|corporation)\b/i.test(contextLower)) {
|
|
98
|
+
return 'organization';
|
|
99
|
+
}
|
|
100
|
+
if (/\b(in|at|from|located|city|country|region)\b/i.test(contextLower)) {
|
|
101
|
+
return 'location';
|
|
102
|
+
}
|
|
103
|
+
if (/\b(product|launched|released|device|software)\b/i.test(contextLower)) {
|
|
104
|
+
return 'product';
|
|
105
|
+
}
|
|
106
|
+
if (/\b(event|conference|meeting|summit|festival)\b/i.test(contextLower)) {
|
|
107
|
+
return 'event';
|
|
108
|
+
}
|
|
109
|
+
return 'concept';
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
class TopicExtractor {
|
|
113
|
+
constructor() {
|
|
114
|
+
this.stopWords = new Set([
|
|
115
|
+
'the', 'a', 'an', 'is', 'are', 'was', 'were', 'be', 'been', 'being',
|
|
116
|
+
'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would', 'could',
|
|
117
|
+
'should', 'may', 'might', 'must', 'can', 'this', 'that', 'these', 'those'
|
|
118
|
+
]);
|
|
119
|
+
}
|
|
120
|
+
extract(text) {
|
|
121
|
+
const words = text.toLowerCase().match(/\b\w{4,}\b/g) || [];
|
|
122
|
+
const wordFreq = new Map();
|
|
123
|
+
// Calculate word frequencies
|
|
124
|
+
words.forEach(word => {
|
|
125
|
+
if (!this.stopWords.has(word)) {
|
|
126
|
+
wordFreq.set(word, (wordFreq.get(word) || 0) + 1);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
// Group related words into topics
|
|
130
|
+
const topics = [];
|
|
131
|
+
const sortedWords = Array.from(wordFreq.entries())
|
|
132
|
+
.sort((a, b) => b[1] - a[1])
|
|
133
|
+
.slice(0, 20);
|
|
134
|
+
// Simple topic clustering
|
|
135
|
+
const usedWords = new Set();
|
|
136
|
+
sortedWords.forEach(([word, freq]) => {
|
|
137
|
+
if (!usedWords.has(word)) {
|
|
138
|
+
const relatedWords = this.findRelatedWords(word, sortedWords, usedWords);
|
|
139
|
+
topics.push({
|
|
140
|
+
name: word,
|
|
141
|
+
relevance: freq / words.length,
|
|
142
|
+
keywords: [word, ...relatedWords],
|
|
143
|
+
subtopics: relatedWords.slice(0, 3)
|
|
144
|
+
});
|
|
145
|
+
usedWords.add(word);
|
|
146
|
+
relatedWords.forEach(w => usedWords.add(w));
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
return topics.slice(0, 5);
|
|
150
|
+
}
|
|
151
|
+
findRelatedWords(mainWord, allWords, usedWords) {
|
|
152
|
+
const related = [];
|
|
153
|
+
const mainPrefix = mainWord.substring(0, 3);
|
|
154
|
+
allWords.forEach(([word, _]) => {
|
|
155
|
+
if (word !== mainWord && !usedWords.has(word)) {
|
|
156
|
+
// Check for semantic similarity (simplified)
|
|
157
|
+
if (word.startsWith(mainPrefix) || mainWord.startsWith(word.substring(0, 3))) {
|
|
158
|
+
related.push(word);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
return related.slice(0, 5);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
class KeywordExtractor {
|
|
166
|
+
constructor() {
|
|
167
|
+
this.documentFrequency = new Map();
|
|
168
|
+
this.totalDocuments = 0;
|
|
169
|
+
}
|
|
170
|
+
extract(text, corpus) {
|
|
171
|
+
const words = text.toLowerCase().match(/\b\w{3,}\b/g) || [];
|
|
172
|
+
const wordFreq = new Map();
|
|
173
|
+
words.forEach(word => {
|
|
174
|
+
wordFreq.set(word, (wordFreq.get(word) || 0) + 1);
|
|
175
|
+
});
|
|
176
|
+
// Calculate TF-IDF if corpus is provided
|
|
177
|
+
const keywords = [];
|
|
178
|
+
wordFreq.forEach((freq, word) => {
|
|
179
|
+
const tf = freq / words.length;
|
|
180
|
+
const idf = corpus ? this.calculateIDF(word, corpus) : 1;
|
|
181
|
+
keywords.push({
|
|
182
|
+
term: word,
|
|
183
|
+
frequency: freq,
|
|
184
|
+
importance: tf * (1 + Math.log(1 + freq)),
|
|
185
|
+
tfidf: tf * idf
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
return keywords
|
|
189
|
+
.sort((a, b) => b.importance - a.importance)
|
|
190
|
+
.slice(0, 15);
|
|
191
|
+
}
|
|
192
|
+
calculateIDF(word, corpus) {
|
|
193
|
+
const docsWithWord = corpus.filter(doc => doc.toLowerCase().includes(word)).length;
|
|
194
|
+
return Math.log(corpus.length / (1 + docsWithWord));
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
// ============================================================================
|
|
198
|
+
// SUMMARIZER
|
|
199
|
+
// ============================================================================
|
|
200
|
+
class Summarizer {
|
|
201
|
+
summarize(text, maxLength = 200) {
|
|
202
|
+
const sentences = this.splitIntoSentences(text);
|
|
203
|
+
if (sentences.length <= 3) {
|
|
204
|
+
return text;
|
|
205
|
+
}
|
|
206
|
+
// Score sentences based on importance
|
|
207
|
+
const sentenceScores = sentences.map((sentence, index) => ({
|
|
208
|
+
sentence,
|
|
209
|
+
index,
|
|
210
|
+
score: this.scoreSentence(sentence, text, index, sentences.length)
|
|
211
|
+
}));
|
|
212
|
+
// Select top sentences
|
|
213
|
+
const topSentences = sentenceScores
|
|
214
|
+
.sort((a, b) => b.score - a.score)
|
|
215
|
+
.slice(0, Math.ceil(sentences.length * 0.3))
|
|
216
|
+
.sort((a, b) => a.index - b.index);
|
|
217
|
+
const summary = topSentences.map(s => s.sentence).join(' ');
|
|
218
|
+
return summary.length > maxLength
|
|
219
|
+
? summary.substring(0, maxLength - 3) + '...'
|
|
220
|
+
: summary;
|
|
221
|
+
}
|
|
222
|
+
splitIntoSentences(text) {
|
|
223
|
+
return text
|
|
224
|
+
.replace(/([.!?])\s+/g, "$1|")
|
|
225
|
+
.split("|")
|
|
226
|
+
.filter(s => s.trim().length > 10);
|
|
227
|
+
}
|
|
228
|
+
scoreSentence(sentence, fullText, index, total) {
|
|
229
|
+
let score = 0;
|
|
230
|
+
// Position score (first and last sentences are often important)
|
|
231
|
+
if (index === 0 || index === total - 1)
|
|
232
|
+
score += 2;
|
|
233
|
+
if (index === 1 || index === total - 2)
|
|
234
|
+
score += 1;
|
|
235
|
+
// Length score (avoid very short or very long sentences)
|
|
236
|
+
const wordCount = sentence.split(/\s+/).length;
|
|
237
|
+
if (wordCount >= 8 && wordCount <= 25)
|
|
238
|
+
score += 1;
|
|
239
|
+
// Keyword density score
|
|
240
|
+
const words = sentence.toLowerCase().match(/\b\w+\b/g) || [];
|
|
241
|
+
const importantWords = words.filter(w => w.length > 5);
|
|
242
|
+
score += importantWords.length / words.length;
|
|
243
|
+
// Presence of numerical data
|
|
244
|
+
if (/\d+/.test(sentence))
|
|
245
|
+
score += 0.5;
|
|
246
|
+
return score;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
// ============================================================================
|
|
250
|
+
// FACT CHECKER
|
|
251
|
+
// ============================================================================
|
|
252
|
+
class FactChecker {
|
|
253
|
+
constructor() {
|
|
254
|
+
this.knownFacts = new Map();
|
|
255
|
+
}
|
|
256
|
+
async checkClaim(claim, sources) {
|
|
257
|
+
// Normalize the claim
|
|
258
|
+
const normalizedClaim = claim.toLowerCase().trim();
|
|
259
|
+
// Check against known facts
|
|
260
|
+
if (this.knownFacts.has(normalizedClaim)) {
|
|
261
|
+
const fact = this.knownFacts.get(normalizedClaim);
|
|
262
|
+
return {
|
|
263
|
+
claim,
|
|
264
|
+
verdict: fact.value ? 'true' : 'false',
|
|
265
|
+
confidence: fact.confidence,
|
|
266
|
+
sources: [],
|
|
267
|
+
explanation: 'Based on verified knowledge base'
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
// Analyze sources for verification
|
|
271
|
+
const sourceAnalysis = this.analyzeSources(sources, claim);
|
|
272
|
+
// Determine verdict based on source analysis
|
|
273
|
+
let verdict;
|
|
274
|
+
let confidence = sourceAnalysis.agreement;
|
|
275
|
+
if (sourceAnalysis.supporting > sourceAnalysis.contradicting * 2) {
|
|
276
|
+
verdict = 'true';
|
|
277
|
+
}
|
|
278
|
+
else if (sourceAnalysis.contradicting > sourceAnalysis.supporting * 2) {
|
|
279
|
+
verdict = 'false';
|
|
280
|
+
}
|
|
281
|
+
else if (sourceAnalysis.supporting > 0 || sourceAnalysis.contradicting > 0) {
|
|
282
|
+
verdict = 'partially_true';
|
|
283
|
+
confidence *= 0.7;
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
verdict = 'unverifiable';
|
|
287
|
+
confidence = 0.3;
|
|
288
|
+
}
|
|
289
|
+
return {
|
|
290
|
+
claim,
|
|
291
|
+
verdict,
|
|
292
|
+
confidence,
|
|
293
|
+
sources: sourceAnalysis.relevantSources,
|
|
294
|
+
explanation: this.generateExplanation(verdict, sourceAnalysis),
|
|
295
|
+
corrections: sourceAnalysis.corrections
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
analyzeSources(sources, claim) {
|
|
299
|
+
const claimWords = claim.toLowerCase().split(/\s+/);
|
|
300
|
+
let supporting = 0;
|
|
301
|
+
let contradicting = 0;
|
|
302
|
+
let neutral = 0;
|
|
303
|
+
const relevantSources = [];
|
|
304
|
+
const corrections = [];
|
|
305
|
+
sources.forEach(source => {
|
|
306
|
+
const content = (source.title + ' ' + source.snippet).toLowerCase();
|
|
307
|
+
const relevance = claimWords.filter(w => content.includes(w)).length / claimWords.length;
|
|
308
|
+
if (relevance > 0.5) {
|
|
309
|
+
relevantSources.push(source);
|
|
310
|
+
// Check for supporting/contradicting indicators
|
|
311
|
+
if (this.isSupporting(content, claim)) {
|
|
312
|
+
supporting++;
|
|
313
|
+
}
|
|
314
|
+
else if (this.isContradicting(content, claim)) {
|
|
315
|
+
contradicting++;
|
|
316
|
+
const correction = this.extractCorrection(content, claim);
|
|
317
|
+
if (correction)
|
|
318
|
+
corrections.push(correction);
|
|
319
|
+
}
|
|
320
|
+
else {
|
|
321
|
+
neutral++;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
const total = supporting + contradicting + neutral || 1;
|
|
326
|
+
const agreement = Math.max(supporting, contradicting) / total;
|
|
327
|
+
return { supporting, contradicting, neutral, agreement, relevantSources, corrections };
|
|
328
|
+
}
|
|
329
|
+
isSupporting(content, _claim) {
|
|
330
|
+
const positiveIndicators = ['confirmed', 'true', 'correct', 'yes', 'indeed', 'verified'];
|
|
331
|
+
return positiveIndicators.some(ind => content.includes(ind));
|
|
332
|
+
}
|
|
333
|
+
isContradicting(content, _claim) {
|
|
334
|
+
const negativeIndicators = ['false', 'incorrect', 'not true', 'myth', 'misleading', 'wrong'];
|
|
335
|
+
return negativeIndicators.some(ind => content.includes(ind));
|
|
336
|
+
}
|
|
337
|
+
extractCorrection(content, _claim) {
|
|
338
|
+
// Extract potential correction from content
|
|
339
|
+
const correctionMatch = content.match(/(?:actually|in fact|correctly|the truth is)[^.]+/i);
|
|
340
|
+
return correctionMatch ? correctionMatch[0].trim() : undefined;
|
|
341
|
+
}
|
|
342
|
+
generateExplanation(verdict, analysis) {
|
|
343
|
+
switch (verdict) {
|
|
344
|
+
case 'true':
|
|
345
|
+
return `Supported by ${analysis.supporting} reliable sources with high agreement.`;
|
|
346
|
+
case 'false':
|
|
347
|
+
return `Contradicted by ${analysis.contradicting} sources. ${analysis.corrections.length > 0 ? 'Corrections found.' : ''}`;
|
|
348
|
+
case 'partially_true':
|
|
349
|
+
return `Mixed evidence: ${analysis.supporting} supporting, ${analysis.contradicting} contradicting sources.`;
|
|
350
|
+
case 'unverifiable':
|
|
351
|
+
return 'Insufficient reliable sources to verify this claim.';
|
|
352
|
+
default:
|
|
353
|
+
return 'Unable to determine veracity.';
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
addFact(claim, value, confidence) {
|
|
357
|
+
this.knownFacts.set(claim.toLowerCase().trim(), { value, confidence });
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
// ============================================================================
|
|
361
|
+
// COMPARISON ENGINE
|
|
362
|
+
// ============================================================================
|
|
363
|
+
class ComparisonEngine {
|
|
364
|
+
compare(subjects, contents) {
|
|
365
|
+
const similarities = [];
|
|
366
|
+
const differences = [];
|
|
367
|
+
// Extract features from each subject
|
|
368
|
+
const features = subjects.map((subject, index) => ({
|
|
369
|
+
subject,
|
|
370
|
+
content: contents[index],
|
|
371
|
+
entities: this.extractEntities(contents[index]),
|
|
372
|
+
topics: this.extractTopics(contents[index]),
|
|
373
|
+
keywords: this.extractKeywords(contents[index]),
|
|
374
|
+
sentiment: this.analyzeSentiment(contents[index])
|
|
375
|
+
}));
|
|
376
|
+
// Compare features
|
|
377
|
+
const aspects = ['entities', 'topics', 'keywords', 'sentiment'];
|
|
378
|
+
aspects.forEach(aspect => {
|
|
379
|
+
const values = {};
|
|
380
|
+
features.forEach(f => {
|
|
381
|
+
values[f.subject] = f[aspect];
|
|
382
|
+
});
|
|
383
|
+
const similarity = this.calculateSimilarity(values);
|
|
384
|
+
if (similarity > 0.6) {
|
|
385
|
+
similarities.push({
|
|
386
|
+
aspect,
|
|
387
|
+
values,
|
|
388
|
+
significance: similarity
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
else {
|
|
392
|
+
differences.push({
|
|
393
|
+
aspect,
|
|
394
|
+
values,
|
|
395
|
+
significance: 1 - similarity
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
// Generate conclusion
|
|
400
|
+
const conclusion = this.generateComparisonConclusion(subjects, similarities, differences);
|
|
401
|
+
const confidence = similarities.length / (similarities.length + differences.length);
|
|
402
|
+
return {
|
|
403
|
+
id: `comparison_${Date.now()}`,
|
|
404
|
+
subjects,
|
|
405
|
+
similarities,
|
|
406
|
+
differences,
|
|
407
|
+
conclusion,
|
|
408
|
+
confidence
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
extractEntities(text) {
|
|
412
|
+
const words = text.match(/\b[A-Z][a-z]+\b/g) || [];
|
|
413
|
+
return [...new Set(words)];
|
|
414
|
+
}
|
|
415
|
+
extractTopics(text) {
|
|
416
|
+
const words = text.toLowerCase().match(/\b\w{5,}\b/g) || [];
|
|
417
|
+
const freq = new Map();
|
|
418
|
+
words.forEach(w => freq.set(w, (freq.get(w) || 0) + 1));
|
|
419
|
+
return Array.from(freq.entries())
|
|
420
|
+
.sort((a, b) => b[1] - a[1])
|
|
421
|
+
.slice(0, 5)
|
|
422
|
+
.map(([w]) => w);
|
|
423
|
+
}
|
|
424
|
+
extractKeywords(text) {
|
|
425
|
+
return this.extractTopics(text).slice(0, 10);
|
|
426
|
+
}
|
|
427
|
+
analyzeSentiment(text) {
|
|
428
|
+
const positive = /\b(good|great|excellent|positive|benefit|advantage)\b/gi;
|
|
429
|
+
const negative = /\b(bad|poor|negative|problem|issue|disadvantage)\b/gi;
|
|
430
|
+
const posCount = (text.match(positive) || []).length;
|
|
431
|
+
const negCount = (text.match(negative) || []).length;
|
|
432
|
+
if (posCount > negCount)
|
|
433
|
+
return 'positive';
|
|
434
|
+
if (negCount > posCount)
|
|
435
|
+
return 'negative';
|
|
436
|
+
return 'neutral';
|
|
437
|
+
}
|
|
438
|
+
calculateSimilarity(values) {
|
|
439
|
+
const subjects = Object.keys(values);
|
|
440
|
+
if (subjects.length < 2)
|
|
441
|
+
return 1;
|
|
442
|
+
let totalSimilarity = 0;
|
|
443
|
+
let comparisons = 0;
|
|
444
|
+
for (let i = 0; i < subjects.length; i++) {
|
|
445
|
+
for (let j = i + 1; j < subjects.length; j++) {
|
|
446
|
+
const val1 = values[subjects[i]];
|
|
447
|
+
const val2 = values[subjects[j]];
|
|
448
|
+
if (Array.isArray(val1) && Array.isArray(val2)) {
|
|
449
|
+
const intersection = val1.filter(v => val2.includes(v));
|
|
450
|
+
const union = [...new Set([...val1, ...val2])];
|
|
451
|
+
totalSimilarity += intersection.length / union.length;
|
|
452
|
+
}
|
|
453
|
+
else if (typeof val1 === 'string' && typeof val2 === 'string') {
|
|
454
|
+
totalSimilarity += val1 === val2 ? 1 : 0;
|
|
455
|
+
}
|
|
456
|
+
comparisons++;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
return comparisons > 0 ? totalSimilarity / comparisons : 0;
|
|
460
|
+
}
|
|
461
|
+
generateComparisonConclusion(subjects, similarities, differences) {
|
|
462
|
+
const similarityRatio = similarities.length / (similarities.length + differences.length);
|
|
463
|
+
if (similarityRatio > 0.7) {
|
|
464
|
+
return `${subjects.join(' and ')} share significant similarities, particularly in ${similarities.map(s => s.aspect).join(', ')}.`;
|
|
465
|
+
}
|
|
466
|
+
else if (similarityRatio < 0.3) {
|
|
467
|
+
return `${subjects.join(' and ')} are notably different across ${differences.map(d => d.aspect).join(', ')}.`;
|
|
468
|
+
}
|
|
469
|
+
else {
|
|
470
|
+
return `${subjects.join(' and ')} show both similarities and differences, with overlap in ${similarities.map(s => s.aspect).join(', ')} but divergence in ${differences.map(d => d.aspect).join(', ')}.`;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
// ============================================================================
|
|
475
|
+
// MAIN ANALYSIS ENGINE
|
|
476
|
+
// ============================================================================
|
|
477
|
+
class AnalysisEngine extends events_1.EventEmitter {
|
|
478
|
+
constructor() {
|
|
479
|
+
super();
|
|
480
|
+
this.sentimentAnalyzer = new SentimentAnalyzer();
|
|
481
|
+
this.entityExtractor = new EntityExtractor();
|
|
482
|
+
this.topicExtractor = new TopicExtractor();
|
|
483
|
+
this.keywordExtractor = new KeywordExtractor();
|
|
484
|
+
this.summarizer = new Summarizer();
|
|
485
|
+
this.factChecker = new FactChecker();
|
|
486
|
+
this.comparisonEngine = new ComparisonEngine();
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Perform comprehensive analysis on content
|
|
490
|
+
*/
|
|
491
|
+
async analyze(content, options = {}) {
|
|
492
|
+
const { types = ['sentiment', 'entity', 'topic', 'keyword', 'summary'], depth = 'moderate', context } = options;
|
|
493
|
+
const requestId = this.generateId();
|
|
494
|
+
const startTime = Date.now();
|
|
495
|
+
this.emit('analysis_start', {
|
|
496
|
+
id: requestId,
|
|
497
|
+
stage: types_1.ThinkingStage.ANALYSIS,
|
|
498
|
+
timestamp: new Date(),
|
|
499
|
+
data: { content: content.substring(0, 100) + '...', types }
|
|
500
|
+
});
|
|
501
|
+
const results = [];
|
|
502
|
+
try {
|
|
503
|
+
for (const type of types) {
|
|
504
|
+
const result = await this.analyzeByType(type, content, context, depth);
|
|
505
|
+
results.push(result);
|
|
506
|
+
}
|
|
507
|
+
const processingTime = Date.now() - startTime;
|
|
508
|
+
this.emit('analysis_complete', {
|
|
509
|
+
id: requestId,
|
|
510
|
+
stage: types_1.ThinkingStage.ANALYSIS,
|
|
511
|
+
timestamp: new Date(),
|
|
512
|
+
data: { results, processingTime }
|
|
513
|
+
});
|
|
514
|
+
return results;
|
|
515
|
+
}
|
|
516
|
+
catch (error) {
|
|
517
|
+
this.emit('analysis_error', {
|
|
518
|
+
id: requestId,
|
|
519
|
+
stage: types_1.ThinkingStage.ANALYSIS,
|
|
520
|
+
timestamp: new Date(),
|
|
521
|
+
data: { error }
|
|
522
|
+
});
|
|
523
|
+
throw new types_1.ThinkingError(`Analysis failed: ${error instanceof Error ? error.message : 'Unknown error'}`, types_1.ThinkingStage.ANALYSIS, true, error instanceof Error ? error : undefined);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* Analyze by specific type
|
|
528
|
+
*/
|
|
529
|
+
async analyzeByType(type, content, context, depth = 'moderate') {
|
|
530
|
+
const startTime = Date.now();
|
|
531
|
+
let findings = [];
|
|
532
|
+
switch (type) {
|
|
533
|
+
case 'sentiment':
|
|
534
|
+
findings = this.analyzeSentiment(content);
|
|
535
|
+
break;
|
|
536
|
+
case 'entity':
|
|
537
|
+
findings = this.analyzeEntities(content);
|
|
538
|
+
break;
|
|
539
|
+
case 'topic':
|
|
540
|
+
findings = this.analyzeTopics(content);
|
|
541
|
+
break;
|
|
542
|
+
case 'keyword':
|
|
543
|
+
findings = this.analyzeKeywords(content);
|
|
544
|
+
break;
|
|
545
|
+
case 'summary':
|
|
546
|
+
findings = this.generateSummary(content, depth);
|
|
547
|
+
break;
|
|
548
|
+
case 'fact_check':
|
|
549
|
+
findings = await this.factCheck(content);
|
|
550
|
+
break;
|
|
551
|
+
case 'comparison':
|
|
552
|
+
findings = this.compareContent(content, context);
|
|
553
|
+
break;
|
|
554
|
+
case 'trend':
|
|
555
|
+
findings = this.analyzeTrends(content);
|
|
556
|
+
break;
|
|
557
|
+
}
|
|
558
|
+
return {
|
|
559
|
+
id: this.generateId(),
|
|
560
|
+
requestId: this.generateId(),
|
|
561
|
+
type,
|
|
562
|
+
findings,
|
|
563
|
+
confidence: this.calculateConfidence(findings),
|
|
564
|
+
processingTime: Date.now() - startTime,
|
|
565
|
+
timestamp: new Date()
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
analyzeSentiment(content) {
|
|
569
|
+
const score = this.sentimentAnalyzer.analyze(content);
|
|
570
|
+
const label = this.sentimentAnalyzer.getSentimentLabel(score);
|
|
571
|
+
return [{
|
|
572
|
+
id: this.generateId(),
|
|
573
|
+
type: 'sentiment_analysis',
|
|
574
|
+
value: { score, label },
|
|
575
|
+
confidence: 0.85,
|
|
576
|
+
evidence: [{
|
|
577
|
+
source: 'sentiment_analyzer',
|
|
578
|
+
excerpt: content.substring(0, 100),
|
|
579
|
+
location: 'full_text',
|
|
580
|
+
strength: 0.8
|
|
581
|
+
}],
|
|
582
|
+
relatedFindings: []
|
|
583
|
+
}];
|
|
584
|
+
}
|
|
585
|
+
analyzeEntities(content) {
|
|
586
|
+
const entities = this.entityExtractor.extract(content);
|
|
587
|
+
return entities.slice(0, 10).map(entity => ({
|
|
588
|
+
id: this.generateId(),
|
|
589
|
+
type: 'entity',
|
|
590
|
+
value: entity,
|
|
591
|
+
confidence: entity.confidence,
|
|
592
|
+
evidence: [{
|
|
593
|
+
source: 'entity_extractor',
|
|
594
|
+
excerpt: `Found ${entity.name} (${entity.type}) mentioned ${entity.mentions} times`,
|
|
595
|
+
location: 'content',
|
|
596
|
+
strength: entity.confidence
|
|
597
|
+
}],
|
|
598
|
+
relatedFindings: []
|
|
599
|
+
}));
|
|
600
|
+
}
|
|
601
|
+
analyzeTopics(content) {
|
|
602
|
+
const topics = this.topicExtractor.extract(content);
|
|
603
|
+
return topics.map(topic => ({
|
|
604
|
+
id: this.generateId(),
|
|
605
|
+
type: 'topic',
|
|
606
|
+
value: topic,
|
|
607
|
+
confidence: topic.relevance,
|
|
608
|
+
evidence: [{
|
|
609
|
+
source: 'topic_extractor',
|
|
610
|
+
excerpt: `Topic: ${topic.name} with keywords: ${topic.keywords.join(', ')}`,
|
|
611
|
+
location: 'content',
|
|
612
|
+
strength: topic.relevance
|
|
613
|
+
}],
|
|
614
|
+
relatedFindings: []
|
|
615
|
+
}));
|
|
616
|
+
}
|
|
617
|
+
analyzeKeywords(content) {
|
|
618
|
+
const keywords = this.keywordExtractor.extract(content);
|
|
619
|
+
return keywords.map(kw => ({
|
|
620
|
+
id: this.generateId(),
|
|
621
|
+
type: 'keyword',
|
|
622
|
+
value: kw,
|
|
623
|
+
confidence: kw.importance,
|
|
624
|
+
evidence: [{
|
|
625
|
+
source: 'keyword_extractor',
|
|
626
|
+
excerpt: `Keyword "${kw.term}" appears ${kw.frequency} times`,
|
|
627
|
+
location: 'content',
|
|
628
|
+
strength: kw.importance
|
|
629
|
+
}],
|
|
630
|
+
relatedFindings: []
|
|
631
|
+
}));
|
|
632
|
+
}
|
|
633
|
+
generateSummary(content, depth) {
|
|
634
|
+
const maxLength = depth === 'surface' ? 100 : depth === 'deep' ? 500 : 250;
|
|
635
|
+
const summary = this.summarizer.summarize(content, maxLength);
|
|
636
|
+
return [{
|
|
637
|
+
id: this.generateId(),
|
|
638
|
+
type: 'summary',
|
|
639
|
+
value: { summary, originalLength: content.length, compressionRatio: summary.length / content.length },
|
|
640
|
+
confidence: 0.8,
|
|
641
|
+
evidence: [{
|
|
642
|
+
source: 'summarizer',
|
|
643
|
+
excerpt: summary.substring(0, 100),
|
|
644
|
+
location: 'generated_summary',
|
|
645
|
+
strength: 0.75
|
|
646
|
+
}],
|
|
647
|
+
relatedFindings: []
|
|
648
|
+
}];
|
|
649
|
+
}
|
|
650
|
+
async factCheck(content) {
|
|
651
|
+
// Extract claims from content (simplified)
|
|
652
|
+
const sentences = content.match(/[^.!?]+[.!?]+/g) || [];
|
|
653
|
+
const claims = sentences.filter(s => s.length > 20 &&
|
|
654
|
+
!s.toLowerCase().includes('i think') &&
|
|
655
|
+
!s.toLowerCase().includes('maybe')).slice(0, 3);
|
|
656
|
+
const findings = [];
|
|
657
|
+
for (const claim of claims) {
|
|
658
|
+
const factCheck = await this.factChecker.checkClaim(claim, []);
|
|
659
|
+
findings.push({
|
|
660
|
+
id: this.generateId(),
|
|
661
|
+
type: 'fact_check',
|
|
662
|
+
value: factCheck,
|
|
663
|
+
confidence: factCheck.confidence,
|
|
664
|
+
evidence: factCheck.sources.map(s => ({
|
|
665
|
+
source: s.url,
|
|
666
|
+
excerpt: s.snippet,
|
|
667
|
+
location: s.url,
|
|
668
|
+
strength: s.credibility
|
|
669
|
+
})),
|
|
670
|
+
relatedFindings: []
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
return findings;
|
|
674
|
+
}
|
|
675
|
+
compareContent(content, context) {
|
|
676
|
+
if (!context) {
|
|
677
|
+
return [{
|
|
678
|
+
id: this.generateId(),
|
|
679
|
+
type: 'comparison',
|
|
680
|
+
value: { error: 'No comparison context provided' },
|
|
681
|
+
confidence: 0,
|
|
682
|
+
evidence: [],
|
|
683
|
+
relatedFindings: []
|
|
684
|
+
}];
|
|
685
|
+
}
|
|
686
|
+
const comparison = this.comparisonEngine.compare(['Current Content', 'Context'], [content, context]);
|
|
687
|
+
return [{
|
|
688
|
+
id: this.generateId(),
|
|
689
|
+
type: 'comparison',
|
|
690
|
+
value: comparison,
|
|
691
|
+
confidence: comparison.confidence,
|
|
692
|
+
evidence: [{
|
|
693
|
+
source: 'comparison_engine',
|
|
694
|
+
excerpt: comparison.conclusion,
|
|
695
|
+
location: 'comparison_result',
|
|
696
|
+
strength: comparison.confidence
|
|
697
|
+
}],
|
|
698
|
+
relatedFindings: []
|
|
699
|
+
}];
|
|
700
|
+
}
|
|
701
|
+
analyzeTrends(content) {
|
|
702
|
+
// Simple trend analysis based on temporal references
|
|
703
|
+
const temporalPatterns = [
|
|
704
|
+
{ pattern: /\b(increasing|growing|rising|upward)\b/gi, trend: 'upward' },
|
|
705
|
+
{ pattern: /\b(decreasing|declining|falling|downward)\b/gi, trend: 'downward' },
|
|
706
|
+
{ pattern: /\b(stable|constant|steady|unchanged)\b/gi, trend: 'stable' }
|
|
707
|
+
];
|
|
708
|
+
const trends = [];
|
|
709
|
+
temporalPatterns.forEach(({ pattern, trend }) => {
|
|
710
|
+
const matches = content.match(pattern) || [];
|
|
711
|
+
if (matches.length > 0) {
|
|
712
|
+
trends.push({ trend, count: matches.length });
|
|
713
|
+
}
|
|
714
|
+
});
|
|
715
|
+
return [{
|
|
716
|
+
id: this.generateId(),
|
|
717
|
+
type: 'trend',
|
|
718
|
+
value: trends,
|
|
719
|
+
confidence: trends.length > 0 ? 0.7 : 0.3,
|
|
720
|
+
evidence: [{
|
|
721
|
+
source: 'trend_analyzer',
|
|
722
|
+
excerpt: `Detected trends: ${trends.map(t => t.trend).join(', ')}`,
|
|
723
|
+
location: 'content',
|
|
724
|
+
strength: 0.65
|
|
725
|
+
}],
|
|
726
|
+
relatedFindings: []
|
|
727
|
+
}];
|
|
728
|
+
}
|
|
729
|
+
calculateConfidence(findings) {
|
|
730
|
+
if (findings.length === 0)
|
|
731
|
+
return 0;
|
|
732
|
+
const avgConfidence = findings.reduce((sum, f) => sum + f.confidence, 0) / findings.length;
|
|
733
|
+
return Math.min(0.95, avgConfidence);
|
|
734
|
+
}
|
|
735
|
+
/**
|
|
736
|
+
* Compare multiple contents
|
|
737
|
+
*/
|
|
738
|
+
compare(subjects, contents) {
|
|
739
|
+
return this.comparisonEngine.compare(subjects, contents);
|
|
740
|
+
}
|
|
741
|
+
/**
|
|
742
|
+
* Fact check a claim
|
|
743
|
+
*/
|
|
744
|
+
async factCheckClaim(claim, sources) {
|
|
745
|
+
return this.factChecker.checkClaim(claim, sources);
|
|
746
|
+
}
|
|
747
|
+
/**
|
|
748
|
+
* Add known fact for fact checking
|
|
749
|
+
*/
|
|
750
|
+
addKnownFact(claim, value, confidence) {
|
|
751
|
+
this.factChecker.addFact(claim, value, confidence);
|
|
752
|
+
}
|
|
753
|
+
generateId() {
|
|
754
|
+
return `analysis_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
exports.AnalysisEngine = AnalysisEngine;
|
|
758
|
+
// ============================================================================
|
|
759
|
+
// EXPORT SINGLETON INSTANCE
|
|
760
|
+
// ============================================================================
|
|
761
|
+
exports.analysisEngine = new AnalysisEngine();
|
|
762
|
+
// ============================================================================
|
|
763
|
+
// EXAMPLE USAGE
|
|
764
|
+
// ============================================================================
|
|
765
|
+
/*
|
|
766
|
+
// Comprehensive analysis
|
|
767
|
+
const results = await analysisEngine.analyze(
|
|
768
|
+
"Artificial Intelligence is revolutionizing healthcare. Machine learning algorithms can now detect diseases with 95% accuracy. " +
|
|
769
|
+
"However, there are concerns about privacy and data security. The future looks promising but challenges remain.",
|
|
770
|
+
{
|
|
771
|
+
types: ['sentiment', 'entity', 'topic', 'keyword', 'summary'],
|
|
772
|
+
depth: 'deep'
|
|
773
|
+
}
|
|
774
|
+
);
|
|
775
|
+
|
|
776
|
+
// Compare multiple texts
|
|
777
|
+
const comparison = analysisEngine.compare(
|
|
778
|
+
['Article A', 'Article B', 'Article C'],
|
|
779
|
+
[
|
|
780
|
+
"AI is transforming industries with automation and efficiency gains.",
|
|
781
|
+
"Machine learning brings both opportunities and challenges to various sectors.",
|
|
782
|
+
"Automation through AI technology is reshaping the workplace landscape."
|
|
783
|
+
]
|
|
784
|
+
);
|
|
785
|
+
|
|
786
|
+
// Fact check
|
|
787
|
+
const factCheck = await analysisEngine.factCheckClaim(
|
|
788
|
+
"AI can detect diseases with 95% accuracy",
|
|
789
|
+
searchResults
|
|
790
|
+
);
|
|
791
|
+
*/
|
|
792
|
+
//# sourceMappingURL=analysis.js.map
|