gthinking 1.3.0 → 2.1.1
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/.eslintrc.js +34 -0
- package/ANALYSIS_SUMMARY.md +363 -0
- package/README.md +230 -250
- package/dist/analysis/analysis-engine.d.ts +63 -0
- package/dist/analysis/analysis-engine.d.ts.map +1 -0
- package/dist/analysis/analysis-engine.js +322 -0
- package/dist/analysis/analysis-engine.js.map +1 -0
- package/dist/core/config.d.ts +1419 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +361 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/engine.d.ts +176 -0
- package/dist/core/engine.d.ts.map +1 -0
- package/dist/core/engine.js +604 -0
- package/dist/core/engine.js.map +1 -0
- package/dist/core/errors.d.ts +153 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +287 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/index.d.ts +7 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/{types.js → core/index.js} +8 -4
- package/dist/core/index.js.map +1 -0
- package/dist/core/pipeline.d.ts +121 -0
- package/dist/core/pipeline.d.ts.map +1 -0
- package/dist/core/pipeline.js +289 -0
- package/dist/core/pipeline.js.map +1 -0
- package/dist/core/rate-limiter.d.ts +58 -0
- package/dist/core/rate-limiter.d.ts.map +1 -0
- package/dist/core/rate-limiter.js +133 -0
- package/dist/core/rate-limiter.js.map +1 -0
- package/dist/core/session-manager.d.ts +96 -0
- package/dist/core/session-manager.d.ts.map +1 -0
- package/dist/core/session-manager.js +223 -0
- package/dist/core/session-manager.js.map +1 -0
- package/dist/creativity/creativity-engine.d.ts +6 -0
- package/dist/creativity/creativity-engine.d.ts.map +1 -0
- package/dist/creativity/creativity-engine.js +17 -0
- package/dist/creativity/creativity-engine.js.map +1 -0
- package/dist/index.d.ts +24 -32
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +130 -104
- package/dist/index.js.map +1 -1
- package/dist/learning/learning-engine.d.ts +6 -0
- package/dist/learning/learning-engine.d.ts.map +1 -0
- package/dist/learning/learning-engine.js +17 -0
- package/dist/learning/learning-engine.js.map +1 -0
- package/dist/llm/index.d.ts +10 -0
- package/dist/llm/index.d.ts.map +1 -0
- package/dist/llm/index.js +26 -0
- package/dist/llm/index.js.map +1 -0
- package/dist/llm/llm-service.d.ts +109 -0
- package/dist/llm/llm-service.d.ts.map +1 -0
- package/dist/llm/llm-service.js +224 -0
- package/dist/llm/llm-service.js.map +1 -0
- package/dist/llm/providers/base.d.ts +85 -0
- package/dist/llm/providers/base.d.ts.map +1 -0
- package/dist/llm/providers/base.js +57 -0
- package/dist/llm/providers/base.js.map +1 -0
- package/dist/llm/providers/cli.d.ts +23 -0
- package/dist/llm/providers/cli.d.ts.map +1 -0
- package/dist/llm/providers/cli.js +158 -0
- package/dist/llm/providers/cli.js.map +1 -0
- package/dist/llm/providers/gemini.d.ts +30 -0
- package/dist/llm/providers/gemini.d.ts.map +1 -0
- package/dist/llm/providers/gemini.js +168 -0
- package/dist/llm/providers/gemini.js.map +1 -0
- package/dist/llm/sanitization.d.ts +50 -0
- package/dist/llm/sanitization.d.ts.map +1 -0
- package/dist/llm/sanitization.js +149 -0
- package/dist/llm/sanitization.js.map +1 -0
- package/dist/{server.d.ts.map → mcp/server.d.ts.map} +1 -1
- package/dist/mcp/server.js +108 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/planning/planning-engine.d.ts +6 -0
- package/dist/planning/planning-engine.d.ts.map +1 -0
- package/dist/planning/planning-engine.js +17 -0
- package/dist/planning/planning-engine.js.map +1 -0
- package/dist/reasoning/reasoning-engine.d.ts +6 -0
- package/dist/reasoning/reasoning-engine.d.ts.map +1 -0
- package/dist/reasoning/reasoning-engine.js +17 -0
- package/dist/reasoning/reasoning-engine.js.map +1 -0
- package/dist/search/search-engine.d.ts +99 -0
- package/dist/search/search-engine.d.ts.map +1 -0
- package/dist/search/search-engine.js +271 -0
- package/dist/search/search-engine.js.map +1 -0
- package/dist/synthesis/synthesis-engine.d.ts +6 -0
- package/dist/synthesis/synthesis-engine.d.ts.map +1 -0
- package/dist/synthesis/synthesis-engine.js +17 -0
- package/dist/synthesis/synthesis-engine.js.map +1 -0
- package/dist/types/analysis.d.ts +1534 -49
- package/dist/types/analysis.d.ts.map +1 -1
- package/dist/types/analysis.js +250 -0
- package/dist/types/analysis.js.map +1 -1
- package/dist/types/core.d.ts +257 -30
- package/dist/types/core.d.ts.map +1 -1
- package/dist/types/core.js +148 -18
- package/dist/types/core.js.map +1 -1
- package/dist/types/creativity.d.ts +2871 -56
- package/dist/types/creativity.d.ts.map +1 -1
- package/dist/types/creativity.js +195 -0
- package/dist/types/creativity.js.map +1 -1
- package/dist/types/index.d.ts +6 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +17 -2
- package/dist/types/index.js.map +1 -1
- package/dist/types/learning.d.ts +851 -61
- package/dist/types/learning.d.ts.map +1 -1
- package/dist/types/learning.js +155 -0
- package/dist/types/learning.js.map +1 -1
- package/dist/types/planning.d.ts +2223 -71
- package/dist/types/planning.d.ts.map +1 -1
- package/dist/types/planning.js +190 -0
- package/dist/types/planning.js.map +1 -1
- package/dist/types/reasoning.d.ts +2209 -72
- package/dist/types/reasoning.d.ts.map +1 -1
- package/dist/types/reasoning.js +200 -1
- package/dist/types/reasoning.js.map +1 -1
- package/dist/types/search.d.ts +981 -53
- package/dist/types/search.d.ts.map +1 -1
- package/dist/types/search.js +137 -0
- package/dist/types/search.js.map +1 -1
- package/dist/types/synthesis.d.ts +583 -38
- package/dist/types/synthesis.d.ts.map +1 -1
- package/dist/types/synthesis.js +138 -0
- package/dist/types/synthesis.js.map +1 -1
- package/dist/utils/cache.d.ts +144 -0
- package/dist/utils/cache.d.ts.map +1 -0
- package/dist/utils/cache.js +288 -0
- package/dist/utils/cache.js.map +1 -0
- package/dist/utils/id-generator.d.ts +89 -0
- package/dist/utils/id-generator.d.ts.map +1 -0
- package/dist/utils/id-generator.js +132 -0
- package/dist/utils/id-generator.js.map +1 -0
- package/dist/utils/index.d.ts +11 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +33 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +142 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +248 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/metrics.d.ts +149 -0
- package/dist/utils/metrics.d.ts.map +1 -0
- package/dist/utils/metrics.js +296 -0
- package/dist/utils/metrics.js.map +1 -0
- package/dist/utils/timer.d.ts +7 -0
- package/dist/utils/timer.d.ts.map +1 -0
- package/dist/utils/timer.js +17 -0
- package/dist/utils/timer.js.map +1 -0
- package/dist/utils/validation.d.ts +147 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +275 -0
- package/dist/utils/validation.js.map +1 -0
- package/docs/API.md +411 -0
- package/docs/ARCHITECTURE.md +271 -0
- package/docs/CHANGELOG.md +283 -0
- package/jest.config.js +28 -0
- package/package.json +43 -30
- package/src/analysis/analysis-engine.ts +383 -0
- package/src/core/config.ts +406 -0
- package/src/core/engine.ts +785 -0
- package/src/core/errors.ts +349 -0
- package/src/core/index.ts +12 -0
- package/src/core/pipeline.ts +424 -0
- package/src/core/rate-limiter.ts +155 -0
- package/src/core/session-manager.ts +269 -0
- package/src/creativity/creativity-engine.ts +14 -0
- package/src/index.ts +178 -0
- package/src/learning/learning-engine.ts +14 -0
- package/src/llm/index.ts +10 -0
- package/src/llm/llm-service.ts +285 -0
- package/src/llm/providers/base.ts +146 -0
- package/src/llm/providers/cli.ts +186 -0
- package/src/llm/providers/gemini.ts +201 -0
- package/src/llm/sanitization.ts +178 -0
- package/src/mcp/server.ts +117 -0
- package/src/planning/planning-engine.ts +14 -0
- package/src/reasoning/reasoning-engine.ts +14 -0
- package/src/search/search-engine.ts +333 -0
- package/src/synthesis/synthesis-engine.ts +14 -0
- package/src/types/analysis.ts +337 -0
- package/src/types/core.ts +342 -0
- package/src/types/creativity.ts +268 -0
- package/src/types/index.ts +31 -0
- package/src/types/learning.ts +215 -0
- package/src/types/planning.ts +251 -0
- package/src/types/reasoning.ts +288 -0
- package/src/types/search.ts +192 -0
- package/src/types/synthesis.ts +187 -0
- package/src/utils/cache.ts +363 -0
- package/src/utils/id-generator.ts +135 -0
- package/src/utils/index.ts +22 -0
- package/src/utils/logger.ts +290 -0
- package/src/utils/metrics.ts +380 -0
- package/src/utils/timer.ts +15 -0
- package/src/utils/validation.ts +297 -0
- package/tests/setup.ts +22 -0
- package/tests/unit/cache.test.ts +189 -0
- package/tests/unit/engine.test.ts +179 -0
- package/tests/unit/validation.test.ts +218 -0
- package/tsconfig.json +17 -12
- package/GEMINI.md +0 -68
- package/analysis.ts +0 -1063
- package/creativity.ts +0 -1055
- package/dist/analysis.d.ts +0 -54
- package/dist/analysis.d.ts.map +0 -1
- package/dist/analysis.js +0 -866
- package/dist/analysis.js.map +0 -1
- package/dist/creativity.d.ts +0 -81
- package/dist/creativity.d.ts.map +0 -1
- package/dist/creativity.js +0 -828
- package/dist/creativity.js.map +0 -1
- package/dist/engine.d.ts +0 -90
- package/dist/engine.d.ts.map +0 -1
- package/dist/engine.js +0 -720
- package/dist/engine.js.map +0 -1
- package/dist/examples.d.ts +0 -7
- package/dist/examples.d.ts.map +0 -1
- package/dist/examples.js +0 -506
- package/dist/examples.js.map +0 -1
- package/dist/learning.d.ts +0 -72
- package/dist/learning.d.ts.map +0 -1
- package/dist/learning.js +0 -615
- package/dist/learning.js.map +0 -1
- package/dist/llm-service.d.ts +0 -21
- package/dist/llm-service.d.ts.map +0 -1
- package/dist/llm-service.js +0 -100
- package/dist/llm-service.js.map +0 -1
- package/dist/planning.d.ts +0 -62
- package/dist/planning.d.ts.map +0 -1
- package/dist/planning.js +0 -886
- package/dist/planning.js.map +0 -1
- package/dist/reasoning.d.ts +0 -73
- package/dist/reasoning.d.ts.map +0 -1
- package/dist/reasoning.js +0 -845
- package/dist/reasoning.js.map +0 -1
- package/dist/search-discovery.d.ts +0 -73
- package/dist/search-discovery.d.ts.map +0 -1
- package/dist/search-discovery.js +0 -548
- package/dist/search-discovery.js.map +0 -1
- package/dist/server.js +0 -113
- package/dist/server.js.map +0 -1
- package/dist/types/engine.d.ts +0 -55
- package/dist/types/engine.d.ts.map +0 -1
- package/dist/types/engine.js +0 -3
- package/dist/types/engine.js.map +0 -1
- package/dist/types.d.ts +0 -6
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js.map +0 -1
- package/engine.ts +0 -1009
- package/examples.ts +0 -717
- package/index.ts +0 -106
- package/learning.ts +0 -779
- package/llm-service.ts +0 -120
- package/planning.ts +0 -1101
- package/reasoning.ts +0 -1079
- package/search-discovery.ts +0 -700
- package/server.ts +0 -115
- package/types/analysis.ts +0 -69
- package/types/core.ts +0 -90
- package/types/creativity.ts +0 -72
- package/types/engine.ts +0 -60
- package/types/index.ts +0 -9
- package/types/learning.ts +0 -69
- package/types/planning.ts +0 -85
- package/types/reasoning.ts +0 -92
- package/types/search.ts +0 -58
- package/types/synthesis.ts +0 -43
- package/types.ts +0 -6
- /package/dist/{server.d.ts → mcp/server.d.ts} +0 -0
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analysis Engine for gthinking v2.0.0
|
|
3
|
+
* AI-powered content analysis including sentiment, entities, topics, and more.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { EventEmitter } from 'events';
|
|
7
|
+
import { Logger } from '../utils/logger';
|
|
8
|
+
import { LLMService } from '../llm/llm-service';
|
|
9
|
+
import {
|
|
10
|
+
AnalysisRequest,
|
|
11
|
+
AnalysisRequestSchema,
|
|
12
|
+
AnalysisType,
|
|
13
|
+
CompleteAnalysisResult,
|
|
14
|
+
SentimentResult,
|
|
15
|
+
EntityExtractionResult,
|
|
16
|
+
TopicExtractionResult,
|
|
17
|
+
KeywordExtractionResult,
|
|
18
|
+
SummaryResult,
|
|
19
|
+
ReadabilityResult,
|
|
20
|
+
ThinkingStage,
|
|
21
|
+
ValidationError,
|
|
22
|
+
} from '../types';
|
|
23
|
+
import { validateSchema, safeJsonParse } from '../utils/validation';
|
|
24
|
+
import { withRetry, StageError } from '../core/errors';
|
|
25
|
+
|
|
26
|
+
const logger = new Logger('AnalysisEngine');
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Analysis Engine
|
|
30
|
+
*/
|
|
31
|
+
export class AnalysisEngine extends EventEmitter {
|
|
32
|
+
private llmService: LLMService | null = null;
|
|
33
|
+
|
|
34
|
+
constructor(llmService?: LLMService) {
|
|
35
|
+
super();
|
|
36
|
+
this.llmService = llmService || null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Set the LLM service
|
|
41
|
+
* @param llmService - The LLM service instance
|
|
42
|
+
*/
|
|
43
|
+
public setLLMService(llmService: LLMService): void {
|
|
44
|
+
this.llmService = llmService;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Analyze content based on request
|
|
49
|
+
* @param request - The analysis request
|
|
50
|
+
* @returns Complete analysis result
|
|
51
|
+
*/
|
|
52
|
+
public async analyze(request: unknown): Promise<CompleteAnalysisResult> {
|
|
53
|
+
const startTime = Date.now();
|
|
54
|
+
|
|
55
|
+
// Validate request
|
|
56
|
+
const validatedRequest = validateSchema(AnalysisRequestSchema, request);
|
|
57
|
+
|
|
58
|
+
logger.info('Starting analysis', {
|
|
59
|
+
types: validatedRequest.types,
|
|
60
|
+
contentLength: validatedRequest.content.length
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
this.emit('analysis:start', { request: validatedRequest });
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
// Execute requested analysis types in parallel
|
|
67
|
+
const tasks: Promise<void>[] = [];
|
|
68
|
+
const result: Partial<CompleteAnalysisResult> = {
|
|
69
|
+
success: true,
|
|
70
|
+
timestamp: new Date(),
|
|
71
|
+
request: validatedRequest,
|
|
72
|
+
rawContent: validatedRequest.options.includeRaw ? validatedRequest.content : undefined,
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
if (validatedRequest.types.includes(AnalysisType.SENTIMENT)) {
|
|
76
|
+
tasks.push(this.analyzeSentiment(validatedRequest).then(res => { result.sentiment = res; }));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (validatedRequest.types.includes(AnalysisType.ENTITY)) {
|
|
80
|
+
tasks.push(this.extractEntities(validatedRequest).then(res => { result.entities = res; }));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (validatedRequest.types.includes(AnalysisType.TOPIC)) {
|
|
84
|
+
tasks.push(this.extractTopics(validatedRequest).then(res => { result.topics = res; }));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (validatedRequest.types.includes(AnalysisType.KEYWORD)) {
|
|
88
|
+
tasks.push(this.extractKeywords(validatedRequest).then(res => { result.keywords = res; }));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (validatedRequest.types.includes(AnalysisType.SUMMARY)) {
|
|
92
|
+
tasks.push(this.generateSummary(validatedRequest).then(res => { result.summary = res; }));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (validatedRequest.types.includes(AnalysisType.READABILITY)) {
|
|
96
|
+
// Readability is calculated locally, no LLM needed
|
|
97
|
+
tasks.push(Promise.resolve(this.analyzeReadability(validatedRequest.content)).then(res => { result.readability = res; }));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Wait for all tasks to complete
|
|
101
|
+
await Promise.all(tasks);
|
|
102
|
+
|
|
103
|
+
const duration = Date.now() - startTime;
|
|
104
|
+
const finalResult = {
|
|
105
|
+
...result,
|
|
106
|
+
duration,
|
|
107
|
+
confidence: this.calculateOverallConfidence(result),
|
|
108
|
+
errors: [],
|
|
109
|
+
} as CompleteAnalysisResult;
|
|
110
|
+
|
|
111
|
+
logger.info('Analysis completed', { duration });
|
|
112
|
+
this.emit('analysis:complete', { result: finalResult });
|
|
113
|
+
|
|
114
|
+
return finalResult;
|
|
115
|
+
} catch (error) {
|
|
116
|
+
logger.error('Analysis failed', { error });
|
|
117
|
+
this.emit('analysis:error', { error });
|
|
118
|
+
|
|
119
|
+
throw new StageError(
|
|
120
|
+
`Analysis failed: ${(error as Error).message}`,
|
|
121
|
+
ThinkingStage.ANALYSIS,
|
|
122
|
+
false,
|
|
123
|
+
{ originalError: error }
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Analyze sentiment
|
|
130
|
+
*/
|
|
131
|
+
private async analyzeSentiment(request: AnalysisRequest): Promise<SentimentResult> {
|
|
132
|
+
this.ensureLLM();
|
|
133
|
+
|
|
134
|
+
const prompt = `
|
|
135
|
+
Analyze the sentiment of the following text.
|
|
136
|
+
Return a JSON object with:
|
|
137
|
+
- overall: "positive", "negative", "neutral", or "mixed"
|
|
138
|
+
- score: number between -1 (negative) and 1 (positive)
|
|
139
|
+
- confidence: number between 0 and 1
|
|
140
|
+
- emotions: object with scores (0-1) for joy, sadness, anger, fear, surprise, disgust
|
|
141
|
+
|
|
142
|
+
Text: "${request.content.slice(0, 5000)}"
|
|
143
|
+
`;
|
|
144
|
+
|
|
145
|
+
return this.executeLLMAnalysis<SentimentResult>(prompt);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Extract entities
|
|
150
|
+
*/
|
|
151
|
+
private async extractEntities(request: AnalysisRequest): Promise<EntityExtractionResult> {
|
|
152
|
+
this.ensureLLM();
|
|
153
|
+
|
|
154
|
+
const prompt = `
|
|
155
|
+
Extract entities from the following text.
|
|
156
|
+
Return a JSON object with:
|
|
157
|
+
- entities: array of objects with { text, type, confidence }
|
|
158
|
+
- totalCount: total number of entities
|
|
159
|
+
|
|
160
|
+
Entity types: person, organization, location, product, event, concept, date, money, percent
|
|
161
|
+
Max entities: ${request.options.maxEntities}
|
|
162
|
+
|
|
163
|
+
Text: "${request.content.slice(0, 5000)}"
|
|
164
|
+
`;
|
|
165
|
+
|
|
166
|
+
const result = await this.executeLLMAnalysis<any>(prompt);
|
|
167
|
+
|
|
168
|
+
// Post-process to ensure correct structure
|
|
169
|
+
const entities = (result.entities || []).map((e: any) => ({
|
|
170
|
+
id: crypto.randomUUID(),
|
|
171
|
+
text: e.text,
|
|
172
|
+
type: e.type,
|
|
173
|
+
startIndex: 0, // Placeholder
|
|
174
|
+
endIndex: 0, // Placeholder
|
|
175
|
+
confidence: e.confidence || 0.8,
|
|
176
|
+
metadata: {}
|
|
177
|
+
}));
|
|
178
|
+
|
|
179
|
+
return {
|
|
180
|
+
entities,
|
|
181
|
+
totalCount: entities.length,
|
|
182
|
+
byType: {} // Needs aggregation logic if needed
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Extract topics
|
|
188
|
+
*/
|
|
189
|
+
private async extractTopics(request: AnalysisRequest): Promise<TopicExtractionResult> {
|
|
190
|
+
this.ensureLLM();
|
|
191
|
+
|
|
192
|
+
const prompt = `
|
|
193
|
+
Extract main topics from the following text.
|
|
194
|
+
Return a JSON object with:
|
|
195
|
+
- topics: array of objects with { name, confidence, relevance, keywords (array of strings) }
|
|
196
|
+
- mainTopic: string
|
|
197
|
+
|
|
198
|
+
Max topics: ${request.options.maxTopics}
|
|
199
|
+
|
|
200
|
+
Text: "${request.content.slice(0, 5000)}"
|
|
201
|
+
`;
|
|
202
|
+
|
|
203
|
+
const result = await this.executeLLMAnalysis<any>(prompt);
|
|
204
|
+
|
|
205
|
+
const topics = (result.topics || []).map((t: any) => ({
|
|
206
|
+
id: crypto.randomUUID(),
|
|
207
|
+
name: t.name,
|
|
208
|
+
confidence: t.confidence || 0.8,
|
|
209
|
+
relevance: t.relevance || 0.5,
|
|
210
|
+
keywords: t.keywords || []
|
|
211
|
+
}));
|
|
212
|
+
|
|
213
|
+
return {
|
|
214
|
+
topics,
|
|
215
|
+
mainTopic: result.mainTopic,
|
|
216
|
+
topicHierarchy: []
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Extract keywords
|
|
222
|
+
*/
|
|
223
|
+
private async extractKeywords(request: AnalysisRequest): Promise<KeywordExtractionResult> {
|
|
224
|
+
this.ensureLLM();
|
|
225
|
+
|
|
226
|
+
const prompt = `
|
|
227
|
+
Extract keywords and key phrases from the following text.
|
|
228
|
+
Return a JSON object with:
|
|
229
|
+
- keywords: array of objects with { text, score, frequency }
|
|
230
|
+
- keyPhrases: array of strings
|
|
231
|
+
|
|
232
|
+
Max keywords: ${request.options.maxKeywords}
|
|
233
|
+
|
|
234
|
+
Text: "${request.content.slice(0, 5000)}"
|
|
235
|
+
`;
|
|
236
|
+
|
|
237
|
+
const result = await this.executeLLMAnalysis<any>(prompt);
|
|
238
|
+
|
|
239
|
+
const keywords = (result.keywords || []).map((k: any) => ({
|
|
240
|
+
text: k.text,
|
|
241
|
+
score: k.score || 0.5,
|
|
242
|
+
frequency: k.frequency || 1,
|
|
243
|
+
tfidf: 0,
|
|
244
|
+
isKeyPhrase: false
|
|
245
|
+
}));
|
|
246
|
+
|
|
247
|
+
return {
|
|
248
|
+
keywords,
|
|
249
|
+
keyPhrases: result.keyPhrases || [],
|
|
250
|
+
totalWords: request.content.split(/\s+/).length,
|
|
251
|
+
uniqueWords: 0 // Placeholder
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Generate summary
|
|
257
|
+
*/
|
|
258
|
+
private async generateSummary(request: AnalysisRequest): Promise<SummaryResult> {
|
|
259
|
+
this.ensureLLM();
|
|
260
|
+
|
|
261
|
+
const prompt = `
|
|
262
|
+
Summarize the following text.
|
|
263
|
+
Return a JSON object with:
|
|
264
|
+
- summary: string
|
|
265
|
+
- keyPoints: array of strings
|
|
266
|
+
|
|
267
|
+
Length: ${request.options.summaryLength}
|
|
268
|
+
|
|
269
|
+
Text: "${request.content.slice(0, 10000)}"
|
|
270
|
+
`;
|
|
271
|
+
|
|
272
|
+
const result = await this.executeLLMAnalysis<any>(prompt);
|
|
273
|
+
|
|
274
|
+
return {
|
|
275
|
+
summary: result.summary,
|
|
276
|
+
keyPoints: result.keyPoints || [],
|
|
277
|
+
originalLength: request.content.length,
|
|
278
|
+
summaryLength: result.summary?.length || 0,
|
|
279
|
+
compressionRatio: result.summary ? result.summary.length / request.content.length : 0,
|
|
280
|
+
method: 'abstractive'
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Calculate readability metrics (Locally)
|
|
286
|
+
*/
|
|
287
|
+
private analyzeReadability(text: string): ReadabilityResult {
|
|
288
|
+
const words = text.trim().split(/\s+/).length;
|
|
289
|
+
const sentences = text.split(/[.!?]+/).length - 1 || 1;
|
|
290
|
+
const syllables = this.countSyllables(text);
|
|
291
|
+
const complexWords = this.countComplexWords(text);
|
|
292
|
+
|
|
293
|
+
// Flesch-Kincaid Grade Level
|
|
294
|
+
const fkGrade = 0.39 * (words / sentences) + 11.8 * (syllables / words) - 15.59;
|
|
295
|
+
|
|
296
|
+
// Flesch Reading Ease
|
|
297
|
+
const fReadingEase = 206.835 - 1.015 * (words / sentences) - 84.6 * (syllables / words);
|
|
298
|
+
|
|
299
|
+
return {
|
|
300
|
+
score: Math.max(0, Math.min(100, fReadingEase)),
|
|
301
|
+
grade: this.getGradeLevel(fkGrade),
|
|
302
|
+
metrics: {
|
|
303
|
+
fleschKincaid: fkGrade,
|
|
304
|
+
fleschReadingEase: fReadingEase,
|
|
305
|
+
gunningFog: 0, // Placeholder
|
|
306
|
+
smogIndex: 0, // Placeholder
|
|
307
|
+
colemanLiau: 0, // Placeholder
|
|
308
|
+
automatedReadability: 0 // Placeholder
|
|
309
|
+
},
|
|
310
|
+
statistics: {
|
|
311
|
+
wordCount: words,
|
|
312
|
+
sentenceCount: sentences,
|
|
313
|
+
syllableCount: syllables,
|
|
314
|
+
avgWordsPerSentence: words / sentences,
|
|
315
|
+
avgSyllablesPerWord: syllables / words,
|
|
316
|
+
complexWordCount: complexWords,
|
|
317
|
+
complexWordPercentage: (complexWords / words) * 100
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
private countSyllables(text: string): number {
|
|
323
|
+
// Very basic syllable counter
|
|
324
|
+
return text.length / 3;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
private countComplexWords(text: string): number {
|
|
328
|
+
// Placeholder
|
|
329
|
+
return text.split(/\s+/).filter(w => w.length > 6).length;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
private getGradeLevel(score: number): any {
|
|
333
|
+
if (score < 5) return 'elementary';
|
|
334
|
+
if (score < 8) return 'middle_school';
|
|
335
|
+
if (score < 12) return 'high_school';
|
|
336
|
+
if (score < 16) return 'college';
|
|
337
|
+
return 'graduate';
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Execute LLM analysis with retries and parsing
|
|
342
|
+
*/
|
|
343
|
+
private async executeLLMAnalysis<T>(prompt: string): Promise<T> {
|
|
344
|
+
if (!this.llmService) throw new Error('LLM Service not initialized');
|
|
345
|
+
|
|
346
|
+
const response = await withRetry(async () => {
|
|
347
|
+
return this.llmService!.complete(prompt, 'You are a precise text analysis engine. Output valid JSON only.');
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
// Clean up potential markdown code blocks
|
|
351
|
+
const cleanResponse = response.replace(/```json/g, '').replace(/```/g, '').trim();
|
|
352
|
+
|
|
353
|
+
const parsed = safeJsonParse<T>(cleanResponse);
|
|
354
|
+
if (!parsed) {
|
|
355
|
+
throw new Error('Failed to parse LLM response as JSON');
|
|
356
|
+
}
|
|
357
|
+
return parsed;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
private ensureLLM(): void {
|
|
361
|
+
if (!this.llmService) {
|
|
362
|
+
throw new Error('LLM Service is required for this analysis type');
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
private calculateOverallConfidence(result: Partial<CompleteAnalysisResult>): number {
|
|
367
|
+
// Simple average of available confidences
|
|
368
|
+
const confidences: number[] = [];
|
|
369
|
+
if (result.sentiment) confidences.push(result.sentiment.confidence);
|
|
370
|
+
if (result.entities) confidences.push(0.8); // Entities usually high
|
|
371
|
+
if (result.topics) confidences.push(0.8);
|
|
372
|
+
|
|
373
|
+
if (confidences.length === 0) return 0.8;
|
|
374
|
+
return confidences.reduce((a, b) => a + b, 0) / confidences.length;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Factory function
|
|
380
|
+
*/
|
|
381
|
+
export function createAnalysisEngine(llmService?: LLMService): AnalysisEngine {
|
|
382
|
+
return new AnalysisEngine(llmService);
|
|
383
|
+
}
|