fragment-ts 1.0.1 → 1.0.3

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.
Files changed (49) hide show
  1. package/README.md +9 -9
  2. package/dist/cli/commands/diagnostics.command.js +2 -2
  3. package/dist/cli/commands/generate.command.js +3 -3
  4. package/dist/cli/commands/generate.command.js.map +1 -1
  5. package/dist/cli/commands/init.command.js +7 -7
  6. package/examples/blog-api/fragment.json +3 -7
  7. package/examples/blog-api/package-lock.json +3405 -0
  8. package/examples/blog-api/package.json +1 -1
  9. package/examples/blog-api/src/controllers/app.controller.ts +1 -1
  10. package/examples/blog-api/src/controllers/auth.controller.ts +1 -1
  11. package/examples/blog-api/src/controllers/category.controller.ts +1 -1
  12. package/examples/blog-api/src/controllers/comment.controller.ts +13 -9
  13. package/examples/blog-api/src/controllers/post.controller.ts +1 -1
  14. package/examples/blog-api/src/main.ts +3 -3
  15. package/examples/blog-api/src/repositories/category.repository.ts +1 -1
  16. package/examples/blog-api/src/repositories/comment.repository.ts +1 -1
  17. package/examples/blog-api/src/repositories/post.repository.ts +1 -1
  18. package/examples/blog-api/src/seeds/SampleData.seed.ts +1 -1
  19. package/examples/blog-api/src/services/app.service.ts +1 -1
  20. package/examples/blog-api/src/services/auth.service.ts +2 -2
  21. package/examples/blog-api/src/services/category.service.ts +1 -1
  22. package/examples/blog-api/src/services/comment.service.ts +1 -1
  23. package/examples/blog-api/src/services/post.service.ts +1 -1
  24. package/package.json +7 -8
  25. package/src/cli/commands/diagnostics.command.ts +2 -2
  26. package/src/cli/commands/generate.command.ts +3 -3
  27. package/src/cli/commands/init.command.ts +7 -7
  28. package/examples/ai-assistant/fragment.json +0 -18
  29. package/examples/ai-assistant/package-lock.json +0 -2921
  30. package/examples/ai-assistant/package.json +0 -20
  31. package/examples/ai-assistant/src/controllers/app.controller.ts +0 -9
  32. package/examples/ai-assistant/src/controllers/chat.controller.ts +0 -69
  33. package/examples/ai-assistant/src/controllers/conversation.controller.ts +0 -29
  34. package/examples/ai-assistant/src/controllers/message.controller.ts +0 -29
  35. package/examples/ai-assistant/src/controllers/search.controller.ts +0 -16
  36. package/examples/ai-assistant/src/dto/create-conversation.dto.ts +0 -6
  37. package/examples/ai-assistant/src/dto/create-message.dto.ts +0 -6
  38. package/examples/ai-assistant/src/entities/conversation.entity.ts +0 -23
  39. package/examples/ai-assistant/src/entities/message.entity.ts +0 -27
  40. package/examples/ai-assistant/src/entities/user.entity.ts +0 -16
  41. package/examples/ai-assistant/src/main.ts +0 -15
  42. package/examples/ai-assistant/src/migrations/1767738396740-CreateConversationTables.ts +0 -37
  43. package/examples/ai-assistant/src/repositories/conversation.repository.ts +0 -32
  44. package/examples/ai-assistant/src/repositories/message.repository.ts +0 -30
  45. package/examples/ai-assistant/src/services/ai.service.ts +0 -41
  46. package/examples/ai-assistant/src/services/app.service.ts +0 -8
  47. package/examples/ai-assistant/src/services/conversation.service.ts +0 -75
  48. package/examples/ai-assistant/src/services/message.service.ts +0 -27
  49. package/examples/ai-assistant/tsconfig.json +0 -23
@@ -1,20 +0,0 @@
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
- }
@@ -1,9 +0,0 @@
1
- import { Controller, Get } from 'fragment';
2
-
3
- @Controller('/api')
4
- export class AppController {
5
- @Get('/health')
6
- health() {
7
- return { status: 'who dey help', timestamp: new Date().toISOString() };
8
- }
9
- }
@@ -1,69 +0,0 @@
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
- }
@@ -1,29 +0,0 @@
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
- }
@@ -1,29 +0,0 @@
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
- }
@@ -1,16 +0,0 @@
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
- }
@@ -1,6 +0,0 @@
1
- import { IsString } from 'class-validator';
2
-
3
- export class CreateConversationDto {
4
- @IsString()
5
- name!: string;
6
- }
@@ -1,6 +0,0 @@
1
- import { IsString } from 'class-validator';
2
-
3
- export class CreateMessageDto {
4
- @IsString()
5
- name!: string;
6
- }
@@ -1,23 +0,0 @@
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
- }
@@ -1,27 +0,0 @@
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
- }
@@ -1,16 +0,0 @@
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
- }
@@ -1,15 +0,0 @@
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();
@@ -1,37 +0,0 @@
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
- }
@@ -1,32 +0,0 @@
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
- }
@@ -1,30 +0,0 @@
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
- }
@@ -1,41 +0,0 @@
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
- }
@@ -1,8 +0,0 @@
1
- import { Service } from 'fragment';
2
-
3
- @Service()
4
- export class AppService {
5
- getMessage(): string {
6
- return 'Welcome to Fragment Framework!';
7
- }
8
- }
@@ -1,75 +0,0 @@
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
- }
@@ -1,27 +0,0 @@
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
- }
@@ -1,23 +0,0 @@
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
- }