@amirdaraee/namewise 0.5.3 → 0.5.4
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/CHANGELOG.md +9 -0
- package/dist/index.js +0 -0
- package/package.json +2 -2
- package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -82
- package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -61
- package/.github/workflows/auto-release.yml +0 -81
- package/.github/workflows/build.yml +0 -55
- package/.github/workflows/publish.yml +0 -134
- package/.github/workflows/test.yml +0 -45
- package/eng.traineddata +0 -0
- package/src/cli/commands.ts +0 -64
- package/src/cli/rename.ts +0 -171
- package/src/index.ts +0 -54
- package/src/parsers/excel-parser.ts +0 -66
- package/src/parsers/factory.ts +0 -38
- package/src/parsers/pdf-parser.ts +0 -99
- package/src/parsers/text-parser.ts +0 -43
- package/src/parsers/word-parser.ts +0 -50
- package/src/services/ai-factory.ts +0 -39
- package/src/services/claude-service.ts +0 -119
- package/src/services/file-renamer.ts +0 -141
- package/src/services/lmstudio-service.ts +0 -161
- package/src/services/ollama-service.ts +0 -191
- package/src/services/openai-service.ts +0 -117
- package/src/types/index.ts +0 -76
- package/src/types/pdf-extraction.d.ts +0 -7
- package/src/utils/ai-prompts.ts +0 -76
- package/src/utils/file-templates.ts +0 -275
- package/src/utils/naming-conventions.ts +0 -67
- package/src/utils/pdf-to-image.ts +0 -137
- package/tests/data/console-test-1.txt +0 -1
- package/tests/data/console-test-2.txt +0 -1
- package/tests/data/console-test-long-filename-for-display-testing.txt +0 -1
- package/tests/data/empty-file.txt +0 -0
- package/tests/data/failure.txt +0 -1
- package/tests/data/file1.txt +0 -1
- package/tests/data/file2.txt +0 -1
- package/tests/data/much-longer-filename-to-test-clearing.txt +0 -1
- package/tests/data/sample-markdown.md +0 -9
- package/tests/data/sample-pdf.pdf +0 -0
- package/tests/data/sample-text.txt +0 -25
- package/tests/data/short.txt +0 -1
- package/tests/data/single-file.txt +0 -1
- package/tests/data/success.txt +0 -1
- package/tests/data/this-is-a-very-long-filename-that-should-be-truncated-for-better-display-purposes.txt +0 -1
- package/tests/data/very-long-filename-that-should-be-cleared-properly.txt +0 -1
- package/tests/data/x.txt +0 -1
- package/tests/integration/ai-prompting.test.ts +0 -386
- package/tests/integration/end-to-end.test.ts +0 -209
- package/tests/integration/person-name-extraction.test.ts +0 -440
- package/tests/integration/workflow.test.ts +0 -336
- package/tests/mocks/mock-ai-service.ts +0 -58
- package/tests/unit/cli/commands.test.ts +0 -169
- package/tests/unit/parsers/factory.test.ts +0 -100
- package/tests/unit/parsers/pdf-parser.test.ts +0 -63
- package/tests/unit/parsers/text-parser.test.ts +0 -85
- package/tests/unit/services/ai-factory.test.ts +0 -85
- package/tests/unit/services/claude-service.test.ts +0 -188
- package/tests/unit/services/file-renamer.test.ts +0 -514
- package/tests/unit/services/lmstudio-service.test.ts +0 -326
- package/tests/unit/services/ollama-service.test.ts +0 -264
- package/tests/unit/services/openai-service.test.ts +0 -196
- package/tests/unit/utils/ai-prompts.test.ts +0 -213
- package/tests/unit/utils/file-templates.test.ts +0 -199
- package/tests/unit/utils/naming-conventions.test.ts +0 -88
- package/tests/unit/utils/pdf-to-image.test.ts +0 -127
- package/tsconfig.json +0 -20
- package/vitest.config.ts +0 -30
|
@@ -1,326 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
2
|
-
import { LMStudioService } from '../../../src/services/lmstudio-service.js';
|
|
3
|
-
import { FileInfo } from '../../../src/types/index.js';
|
|
4
|
-
|
|
5
|
-
// Mock fetch globally
|
|
6
|
-
const mockFetch = vi.fn();
|
|
7
|
-
global.fetch = mockFetch;
|
|
8
|
-
|
|
9
|
-
describe('LMStudioService', () => {
|
|
10
|
-
let lmstudioService: LMStudioService;
|
|
11
|
-
|
|
12
|
-
beforeEach(() => {
|
|
13
|
-
lmstudioService = new LMStudioService();
|
|
14
|
-
vi.clearAllMocks();
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
describe('generateFileName()', () => {
|
|
18
|
-
it('should generate filename using OpenAI-compatible API', async () => {
|
|
19
|
-
const mockResponse = {
|
|
20
|
-
choices: [{
|
|
21
|
-
message: {
|
|
22
|
-
content: 'project-requirements-document',
|
|
23
|
-
role: 'assistant'
|
|
24
|
-
},
|
|
25
|
-
finish_reason: 'stop'
|
|
26
|
-
}],
|
|
27
|
-
usage: {
|
|
28
|
-
prompt_tokens: 50,
|
|
29
|
-
completion_tokens: 10,
|
|
30
|
-
total_tokens: 60
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
mockFetch.mockResolvedValueOnce({
|
|
35
|
-
ok: true,
|
|
36
|
-
json: async () => mockResponse
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
const result = await lmstudioService.generateFileName(
|
|
40
|
-
'This document contains project requirements and specifications.',
|
|
41
|
-
'document.txt',
|
|
42
|
-
'kebab-case',
|
|
43
|
-
'document'
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
expect(result).toBe('project-requirements-document');
|
|
47
|
-
expect(mockFetch).toHaveBeenCalledWith(
|
|
48
|
-
'http://localhost:1234/v1/chat/completions',
|
|
49
|
-
expect.objectContaining({
|
|
50
|
-
method: 'POST',
|
|
51
|
-
headers: { 'Content-Type': 'application/json' },
|
|
52
|
-
body: expect.stringContaining('"model":"local-model"')
|
|
53
|
-
})
|
|
54
|
-
);
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it('should include file metadata in the prompt', async () => {
|
|
58
|
-
const mockFileInfo: FileInfo = {
|
|
59
|
-
path: '/test/document.pdf',
|
|
60
|
-
name: 'document.pdf',
|
|
61
|
-
extension: '.pdf',
|
|
62
|
-
size: 1024,
|
|
63
|
-
createdAt: new Date(),
|
|
64
|
-
modifiedAt: new Date(),
|
|
65
|
-
accessedAt: new Date(),
|
|
66
|
-
parentFolder: 'contracts',
|
|
67
|
-
folderPath: ['home', 'user', 'contracts'],
|
|
68
|
-
documentMetadata: {
|
|
69
|
-
title: 'Contract Agreement',
|
|
70
|
-
author: 'John Doe',
|
|
71
|
-
subject: 'Service Contract'
|
|
72
|
-
}
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
const mockResponse = {
|
|
76
|
-
choices: [{
|
|
77
|
-
message: {
|
|
78
|
-
content: 'service-contract-agreement-john-doe',
|
|
79
|
-
role: 'assistant'
|
|
80
|
-
},
|
|
81
|
-
finish_reason: 'stop'
|
|
82
|
-
}]
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
mockFetch.mockResolvedValueOnce({
|
|
86
|
-
ok: true,
|
|
87
|
-
json: async () => mockResponse
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
const result = await lmstudioService.generateFileName(
|
|
91
|
-
'Contract content here...',
|
|
92
|
-
'document.pdf',
|
|
93
|
-
'kebab-case',
|
|
94
|
-
'document',
|
|
95
|
-
mockFileInfo
|
|
96
|
-
);
|
|
97
|
-
|
|
98
|
-
expect(result).toBe('service-contract-agreement-john-doe');
|
|
99
|
-
|
|
100
|
-
const fetchCall = mockFetch.mock.calls[0];
|
|
101
|
-
const requestBody = JSON.parse(fetchCall[1].body);
|
|
102
|
-
const userMessage = requestBody.messages.find((m: any) => m.role === 'user');
|
|
103
|
-
|
|
104
|
-
expect(userMessage.content).toContain('- Title: Contract Agreement');
|
|
105
|
-
expect(userMessage.content).toContain('- Author: John Doe');
|
|
106
|
-
expect(userMessage.content).toContain('- Subject: Service Contract');
|
|
107
|
-
expect(userMessage.content).toContain('- Parent folder: contracts');
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
it('should use proper OpenAI API parameters', async () => {
|
|
111
|
-
const mockResponse = {
|
|
112
|
-
choices: [{
|
|
113
|
-
message: {
|
|
114
|
-
content: 'test-filename',
|
|
115
|
-
role: 'assistant'
|
|
116
|
-
},
|
|
117
|
-
finish_reason: 'stop'
|
|
118
|
-
}]
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
mockFetch.mockResolvedValueOnce({
|
|
122
|
-
ok: true,
|
|
123
|
-
json: async () => mockResponse
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
await lmstudioService.generateFileName('content', 'file.txt');
|
|
127
|
-
|
|
128
|
-
const fetchCall = mockFetch.mock.calls[0];
|
|
129
|
-
const requestBody = JSON.parse(fetchCall[1].body);
|
|
130
|
-
|
|
131
|
-
expect(requestBody).toMatchObject({
|
|
132
|
-
model: 'local-model',
|
|
133
|
-
temperature: 0.3,
|
|
134
|
-
max_tokens: 100,
|
|
135
|
-
stream: false
|
|
136
|
-
});
|
|
137
|
-
expect(requestBody.messages).toHaveLength(2); // system + user
|
|
138
|
-
expect(requestBody.messages[0].role).toBe('system');
|
|
139
|
-
expect(requestBody.messages[1].role).toBe('user');
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
it('should sanitize response content', async () => {
|
|
143
|
-
const mockResponse = {
|
|
144
|
-
choices: [{
|
|
145
|
-
message: {
|
|
146
|
-
content: '"Project Report.docx"',
|
|
147
|
-
role: 'assistant'
|
|
148
|
-
},
|
|
149
|
-
finish_reason: 'stop'
|
|
150
|
-
}]
|
|
151
|
-
};
|
|
152
|
-
|
|
153
|
-
mockFetch.mockResolvedValueOnce({
|
|
154
|
-
ok: true,
|
|
155
|
-
json: async () => mockResponse
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
const result = await lmstudioService.generateFileName(
|
|
159
|
-
'Report content',
|
|
160
|
-
'report.docx',
|
|
161
|
-
'kebab-case'
|
|
162
|
-
);
|
|
163
|
-
|
|
164
|
-
expect(result).toBe('project-report'); // Should remove quotes and extension
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
it('should handle API errors', async () => {
|
|
168
|
-
mockFetch.mockResolvedValueOnce({
|
|
169
|
-
ok: false,
|
|
170
|
-
status: 500,
|
|
171
|
-
statusText: 'Internal Server Error',
|
|
172
|
-
text: async () => 'Server error'
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
await expect(
|
|
176
|
-
lmstudioService.generateFileName('content', 'file.txt')
|
|
177
|
-
).rejects.toThrow('LMStudio service failed');
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
it('should handle network errors', async () => {
|
|
181
|
-
mockFetch.mockRejectedValueOnce(new Error('Network error'));
|
|
182
|
-
|
|
183
|
-
await expect(
|
|
184
|
-
lmstudioService.generateFileName('content', 'file.txt')
|
|
185
|
-
).rejects.toThrow('LMStudio service failed');
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
it('should handle empty response', async () => {
|
|
189
|
-
const mockResponse = {
|
|
190
|
-
choices: [{
|
|
191
|
-
message: {
|
|
192
|
-
content: '',
|
|
193
|
-
role: 'assistant'
|
|
194
|
-
},
|
|
195
|
-
finish_reason: 'stop'
|
|
196
|
-
}]
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
mockFetch.mockResolvedValueOnce({
|
|
200
|
-
ok: true,
|
|
201
|
-
json: async () => mockResponse
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
await expect(
|
|
205
|
-
lmstudioService.generateFileName('content', 'file.txt')
|
|
206
|
-
).rejects.toThrow('LMStudio service failed');
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
it('should handle missing choices in response', async () => {
|
|
210
|
-
const mockResponse = {
|
|
211
|
-
choices: []
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
mockFetch.mockResolvedValueOnce({
|
|
215
|
-
ok: true,
|
|
216
|
-
json: async () => mockResponse
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
await expect(
|
|
220
|
-
lmstudioService.generateFileName('content', 'file.txt')
|
|
221
|
-
).rejects.toThrow('LMStudio service failed');
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
it('should use custom base URL and model', async () => {
|
|
225
|
-
const customService = new LMStudioService('http://custom:8080', 'custom-model');
|
|
226
|
-
|
|
227
|
-
const mockResponse = {
|
|
228
|
-
choices: [{
|
|
229
|
-
message: {
|
|
230
|
-
content: 'test-filename',
|
|
231
|
-
role: 'assistant'
|
|
232
|
-
},
|
|
233
|
-
finish_reason: 'stop'
|
|
234
|
-
}]
|
|
235
|
-
};
|
|
236
|
-
|
|
237
|
-
mockFetch.mockResolvedValueOnce({
|
|
238
|
-
ok: true,
|
|
239
|
-
json: async () => mockResponse
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
await customService.generateFileName('content', 'file.txt');
|
|
243
|
-
|
|
244
|
-
expect(mockFetch).toHaveBeenCalledWith(
|
|
245
|
-
'http://custom:8080/v1/chat/completions',
|
|
246
|
-
expect.objectContaining({
|
|
247
|
-
body: expect.stringContaining('"model":"custom-model"')
|
|
248
|
-
})
|
|
249
|
-
);
|
|
250
|
-
});
|
|
251
|
-
});
|
|
252
|
-
|
|
253
|
-
describe('isAvailable()', () => {
|
|
254
|
-
it('should return true when service is available', async () => {
|
|
255
|
-
mockFetch.mockResolvedValueOnce({
|
|
256
|
-
ok: true
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
const result = await lmstudioService.isAvailable();
|
|
260
|
-
|
|
261
|
-
expect(result).toBe(true);
|
|
262
|
-
expect(mockFetch).toHaveBeenCalledWith('http://localhost:1234/v1/models');
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
it('should return false when service is not available', async () => {
|
|
266
|
-
mockFetch.mockResolvedValueOnce({
|
|
267
|
-
ok: false
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
const result = await lmstudioService.isAvailable();
|
|
271
|
-
|
|
272
|
-
expect(result).toBe(false);
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
it('should return false on network error', async () => {
|
|
276
|
-
mockFetch.mockRejectedValueOnce(new Error('Network error'));
|
|
277
|
-
|
|
278
|
-
const result = await lmstudioService.isAvailable();
|
|
279
|
-
|
|
280
|
-
expect(result).toBe(false);
|
|
281
|
-
});
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
describe('listModels()', () => {
|
|
285
|
-
it('should return list of model IDs', async () => {
|
|
286
|
-
const mockResponse = {
|
|
287
|
-
data: [
|
|
288
|
-
{ id: 'local-model-1', object: 'model', created: 123456, owned_by: 'lmstudio' },
|
|
289
|
-
{ id: 'local-model-2', object: 'model', created: 123457, owned_by: 'lmstudio' },
|
|
290
|
-
{ id: 'custom-model', object: 'model', created: 123458, owned_by: 'user' }
|
|
291
|
-
]
|
|
292
|
-
};
|
|
293
|
-
|
|
294
|
-
mockFetch.mockResolvedValueOnce({
|
|
295
|
-
ok: true,
|
|
296
|
-
json: async () => mockResponse
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
const result = await lmstudioService.listModels();
|
|
300
|
-
|
|
301
|
-
expect(result).toEqual(['local-model-1', 'local-model-2', 'custom-model']);
|
|
302
|
-
expect(mockFetch).toHaveBeenCalledWith('http://localhost:1234/v1/models');
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
it('should return empty array on error', async () => {
|
|
306
|
-
mockFetch.mockResolvedValueOnce({
|
|
307
|
-
ok: false
|
|
308
|
-
});
|
|
309
|
-
|
|
310
|
-
const result = await lmstudioService.listModels();
|
|
311
|
-
|
|
312
|
-
expect(result).toEqual([]);
|
|
313
|
-
});
|
|
314
|
-
|
|
315
|
-
it('should handle malformed response', async () => {
|
|
316
|
-
mockFetch.mockResolvedValueOnce({
|
|
317
|
-
ok: true,
|
|
318
|
-
json: async () => ({ invalid: 'response' })
|
|
319
|
-
});
|
|
320
|
-
|
|
321
|
-
const result = await lmstudioService.listModels();
|
|
322
|
-
|
|
323
|
-
expect(result).toEqual([]);
|
|
324
|
-
});
|
|
325
|
-
});
|
|
326
|
-
});
|
|
@@ -1,264 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
2
|
-
import { OllamaService } from '../../../src/services/ollama-service.js';
|
|
3
|
-
import { FileInfo } from '../../../src/types/index.js';
|
|
4
|
-
|
|
5
|
-
// Mock fetch globally
|
|
6
|
-
const mockFetch = vi.fn();
|
|
7
|
-
global.fetch = mockFetch;
|
|
8
|
-
|
|
9
|
-
describe('OllamaService', () => {
|
|
10
|
-
let ollamaService: OllamaService;
|
|
11
|
-
|
|
12
|
-
beforeEach(() => {
|
|
13
|
-
ollamaService = new OllamaService();
|
|
14
|
-
vi.clearAllMocks();
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
describe('generateFileName()', () => {
|
|
18
|
-
it('should generate filename using Ollama chat API', async () => {
|
|
19
|
-
const mockResponse = {
|
|
20
|
-
message: {
|
|
21
|
-
content: 'project-requirements-document',
|
|
22
|
-
role: 'assistant'
|
|
23
|
-
},
|
|
24
|
-
done: true
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
mockFetch.mockResolvedValueOnce({
|
|
28
|
-
ok: true,
|
|
29
|
-
json: async () => mockResponse
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
const result = await ollamaService.generateFileName(
|
|
33
|
-
'This document contains project requirements and specifications.',
|
|
34
|
-
'document.txt',
|
|
35
|
-
'kebab-case',
|
|
36
|
-
'document'
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
expect(result).toBe('project-requirements-document');
|
|
40
|
-
expect(mockFetch).toHaveBeenCalledWith(
|
|
41
|
-
'http://localhost:11434/api/chat',
|
|
42
|
-
expect.objectContaining({
|
|
43
|
-
method: 'POST',
|
|
44
|
-
headers: { 'Content-Type': 'application/json' },
|
|
45
|
-
body: expect.stringContaining('"model":"llama3.1"')
|
|
46
|
-
})
|
|
47
|
-
);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it('should include file metadata in the prompt', async () => {
|
|
51
|
-
const mockFileInfo: FileInfo = {
|
|
52
|
-
path: '/test/document.pdf',
|
|
53
|
-
name: 'document.pdf',
|
|
54
|
-
extension: '.pdf',
|
|
55
|
-
size: 1024,
|
|
56
|
-
createdAt: new Date(),
|
|
57
|
-
modifiedAt: new Date(),
|
|
58
|
-
accessedAt: new Date(),
|
|
59
|
-
parentFolder: 'contracts',
|
|
60
|
-
folderPath: ['home', 'user', 'contracts'],
|
|
61
|
-
documentMetadata: {
|
|
62
|
-
title: 'Contract Agreement',
|
|
63
|
-
author: 'John Doe',
|
|
64
|
-
subject: 'Service Contract'
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
const mockResponse = {
|
|
69
|
-
message: {
|
|
70
|
-
content: 'service-contract-agreement-john-doe',
|
|
71
|
-
role: 'assistant'
|
|
72
|
-
},
|
|
73
|
-
done: true
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
mockFetch.mockResolvedValueOnce({
|
|
77
|
-
ok: true,
|
|
78
|
-
json: async () => mockResponse
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
const result = await ollamaService.generateFileName(
|
|
82
|
-
'Contract content here...',
|
|
83
|
-
'document.pdf',
|
|
84
|
-
'kebab-case',
|
|
85
|
-
'document',
|
|
86
|
-
mockFileInfo
|
|
87
|
-
);
|
|
88
|
-
|
|
89
|
-
expect(result).toBe('service-contract-agreement-john-doe');
|
|
90
|
-
|
|
91
|
-
const fetchCall = mockFetch.mock.calls[0];
|
|
92
|
-
const requestBody = JSON.parse(fetchCall[1].body);
|
|
93
|
-
const userMessage = requestBody.messages.find((m: any) => m.role === 'user');
|
|
94
|
-
|
|
95
|
-
expect(userMessage.content).toContain('- Title: Contract Agreement');
|
|
96
|
-
expect(userMessage.content).toContain('- Author: John Doe');
|
|
97
|
-
expect(userMessage.content).toContain('- Subject: Service Contract');
|
|
98
|
-
expect(userMessage.content).toContain('- Parent folder: contracts');
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
it('should sanitize response content', async () => {
|
|
102
|
-
const mockResponse = {
|
|
103
|
-
message: {
|
|
104
|
-
content: '"Project Report.docx"',
|
|
105
|
-
role: 'assistant'
|
|
106
|
-
},
|
|
107
|
-
done: true
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
mockFetch.mockResolvedValueOnce({
|
|
111
|
-
ok: true,
|
|
112
|
-
json: async () => mockResponse
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
const result = await ollamaService.generateFileName(
|
|
116
|
-
'Report content',
|
|
117
|
-
'report.docx',
|
|
118
|
-
'kebab-case'
|
|
119
|
-
);
|
|
120
|
-
|
|
121
|
-
expect(result).toBe('project-report'); // Should remove quotes and extension
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
it('should handle API errors', async () => {
|
|
125
|
-
mockFetch.mockResolvedValueOnce({
|
|
126
|
-
ok: false,
|
|
127
|
-
status: 500,
|
|
128
|
-
statusText: 'Internal Server Error',
|
|
129
|
-
text: async () => 'Server error'
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
await expect(
|
|
133
|
-
ollamaService.generateFileName('content', 'file.txt')
|
|
134
|
-
).rejects.toThrow('Ollama service failed');
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
it('should handle network errors', async () => {
|
|
138
|
-
mockFetch.mockRejectedValueOnce(new Error('Network error'));
|
|
139
|
-
|
|
140
|
-
await expect(
|
|
141
|
-
ollamaService.generateFileName('content', 'file.txt')
|
|
142
|
-
).rejects.toThrow('Ollama service failed');
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
it('should handle empty response', async () => {
|
|
146
|
-
const mockResponse = {
|
|
147
|
-
message: {
|
|
148
|
-
content: '',
|
|
149
|
-
role: 'assistant'
|
|
150
|
-
},
|
|
151
|
-
done: true
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
mockFetch.mockResolvedValueOnce({
|
|
155
|
-
ok: true,
|
|
156
|
-
json: async () => mockResponse
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
await expect(
|
|
160
|
-
ollamaService.generateFileName('content', 'file.txt')
|
|
161
|
-
).rejects.toThrow('Ollama service failed');
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
it('should use custom base URL and model', async () => {
|
|
165
|
-
const customService = new OllamaService('http://custom:8080', 'custom-model');
|
|
166
|
-
|
|
167
|
-
const mockResponse = {
|
|
168
|
-
message: {
|
|
169
|
-
content: 'test-filename',
|
|
170
|
-
role: 'assistant'
|
|
171
|
-
},
|
|
172
|
-
done: true
|
|
173
|
-
};
|
|
174
|
-
|
|
175
|
-
mockFetch.mockResolvedValueOnce({
|
|
176
|
-
ok: true,
|
|
177
|
-
json: async () => mockResponse
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
await customService.generateFileName('content', 'file.txt');
|
|
181
|
-
|
|
182
|
-
expect(mockFetch).toHaveBeenCalledWith(
|
|
183
|
-
'http://custom:8080/api/chat',
|
|
184
|
-
expect.objectContaining({
|
|
185
|
-
body: expect.stringContaining('"model":"custom-model"')
|
|
186
|
-
})
|
|
187
|
-
);
|
|
188
|
-
});
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
describe('isAvailable()', () => {
|
|
192
|
-
it('should return true when service is available', async () => {
|
|
193
|
-
mockFetch.mockResolvedValueOnce({
|
|
194
|
-
ok: true
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
const result = await ollamaService.isAvailable();
|
|
198
|
-
|
|
199
|
-
expect(result).toBe(true);
|
|
200
|
-
expect(mockFetch).toHaveBeenCalledWith('http://localhost:11434/api/tags');
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
it('should return false when service is not available', async () => {
|
|
204
|
-
mockFetch.mockResolvedValueOnce({
|
|
205
|
-
ok: false
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
const result = await ollamaService.isAvailable();
|
|
209
|
-
|
|
210
|
-
expect(result).toBe(false);
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
it('should return false on network error', async () => {
|
|
214
|
-
mockFetch.mockRejectedValueOnce(new Error('Network error'));
|
|
215
|
-
|
|
216
|
-
const result = await ollamaService.isAvailable();
|
|
217
|
-
|
|
218
|
-
expect(result).toBe(false);
|
|
219
|
-
});
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
describe('listModels()', () => {
|
|
223
|
-
it('should return list of model names', async () => {
|
|
224
|
-
const mockResponse = {
|
|
225
|
-
models: [
|
|
226
|
-
{ name: 'llama3.1' },
|
|
227
|
-
{ name: 'codellama' },
|
|
228
|
-
{ name: 'mistral' }
|
|
229
|
-
]
|
|
230
|
-
};
|
|
231
|
-
|
|
232
|
-
mockFetch.mockResolvedValueOnce({
|
|
233
|
-
ok: true,
|
|
234
|
-
json: async () => mockResponse
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
const result = await ollamaService.listModels();
|
|
238
|
-
|
|
239
|
-
expect(result).toEqual(['llama3.1', 'codellama', 'mistral']);
|
|
240
|
-
expect(mockFetch).toHaveBeenCalledWith('http://localhost:11434/api/tags');
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
it('should return empty array on error', async () => {
|
|
244
|
-
mockFetch.mockResolvedValueOnce({
|
|
245
|
-
ok: false
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
const result = await ollamaService.listModels();
|
|
249
|
-
|
|
250
|
-
expect(result).toEqual([]);
|
|
251
|
-
});
|
|
252
|
-
|
|
253
|
-
it('should handle malformed response', async () => {
|
|
254
|
-
mockFetch.mockResolvedValueOnce({
|
|
255
|
-
ok: true,
|
|
256
|
-
json: async () => ({ invalid: 'response' })
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
const result = await ollamaService.listModels();
|
|
260
|
-
|
|
261
|
-
expect(result).toEqual([]);
|
|
262
|
-
});
|
|
263
|
-
});
|
|
264
|
-
});
|