fragment-ts 1.0.0 → 1.0.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/README.md +401 -0
- package/USAGE.md +1439 -0
- package/bin/fragment.js +2 -0
- package/dist/ai/ai.module.d.ts +27 -0
- package/dist/ai/ai.module.d.ts.map +1 -0
- package/dist/ai/ai.module.js +77 -0
- package/dist/ai/ai.module.js.map +1 -0
- package/dist/auth/auth.module.d.ts +18 -0
- package/dist/auth/auth.module.d.ts.map +1 -0
- package/dist/auth/auth.module.js +89 -0
- package/dist/auth/auth.module.js.map +1 -0
- package/dist/cli/commands/build.command.d.ts +6 -1
- package/dist/cli/commands/build.command.d.ts.map +1 -0
- package/dist/cli/commands/build.command.js +131 -10
- package/dist/cli/commands/build.command.js.map +1 -0
- package/dist/cli/commands/diagnostics.command.d.ts +16 -0
- package/dist/cli/commands/diagnostics.command.d.ts.map +1 -0
- package/dist/cli/commands/diagnostics.command.js +419 -0
- package/dist/cli/commands/diagnostics.command.js.map +1 -0
- package/dist/cli/commands/generate.command.d.ts +13 -6
- package/dist/cli/commands/generate.command.d.ts.map +1 -0
- package/dist/cli/commands/generate.command.js +201 -128
- package/dist/cli/commands/generate.command.js.map +1 -0
- package/dist/cli/commands/init.command.d.ts +11 -5
- package/dist/cli/commands/init.command.d.ts.map +1 -0
- package/dist/cli/commands/init.command.js +268 -305
- package/dist/cli/commands/init.command.js.map +1 -0
- package/dist/cli/commands/migrate.command.d.ts +12 -5
- package/dist/cli/commands/migrate.command.d.ts.map +1 -0
- package/dist/cli/commands/migrate.command.js +212 -83
- package/dist/cli/commands/migrate.command.js.map +1 -0
- package/dist/cli/commands/serve.command.d.ts +5 -4
- package/dist/cli/commands/serve.command.d.ts.map +1 -0
- package/dist/cli/commands/serve.command.js +179 -21
- package/dist/cli/commands/serve.command.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +22 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/container/di-container.d.ts +13 -7
- package/dist/core/container/di-container.d.ts.map +1 -0
- package/dist/core/container/di-container.js +76 -25
- package/dist/core/container/di-container.js.map +1 -0
- package/dist/core/decorators/application.decorator.d.ts +8 -0
- package/dist/core/decorators/application.decorator.d.ts.map +1 -0
- package/dist/core/decorators/application.decorator.js +16 -0
- package/dist/core/decorators/application.decorator.js.map +1 -0
- package/dist/core/decorators/auto-configuration.decorator.d.ts +2 -0
- package/dist/core/decorators/auto-configuration.decorator.d.ts.map +1 -0
- package/dist/core/decorators/auto-configuration.decorator.js +19 -0
- package/dist/core/decorators/auto-configuration.decorator.js.map +1 -0
- package/dist/core/decorators/conditional.decorators.d.ts +4 -0
- package/dist/core/decorators/conditional.decorators.d.ts.map +1 -0
- package/dist/core/decorators/conditional.decorators.js +22 -0
- package/dist/core/decorators/conditional.decorators.js.map +1 -0
- package/dist/core/decorators/controller.decorator.d.ts +1 -3
- package/dist/core/decorators/controller.decorator.d.ts.map +1 -0
- package/dist/core/decorators/controller.decorator.js +13 -9
- package/dist/core/decorators/controller.decorator.js.map +1 -0
- package/dist/core/decorators/http.decorators.d.ts +12 -0
- package/dist/core/decorators/http.decorators.d.ts.map +1 -0
- package/dist/core/decorators/http.decorators.js +52 -0
- package/dist/core/decorators/http.decorators.js.map +1 -0
- package/dist/core/decorators/injectable.decorator.d.ts +3 -3
- package/dist/core/decorators/injectable.decorator.d.ts.map +1 -0
- package/dist/core/decorators/injectable.decorator.js +12 -8
- package/dist/core/decorators/injectable.decorator.js.map +1 -0
- package/dist/core/decorators/injection.decorators.d.ts +5 -0
- package/dist/core/decorators/injection.decorators.d.ts.map +1 -0
- package/dist/core/decorators/injection.decorators.js +29 -0
- package/dist/core/decorators/injection.decorators.js.map +1 -0
- package/dist/core/decorators/repository.decorator.d.ts +1 -0
- package/dist/core/decorators/repository.decorator.d.ts.map +1 -0
- package/dist/core/decorators/repository.decorator.js +13 -1
- package/dist/core/decorators/repository.decorator.js.map +1 -0
- package/dist/core/decorators/service.decorator.d.ts +1 -0
- package/dist/core/decorators/service.decorator.d.ts.map +1 -0
- package/dist/core/decorators/service.decorator.js +13 -1
- package/dist/core/decorators/service.decorator.js.map +1 -0
- package/dist/core/index.d.ts +13 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +29 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/loader/file-loader.d.ts +5 -0
- package/dist/core/loader/file-loader.d.ts.map +1 -0
- package/dist/core/loader/file-loader.js +85 -0
- package/dist/core/loader/file-loader.js.map +1 -0
- package/dist/core/metadata/metadata-keys.d.ts +20 -0
- package/dist/core/metadata/metadata-keys.d.ts.map +1 -0
- package/dist/core/metadata/metadata-keys.js +23 -0
- package/dist/core/metadata/metadata-keys.js.map +1 -0
- package/dist/core/metadata/metadata-storage.d.ts +36 -0
- package/dist/core/metadata/metadata-storage.d.ts.map +1 -0
- package/dist/core/metadata/metadata-storage.js +53 -0
- package/dist/core/metadata/metadata-storage.js.map +1 -0
- package/dist/core/scanner/component-scanner.d.ts +16 -0
- package/dist/core/scanner/component-scanner.d.ts.map +1 -0
- package/dist/core/scanner/component-scanner.js +147 -0
- package/dist/core/scanner/component-scanner.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +60 -0
- package/dist/index.js.map +1 -0
- package/dist/plugins/plugin-manager.d.ts +14 -0
- package/dist/plugins/plugin-manager.d.ts.map +1 -0
- package/dist/{cli/utils/file-generator.js → plugins/plugin-manager.js} +32 -23
- package/dist/plugins/plugin-manager.js.map +1 -0
- package/dist/shared/errors.d.ts +18 -0
- package/dist/shared/errors.d.ts.map +1 -0
- package/dist/shared/errors.js +41 -0
- package/dist/shared/errors.js.map +1 -0
- package/dist/testing/runner.d.ts +26 -0
- package/dist/testing/runner.d.ts.map +1 -0
- package/dist/testing/runner.js +143 -0
- package/dist/testing/runner.js.map +1 -0
- package/dist/typeorm/typeorm-module.d.ts +36 -0
- package/dist/typeorm/typeorm-module.d.ts.map +1 -0
- package/dist/typeorm/typeorm-module.js +150 -0
- package/dist/typeorm/typeorm-module.js.map +1 -0
- package/dist/web/application.d.ts +29 -0
- package/dist/web/application.d.ts.map +1 -0
- package/dist/web/application.js +301 -0
- package/dist/web/application.js.map +1 -0
- package/dist/web/interfaces.d.ts +14 -0
- package/dist/web/interfaces.d.ts.map +1 -0
- package/dist/{auth/dto/login.dto.js → web/interfaces.js} +1 -0
- package/dist/web/interfaces.js.map +1 -0
- package/examples/ai-assistant/fragment.json +18 -0
- package/examples/ai-assistant/package-lock.json +2921 -0
- package/examples/ai-assistant/package.json +20 -0
- package/examples/ai-assistant/src/controllers/app.controller.ts +9 -0
- package/examples/ai-assistant/src/controllers/chat.controller.ts +69 -0
- package/examples/ai-assistant/src/controllers/conversation.controller.ts +29 -0
- package/examples/ai-assistant/src/controllers/message.controller.ts +29 -0
- package/examples/ai-assistant/src/controllers/search.controller.ts +16 -0
- package/examples/ai-assistant/src/dto/create-conversation.dto.ts +6 -0
- package/examples/ai-assistant/src/dto/create-message.dto.ts +6 -0
- package/examples/ai-assistant/src/entities/conversation.entity.ts +23 -0
- package/examples/ai-assistant/src/entities/message.entity.ts +27 -0
- package/examples/ai-assistant/src/entities/user.entity.ts +16 -0
- package/examples/ai-assistant/src/main.ts +15 -0
- package/examples/ai-assistant/src/migrations/1767738396740-CreateConversationTables.ts +37 -0
- package/examples/ai-assistant/src/repositories/conversation.repository.ts +32 -0
- package/examples/ai-assistant/src/repositories/message.repository.ts +30 -0
- package/examples/ai-assistant/src/services/ai.service.ts +41 -0
- package/examples/ai-assistant/src/services/app.service.ts +8 -0
- package/examples/ai-assistant/src/services/conversation.service.ts +75 -0
- package/examples/ai-assistant/src/services/message.service.ts +27 -0
- package/examples/ai-assistant/tsconfig.json +23 -0
- package/examples/blog-api/fragment.json +18 -0
- package/examples/blog-api/package.json +19 -0
- package/examples/blog-api/src/controllers/app.controller.ts +9 -0
- package/examples/blog-api/src/controllers/auth.controller.ts +17 -0
- package/examples/blog-api/src/controllers/category.controller.ts +29 -0
- package/examples/blog-api/src/controllers/comment.controller.ts +27 -0
- package/examples/blog-api/src/controllers/post.controller.ts +46 -0
- package/examples/blog-api/src/dto/create-category.dto.ts +6 -0
- package/examples/blog-api/src/dto/create-comment.dto.ts +6 -0
- package/examples/blog-api/src/dto/create-post.dto.ts +6 -0
- package/examples/blog-api/src/entities/category.entity.ts +16 -0
- package/examples/blog-api/src/entities/comment.entity.ts +29 -0
- package/examples/blog-api/src/entities/post.entity.ts +42 -0
- package/examples/blog-api/src/entities/user.entity.ts +25 -0
- package/examples/blog-api/src/main.ts +16 -0
- package/examples/blog-api/src/migrations/1767737463842-InitialSchema.ts +60 -0
- package/examples/blog-api/src/repositories/category.repository.ts +25 -0
- package/examples/blog-api/src/repositories/comment.repository.ts +25 -0
- package/examples/blog-api/src/repositories/post.repository.ts +29 -0
- package/examples/blog-api/src/seeds/SampleData.seed.ts +41 -0
- package/examples/blog-api/src/services/app.service.ts +8 -0
- package/examples/blog-api/src/services/auth.service.ts +15 -0
- package/examples/blog-api/src/services/category.service.ts +27 -0
- package/examples/blog-api/src/services/comment.service.ts +31 -0
- package/examples/blog-api/src/services/post.service.ts +35 -0
- package/examples/blog-api/tsconfig.json +23 -0
- package/package.json +56 -33
- package/src/ai/ai.module.ts +110 -0
- package/src/auth/auth.module.ts +77 -0
- package/src/cli/commands/build.command.ts +123 -13
- package/src/cli/commands/diagnostics.command.ts +438 -0
- package/src/cli/commands/generate.command.ts +206 -137
- package/src/cli/commands/init.command.ts +337 -349
- package/src/cli/commands/migrate.command.ts +203 -88
- package/src/cli/commands/serve.command.ts +176 -24
- package/src/cli/index.ts +23 -0
- package/src/core/container/di-container.ts +83 -26
- package/src/core/decorators/application.decorator.ts +26 -0
- package/src/core/decorators/auto-configuration.decorator.ts +17 -0
- package/src/core/decorators/conditional.decorators.ts +19 -0
- package/src/core/decorators/controller.decorator.ts +14 -11
- package/src/core/decorators/http.decorators.ts +71 -0
- package/src/core/decorators/injectable.decorator.ts +14 -9
- package/src/core/decorators/injection.decorators.ts +26 -0
- package/src/core/decorators/repository.decorator.ts +13 -2
- package/src/core/decorators/service.decorator.ts +13 -2
- package/src/core/index.ts +13 -0
- package/src/core/loader/file-loader.ts +55 -0
- package/src/core/metadata/metadata-keys.ts +19 -0
- package/src/core/metadata/metadata-storage.ts +91 -0
- package/src/core/scanner/component-scanner.ts +129 -0
- package/src/index.ts +45 -0
- package/src/plugins/plugin-manager.ts +52 -0
- package/src/shared/errors.ts +34 -0
- package/src/testing/runner.ts +143 -0
- package/src/typeorm/typeorm-module.ts +216 -0
- package/src/web/application.ts +348 -0
- package/src/web/interfaces.ts +17 -0
- package/tsconfig.json +8 -5
- package/.env.example +0 -0
- package/base.ts +0 -1810
- package/base2.ts +0 -968
- package/bin/frg.ts +0 -5
- package/config/fragment.lock.yaml +0 -0
- package/config/fragment.yaml +0 -0
- package/dist/app.d.ts +0 -15
- package/dist/app.js +0 -90
- package/dist/auth/auth.controller.d.ts +0 -10
- package/dist/auth/auth.controller.js +0 -87
- package/dist/auth/auth.middleware.d.ts +0 -2
- package/dist/auth/auth.middleware.js +0 -24
- package/dist/auth/auth.service.d.ts +0 -20
- package/dist/auth/auth.service.js +0 -143
- package/dist/auth/dto/login.dto.d.ts +0 -9
- package/dist/cli/cli.d.ts +0 -12
- package/dist/cli/cli.js +0 -186
- package/dist/cli/commands/config.command.d.ts +0 -6
- package/dist/cli/commands/config.command.js +0 -284
- package/dist/cli/templates/controller.template.d.ts +0 -1
- package/dist/cli/templates/controller.template.js +0 -52
- package/dist/cli/templates/entity.template.d.ts +0 -1
- package/dist/cli/templates/entity.template.js +0 -23
- package/dist/cli/templates/repository.template.d.ts +0 -1
- package/dist/cli/templates/repository.template.js +0 -43
- package/dist/cli/templates/service.template.d.ts +0 -1
- package/dist/cli/templates/service.template.js +0 -43
- package/dist/cli/utils/file-generator.d.ts +0 -9
- package/dist/cli/utils/logger.d.ts +0 -14
- package/dist/cli/utils/logger.js +0 -49
- package/dist/controllers/health.controller.d.ts +0 -13
- package/dist/controllers/health.controller.js +0 -50
- package/dist/core/config/config-loader.d.ts +0 -31
- package/dist/core/config/config-loader.js +0 -98
- package/dist/core/decorators/auth-guard.decorator.d.ts +0 -3
- package/dist/core/decorators/auth-guard.decorator.js +0 -18
- package/dist/core/decorators/autowire.decorator.d.ts +0 -3
- package/dist/core/decorators/autowire.decorator.js +0 -17
- package/dist/core/decorators/middleware.decorator.d.ts +0 -3
- package/dist/core/decorators/middleware.decorator.js +0 -20
- package/dist/core/decorators/route.decorator.d.ts +0 -14
- package/dist/core/decorators/route.decorator.js +0 -32
- package/dist/core/openai/openai-client.d.ts +0 -12
- package/dist/core/openai/openai-client.js +0 -93
- package/dist/database/data-source.d.ts +0 -4
- package/dist/database/data-source.js +0 -26
- package/dist/entities/session.entity.d.ts +0 -9
- package/dist/entities/session.entity.js +0 -45
- package/dist/entities/user.entity.d.ts +0 -10
- package/dist/entities/user.entity.js +0 -48
- package/dist/middlewares/logging.middleware.d.ts +0 -2
- package/dist/middlewares/logging.middleware.js +0 -28
- package/dist/repositories/session.repository.d.ts +0 -9
- package/dist/repositories/session.repository.js +0 -50
- package/dist/repositories/user.repository.d.ts +0 -10
- package/dist/repositories/user.repository.js +0 -43
- package/dist/server.d.ts +0 -1
- package/dist/server.js +0 -30
- package/dist/services/health.service.d.ts +0 -13
- package/dist/services/health.service.js +0 -44
- package/readme.md +0 -120
- package/src/app.ts +0 -121
- package/src/auth/auth.controller.ts +0 -52
- package/src/auth/auth.middleware.ts +0 -27
- package/src/auth/auth.service.ts +0 -110
- package/src/auth/dto/login.dto.ts +0 -11
- package/src/cli/cli.ts +0 -212
- package/src/cli/commands/config.command.ts +0 -280
- package/src/cli/templates/controller.template.ts +0 -51
- package/src/cli/templates/entity.template.ts +0 -22
- package/src/cli/templates/repository.template.ts +0 -42
- package/src/cli/templates/service.template.ts +0 -42
- package/src/cli/utils/file-generator.ts +0 -37
- package/src/cli/utils/logger.ts +0 -52
- package/src/controllers/health.controller.ts +0 -24
- package/src/core/config/config-loader.ts +0 -98
- package/src/core/decorators/auth-guard.decorator.ts +0 -15
- package/src/core/decorators/autowire.decorator.ts +0 -18
- package/src/core/decorators/middleware.decorator.ts +0 -18
- package/src/core/decorators/route.decorator.ts +0 -33
- package/src/core/openai/openai-client.ts +0 -99
- package/src/database/data-source.ts +0 -29
- package/src/entities/session.entity.ts +0 -25
- package/src/entities/user.entity.ts +0 -27
- package/src/middlewares/logging.middleware.ts +0 -28
- package/src/repositories/session.repository.ts +0 -42
- package/src/repositories/user.repository.ts +0 -37
- package/src/server.ts +0 -32
- package/src/services/health.service.ts +0 -29
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ai-assistant",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "dist/main.js",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"start": "node dist/main.js",
|
|
7
|
+
"dev": "fragment serve",
|
|
8
|
+
"build": "fragment build",
|
|
9
|
+
"test": "fragment test"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"fragment": "^1.0.0",
|
|
13
|
+
"reflect-metadata": "^0.1.13"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@types/node": "^20.10.5",
|
|
17
|
+
"ts-node": "^10.9.2",
|
|
18
|
+
"typescript": "^5.3.3"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Controller, Get, Post, Body, Param, Res } from "fragment";
|
|
2
|
+
import { ConversationService } from "../services/conversation.service";
|
|
3
|
+
import { Response } from "express";
|
|
4
|
+
|
|
5
|
+
@Controller("/api/chat")
|
|
6
|
+
export class ChatController {
|
|
7
|
+
constructor(private conversationService: ConversationService) {}
|
|
8
|
+
|
|
9
|
+
@Post("/conversations")
|
|
10
|
+
async createConversation(@Body() body: any) {
|
|
11
|
+
return this.conversationService.create(body.userId || 1, body.title);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@Get("/conversations/:userId")
|
|
15
|
+
async getConversations(@Param("userId") userId: string) {
|
|
16
|
+
return this.conversationService.findByUser(parseInt(userId));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
@Get("/conversations/:id/messages")
|
|
20
|
+
async getMessages(@Param("id") id: string) {
|
|
21
|
+
return this.conversationService.getMessages(parseInt(id));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@Post("/conversations/:id/message")
|
|
25
|
+
async sendMessage(@Param("id") id: string, @Body() body: any) {
|
|
26
|
+
return this.conversationService.chat(parseInt(id), body.message);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@Post("/conversations/:id/stream")
|
|
30
|
+
async streamMessage(
|
|
31
|
+
@Param("id") id: string,
|
|
32
|
+
@Body() body: any,
|
|
33
|
+
@Res() res: Response,
|
|
34
|
+
) {
|
|
35
|
+
res.setHeader("Content-Type", "text/event-stream");
|
|
36
|
+
res.setHeader("Cache-Control", "no-cache");
|
|
37
|
+
res.setHeader("Connection", "keep-alive");
|
|
38
|
+
|
|
39
|
+
let fullResponse = "";
|
|
40
|
+
|
|
41
|
+
await this.conversationService.addMessage(
|
|
42
|
+
parseInt(id),
|
|
43
|
+
"user",
|
|
44
|
+
body.message,
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
const messages = await this.conversationService.getMessages(parseInt(id));
|
|
48
|
+
const aiMessages = messages.map((m: any) => ({
|
|
49
|
+
role: m.role as any,
|
|
50
|
+
content: m.content,
|
|
51
|
+
}));
|
|
52
|
+
|
|
53
|
+
const aiService = (this.conversationService as any).aiService;
|
|
54
|
+
|
|
55
|
+
await aiService.streamChat(aiMessages, (chunk: string) => {
|
|
56
|
+
fullResponse += chunk;
|
|
57
|
+
res.write(`data: ${JSON.stringify({ chunk })}\n\n`);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
await this.conversationService.addMessage(
|
|
61
|
+
parseInt(id),
|
|
62
|
+
"assistant",
|
|
63
|
+
fullResponse,
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
res.write("data: [DONE]\n\n");
|
|
67
|
+
res.end();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Controller, Get, Post, Put, Delete, Body, Param } from 'fragment';
|
|
2
|
+
|
|
3
|
+
@Controller('/conversation')
|
|
4
|
+
export class ConversationController {
|
|
5
|
+
@Get()
|
|
6
|
+
findAll() {
|
|
7
|
+
return [];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
@Get('/:id')
|
|
11
|
+
findOne(@Param('id') id: string) {
|
|
12
|
+
return { id };
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
@Post()
|
|
16
|
+
create(@Body() body: any) {
|
|
17
|
+
return body;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@Put('/:id')
|
|
21
|
+
update(@Param('id') id: string, @Body() body: any) {
|
|
22
|
+
return { id, ...body };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@Delete('/:id')
|
|
26
|
+
delete(@Param('id') id: string) {
|
|
27
|
+
return { deleted: true, id };
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Controller, Get, Post, Put, Delete, Body, Param } from 'fragment';
|
|
2
|
+
|
|
3
|
+
@Controller('/message')
|
|
4
|
+
export class MessageController {
|
|
5
|
+
@Get()
|
|
6
|
+
findAll() {
|
|
7
|
+
return [];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
@Get('/:id')
|
|
11
|
+
findOne(@Param('id') id: string) {
|
|
12
|
+
return { id };
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
@Post()
|
|
16
|
+
create(@Body() body: any) {
|
|
17
|
+
return body;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@Put('/:id')
|
|
21
|
+
update(@Param('id') id: string, @Body() body: any) {
|
|
22
|
+
return { id, ...body };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@Delete('/:id')
|
|
26
|
+
delete(@Param('id') id: string) {
|
|
27
|
+
return { deleted: true, id };
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Controller, Post, Body, Query } from "fragment";
|
|
2
|
+
import { ConversationService } from "../services/conversation.service";
|
|
3
|
+
|
|
4
|
+
@Controller("/api/search")
|
|
5
|
+
export class SearchController {
|
|
6
|
+
constructor(private conversationService: ConversationService) {}
|
|
7
|
+
|
|
8
|
+
@Post("/semantic")
|
|
9
|
+
async semanticSearch(
|
|
10
|
+
@Body() body: any,
|
|
11
|
+
@Query("conversationId") conversationId?: string,
|
|
12
|
+
) {
|
|
13
|
+
const convId = conversationId ? parseInt(conversationId) : undefined;
|
|
14
|
+
return this.conversationService.semanticSearch(body.query, convId);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm';
|
|
2
|
+
import { Message } from './message.entity';
|
|
3
|
+
|
|
4
|
+
@Entity()
|
|
5
|
+
export class Conversation {
|
|
6
|
+
@PrimaryGeneratedColumn()
|
|
7
|
+
id!: number;
|
|
8
|
+
|
|
9
|
+
@Column()
|
|
10
|
+
title!: string;
|
|
11
|
+
|
|
12
|
+
@Column()
|
|
13
|
+
userId!: number;
|
|
14
|
+
|
|
15
|
+
@OneToMany(() => Message, message => message.conversation)
|
|
16
|
+
messages!: Message[];
|
|
17
|
+
|
|
18
|
+
@Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })
|
|
19
|
+
createdAt!: Date;
|
|
20
|
+
|
|
21
|
+
@Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })
|
|
22
|
+
updatedAt!: Date;
|
|
23
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';
|
|
2
|
+
import { Conversation } from './conversation.entity';
|
|
3
|
+
|
|
4
|
+
@Entity()
|
|
5
|
+
export class Message {
|
|
6
|
+
@PrimaryGeneratedColumn()
|
|
7
|
+
id!: number;
|
|
8
|
+
|
|
9
|
+
@Column()
|
|
10
|
+
conversationId!: number;
|
|
11
|
+
|
|
12
|
+
@ManyToOne(() => Conversation, conversation => conversation.messages)
|
|
13
|
+
@JoinColumn({ name: 'conversationId' })
|
|
14
|
+
conversation!: Conversation;
|
|
15
|
+
|
|
16
|
+
@Column()
|
|
17
|
+
role!: string;
|
|
18
|
+
|
|
19
|
+
@Column('text')
|
|
20
|
+
content!: string;
|
|
21
|
+
|
|
22
|
+
@Column('simple-json', { nullable: true })
|
|
23
|
+
embedding!: number[];
|
|
24
|
+
|
|
25
|
+
@Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })
|
|
26
|
+
createdAt?: Date;
|
|
27
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
|
|
2
|
+
|
|
3
|
+
@Entity()
|
|
4
|
+
export class User {
|
|
5
|
+
@PrimaryGeneratedColumn()
|
|
6
|
+
id!: number;
|
|
7
|
+
|
|
8
|
+
@Column()
|
|
9
|
+
email!: string;
|
|
10
|
+
|
|
11
|
+
@Column()
|
|
12
|
+
name!: string;
|
|
13
|
+
|
|
14
|
+
@Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })
|
|
15
|
+
createdAt?: Date;
|
|
16
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { FragmentApplication } from 'fragment';
|
|
3
|
+
import { FragmentWebApplication } from 'fragment';
|
|
4
|
+
|
|
5
|
+
@FragmentApplication({
|
|
6
|
+
port: 3000,
|
|
7
|
+
})
|
|
8
|
+
class Application {}
|
|
9
|
+
|
|
10
|
+
async function bootstrap() {
|
|
11
|
+
const app = new FragmentWebApplication();
|
|
12
|
+
await app.bootstrap(Application);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
bootstrap();
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { MigrationInterface, QueryRunner, Table } from "typeorm";
|
|
2
|
+
|
|
3
|
+
export class CreateConversationTables1234567890 implements MigrationInterface {
|
|
4
|
+
async up(queryRunner: QueryRunner): Promise<void> {
|
|
5
|
+
await queryRunner.createTable(
|
|
6
|
+
new Table({
|
|
7
|
+
name: "conversation",
|
|
8
|
+
columns: [
|
|
9
|
+
{ name: "id", type: "integer", isPrimary: true, isGenerated: true },
|
|
10
|
+
{ name: "title", type: "varchar" },
|
|
11
|
+
{ name: "userId", type: "integer" },
|
|
12
|
+
{ name: "createdAt", type: "datetime", default: "CURRENT_TIMESTAMP" },
|
|
13
|
+
{ name: "updatedAt", type: "datetime", default: "CURRENT_TIMESTAMP" },
|
|
14
|
+
],
|
|
15
|
+
}),
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
await queryRunner.createTable(
|
|
19
|
+
new Table({
|
|
20
|
+
name: "message",
|
|
21
|
+
columns: [
|
|
22
|
+
{ name: "id", type: "integer", isPrimary: true, isGenerated: true },
|
|
23
|
+
{ name: "conversationId", type: "integer" },
|
|
24
|
+
{ name: "role", type: "varchar" },
|
|
25
|
+
{ name: "content", type: "text" },
|
|
26
|
+
{ name: "embedding", type: "text", isNullable: true },
|
|
27
|
+
{ name: "createdAt", type: "datetime", default: "CURRENT_TIMESTAMP" },
|
|
28
|
+
],
|
|
29
|
+
}),
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async down(queryRunner: QueryRunner): Promise<void> {
|
|
34
|
+
await queryRunner.dropTable("message");
|
|
35
|
+
await queryRunner.dropTable("conversation");
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Repository } from "fragment";
|
|
2
|
+
import { Conversation } from "../entities/conversation.entity";
|
|
3
|
+
|
|
4
|
+
@Repository()
|
|
5
|
+
export class ConversationRepository {
|
|
6
|
+
async findAll(): Promise<Conversation[]> {
|
|
7
|
+
return [];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
async findById(id: number): Promise<Conversation | null> {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async create(data: Partial<Conversation>): Promise<Conversation> {
|
|
15
|
+
return data as Conversation;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async update(
|
|
19
|
+
id: number,
|
|
20
|
+
data: Partial<Conversation>,
|
|
21
|
+
): Promise<Conversation | null> {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async delete(id: number): Promise<boolean> {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async findByUser(userId: number): Promise<Conversation[]> {
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Repository } from "fragment";
|
|
2
|
+
import { Message } from "../entities/message.entity";
|
|
3
|
+
import { Conversation } from "../entities/conversation.entity";
|
|
4
|
+
|
|
5
|
+
@Repository()
|
|
6
|
+
export class MessageRepository {
|
|
7
|
+
async findAll(): Promise<Message[]> {
|
|
8
|
+
return [];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async findById(id: number): Promise<Message | null> {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async create(data: Partial<Message>): Promise<Message> {
|
|
16
|
+
return data as Message;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async update(id: number, data: Partial<Message>): Promise<Message | null> {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async delete(id: number): Promise<boolean> {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async findByConversation(conversationId: number): Promise<Conversation[]> {
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Service } from 'fragment';
|
|
2
|
+
import { AIModule } from 'fragment';
|
|
3
|
+
|
|
4
|
+
@Service()
|
|
5
|
+
export class AIService {
|
|
6
|
+
private aiModule: AIModule;
|
|
7
|
+
|
|
8
|
+
constructor() {
|
|
9
|
+
this.aiModule = new AIModule({
|
|
10
|
+
openaiKey: process.env.OPENAI_API_KEY,
|
|
11
|
+
ollamaUrl: process.env.OLLAMA_URL
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async chat(messages: any[]) {
|
|
16
|
+
return this.aiModule.complete(messages, {
|
|
17
|
+
model: 'gpt-3.5-turbo',
|
|
18
|
+
temperature: 0.7,
|
|
19
|
+
maxTokens: 1000
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async streamChat(messages: any[], onChunk: (chunk: string) => void) {
|
|
24
|
+
await this.aiModule.streamComplete(messages, {
|
|
25
|
+
model: 'gpt-3.5-turbo',
|
|
26
|
+
temperature: 0.7
|
|
27
|
+
}, onChunk);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async generateEmbedding(text: string): Promise<number[]> {
|
|
31
|
+
const embeddings = await this.aiModule.embeddings([text]);
|
|
32
|
+
return embeddings[0];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
cosineSimilarity(a: number[], b: number[]): number {
|
|
36
|
+
const dotProduct = a.reduce((sum, val, i) => sum + val * b[i], 0);
|
|
37
|
+
const magnitudeA = Math.sqrt(a.reduce((sum, val) => sum + val * val, 0));
|
|
38
|
+
const magnitudeB = Math.sqrt(b.reduce((sum, val) => sum + val * val, 0));
|
|
39
|
+
return dotProduct / (magnitudeA * magnitudeB);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { Service } from "fragment";
|
|
2
|
+
import { ConversationRepository } from "../repositories/conversation.repository";
|
|
3
|
+
import { MessageRepository } from "../repositories/message.repository";
|
|
4
|
+
import { AIService } from "./ai.service";
|
|
5
|
+
|
|
6
|
+
@Service()
|
|
7
|
+
export class ConversationService {
|
|
8
|
+
constructor(
|
|
9
|
+
private conversationRepository: ConversationRepository,
|
|
10
|
+
private messageRepository: MessageRepository,
|
|
11
|
+
private aiService: AIService,
|
|
12
|
+
) {}
|
|
13
|
+
|
|
14
|
+
async create(userId: number, title: string) {
|
|
15
|
+
return this.conversationRepository.create({ userId, title });
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async findByUser(userId: number) {
|
|
19
|
+
return this.conversationRepository.findByUser(userId);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async addMessage(conversationId: number, role: string, content: string) {
|
|
23
|
+
const embedding = await this.aiService.generateEmbedding(content);
|
|
24
|
+
|
|
25
|
+
return this.messageRepository.create({
|
|
26
|
+
conversationId,
|
|
27
|
+
role,
|
|
28
|
+
content,
|
|
29
|
+
embedding,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async getMessages(conversationId: number) {
|
|
34
|
+
return this.messageRepository.findByConversation(conversationId);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async chat(conversationId: number, userMessage: string) {
|
|
38
|
+
await this.addMessage(conversationId, "user", userMessage);
|
|
39
|
+
|
|
40
|
+
const messages = await this.getMessages(conversationId);
|
|
41
|
+
const aiMessages = messages.map((m:any) => ({
|
|
42
|
+
role: m.role as any,
|
|
43
|
+
content: m.content,
|
|
44
|
+
}));
|
|
45
|
+
|
|
46
|
+
const response = await this.aiService.chat(aiMessages);
|
|
47
|
+
|
|
48
|
+
await this.addMessage(conversationId, "assistant", response);
|
|
49
|
+
|
|
50
|
+
return { response };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async semanticSearch(query: string, conversationId?: number) {
|
|
54
|
+
const queryEmbedding = await this.aiService.generateEmbedding(query);
|
|
55
|
+
|
|
56
|
+
let messages = await this.messageRepository.findAll();
|
|
57
|
+
|
|
58
|
+
if (conversationId) {
|
|
59
|
+
messages = messages.filter((m) => m.conversationId === conversationId);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const results = messages
|
|
63
|
+
.map((message) => ({
|
|
64
|
+
message,
|
|
65
|
+
similarity: this.aiService.cosineSimilarity(
|
|
66
|
+
queryEmbedding,
|
|
67
|
+
message.embedding || [],
|
|
68
|
+
),
|
|
69
|
+
}))
|
|
70
|
+
.sort((a, b) => b.similarity - a.similarity)
|
|
71
|
+
.slice(0, 5);
|
|
72
|
+
|
|
73
|
+
return results;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Service } from 'fragment';
|
|
2
|
+
import { MessageRepository } from '../repositories/message.repository';
|
|
3
|
+
|
|
4
|
+
@Service()
|
|
5
|
+
export class MessageService {
|
|
6
|
+
constructor(private messageRepository: MessageRepository) {}
|
|
7
|
+
|
|
8
|
+
async findAll() {
|
|
9
|
+
return [];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async findOne(id: string) {
|
|
13
|
+
return { id };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async create(data: any) {
|
|
17
|
+
return data;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async update(id: string, data: any) {
|
|
21
|
+
return { id, ...data };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async delete(id: string) {
|
|
25
|
+
return { deleted: true, id };
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"lib": [
|
|
6
|
+
"ES2020"
|
|
7
|
+
],
|
|
8
|
+
"outDir": "./dist",
|
|
9
|
+
"rootDir": "./src",
|
|
10
|
+
"strict": true,
|
|
11
|
+
"esModuleInterop": true,
|
|
12
|
+
"experimentalDecorators": true,
|
|
13
|
+
"emitDecoratorMetadata": true,
|
|
14
|
+
"skipLibCheck": true
|
|
15
|
+
},
|
|
16
|
+
"include": [
|
|
17
|
+
"src/**/*"
|
|
18
|
+
],
|
|
19
|
+
"exclude": [
|
|
20
|
+
"node_modules",
|
|
21
|
+
"dist"
|
|
22
|
+
]
|
|
23
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"server": {
|
|
3
|
+
"port": 3000,
|
|
4
|
+
"host": "0.0.0.0"
|
|
5
|
+
},
|
|
6
|
+
"database": {
|
|
7
|
+
"type": "sqlite",
|
|
8
|
+
"database": "database.sqlite",
|
|
9
|
+
"synchronize": true,
|
|
10
|
+
"logging": false,
|
|
11
|
+
"entities": [
|
|
12
|
+
"dist/**/*.entity.js"
|
|
13
|
+
],
|
|
14
|
+
"migrations": [
|
|
15
|
+
"dist/migrations/**/*.js"
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "blog-api",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "dist/main.js",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"start": "node dist/main.js",
|
|
7
|
+
"dev": "fragment serve",
|
|
8
|
+
"build": "fragment build",
|
|
9
|
+
"test": "fragment test"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"fragment": "^1.0.0",
|
|
13
|
+
"reflect-metadata": "^0.1.13"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"typescript": "^5.3.3",
|
|
17
|
+
"@types/node": "^20.10.5"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Controller, Post, Body } from 'fragment';
|
|
2
|
+
import { AuthService } from '../services/auth.service';
|
|
3
|
+
|
|
4
|
+
@Controller('/auth')
|
|
5
|
+
export class AuthController {
|
|
6
|
+
constructor(private authService: AuthService) {}
|
|
7
|
+
|
|
8
|
+
@Post('/login')
|
|
9
|
+
async login(@Body() body: any) {
|
|
10
|
+
return this.authService.login(body.email, body.password);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
@Post('/register')
|
|
14
|
+
async register(@Body() body: any) {
|
|
15
|
+
return this.authService.register(body);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Controller, Get, Post, Put, Delete, Body, Param } from 'fragment';
|
|
2
|
+
|
|
3
|
+
@Controller('/category')
|
|
4
|
+
export class CategoryController {
|
|
5
|
+
@Get()
|
|
6
|
+
findAll() {
|
|
7
|
+
return [];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
@Get('/:id')
|
|
11
|
+
findOne(@Param('id') id: string) {
|
|
12
|
+
return { id };
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
@Post()
|
|
16
|
+
create(@Body() body: any) {
|
|
17
|
+
return body;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@Put('/:id')
|
|
21
|
+
update(@Param('id') id: string, @Body() body: any) {
|
|
22
|
+
return { id, ...body };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@Delete('/:id')
|
|
26
|
+
delete(@Param('id') id: string) {
|
|
27
|
+
return { deleted: true, id };
|
|
28
|
+
}
|
|
29
|
+
}
|