Skip to content

Commit 07bed27

Browse files
committed
Update configurations and dependencies for webapp and API components
1 parent 0a09bcc commit 07bed27

25 files changed

+729
-129
lines changed

Diff for: apps/api/package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@
88
"migrations:apply:prod": "wrangler d1 migrations apply interviews_db --remote"
99
},
1010
"dependencies": {
11+
"@cloudflare/ai": "1.1.0",
1112
"@hono/swagger-ui": "^0.2.1",
1213
"@hono/zod-openapi": "^0.11.0",
1314
"@langchain/cloudflare": "^0.0.4",
1415
"drizzle-orm": "^0.30.8",
1516
"hono": "4.2.4",
16-
"langchain": "^0.1.33"
17+
"langchain": "^0.1.33",
18+
"openai": "^4.33.1"
1719
},
1820
"devDependencies": {
1921
"@cloudflare/workers-types": "4.20240405.0",

Diff for: apps/api/src/bindings.ts

+3
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,8 @@ export type Bindings = {
22
DB: D1Database;
33
CLOUDFLARE_ACCOUNT_ID: string;
44
CLOUDFLARE_API_TOKEN: string;
5+
OPENAI_API_KEY: string;
56
AI: any;
7+
BUCKET: R2Bucket;
8+
R2_URL: string;
69
}

Diff for: apps/api/src/dtos/feedback.dto.ts

+14-10
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
import { z } from '@hono/zod-openapi';
22

3-
export const FeedbackSchema = z
4-
.object({
5-
id: z.string().openapi({
6-
example: '1',
3+
export const GenerateFeedbackSchema = z.object({
4+
answer: z
5+
.string()
6+
.min(3)
7+
.openapi({
8+
example: 'Message',
79
}),
8-
from: z.string().openapi({
9-
example: 'user',
10+
question: z
11+
.string()
12+
.min(3)
13+
.openapi({
14+
example: 'Message',
1015
}),
11-
text: z.string().openapi({
12-
example: 'message',
16+
simulationId: z.string().openapi({
17+
example: '1',
1318
}),
14-
})
15-
.openapi('Feedback');
19+
});

Diff for: apps/api/src/dtos/message.dto.ts

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export const MessageSchema = z
2626
type: z.string().openapi({
2727
example: 'feedback',
2828
}),
29+
file: z.any().optional()
2930
})
3031
.openapi('Message');
3132

Diff for: apps/api/src/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { dbMiddleware } from '@src/middlewares/db.middleware';
88
import createSimulation from '@src/routes/createSimulation';
99
import createQuestion from '@src/routes/createQuestion';
1010
import createFeedback from '@src/routes/createFeedback';
11+
import createTranscript from '@src/routes/createTranscript';
1112

1213
const app = new OpenAPIHono();
1314
app.use("*", cors());
@@ -19,6 +20,7 @@ app.use('/api/v1/*', dbMiddleware);
1920
app.route('/api/v1/simulations', createSimulation);
2021
app.route('/api/v1/questions', createQuestion);
2122
app.route('/api/v1/feedback', createFeedback);
23+
app.route('/api/v1/transcript', createTranscript);
2224

2325
app.get("/", swaggerUI({ url: "/docs" }));
2426
app.doc("/docs", {

Diff for: apps/api/src/routes/createFeedback.ts

+21-26
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,45 @@
11
import { OpenAPIHono, createRoute } from "@hono/zod-openapi";
2-
import { MessageListSchema } from '@src/dtos/message.dto';
3-
import { generateTranscription } from '@src/services/whisper.service';
2+
import { MessageSchema } from '@src/dtos/message.dto';
3+
import { GenerateFeedbackSchema } from '@src/dtos/feedback.dto';
44
import { generateFeedback } from '@src/services/llm.service';
55
import { App } from "@src/types";
66
import { HTTPException } from "hono/http-exception";
77
import { getSimulationById } from '@src/services/simulation.service';
8+
import { generateAudio } from '@src/services/openai.service';
89

910
const app = new OpenAPIHono<App>();
1011

1112
const route = createRoute({
1213
tags: ['simulation'],
1314
method: 'post',
1415
path: '/',
16+
request: {
17+
body: {
18+
content: {
19+
'application/json': {
20+
schema: GenerateFeedbackSchema,
21+
},
22+
},
23+
},
24+
},
1525
responses: {
1626
200: {
1727
content: {
1828
'application/json': {
19-
schema: MessageListSchema,
29+
schema: MessageSchema,
2030
},
2131
},
22-
description: 'Retrieve new simulation',
32+
description: 'Retrieve new feedback',
2333
},
2434
},
2535
public: true,
2636
});
2737

2838
app.openapi(route, async (c) => {
2939
const db = c.get('db');
30-
const body = await c.req.parseBody();
31-
const file = body.file as File;
32-
const question = body.question as string;
33-
const simulationId = body.simulationId as string;
40+
const { question, answer, simulationId } = c.req.valid('json');
3441
const entity = await getSimulationById(db, +simulationId);
3542

36-
const answer = await generateTranscription(file, c.env.AI);
3743
const response = await generateFeedback({
3844
role: entity.role,
3945
question,
@@ -47,23 +53,12 @@ app.openapi(route, async (c) => {
4753
throw new HTTPException(500, { message: `Complex messsage` })
4854
}
4955

50-
const messages = [
51-
{
52-
id: `${Date.now()}`,
53-
from: 'user',
54-
text: answer,
55-
type: 'response',
56-
},
57-
{
58-
id: `${Date.now() + 1}`,
59-
from: 'bot',
60-
text: content,
61-
type: 'feedback',
62-
},
63-
64-
];
65-
66-
return c.json(messages);
56+
return c.json({
57+
id: `${Date.now() + 1}`,
58+
from: 'bot',
59+
text: content,
60+
type: 'feedback'
61+
},);
6762
});
6863

6964
export default app;

Diff for: apps/api/src/routes/createQuestion.ts

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { OpenAPIHono, createRoute } from "@hono/zod-openapi";
22
import { MessageSchema, NewMessageSchema } from '@src/dtos/message.dto';
33
import { getSimulationById } from '@src/services/simulation.service';
44
import { generateQuestion } from '@src/services/llm.service';
5+
import { generateAudio } from '@src/services/openai.service';
56
import { App } from "@src/types";
67

78
const app = new OpenAPIHono<App>();
@@ -44,11 +45,14 @@ app.openapi(route, async (c) => {
4445
cloudflareApiToken: c.env.CLOUDFLARE_API_TOKEN,
4546
}, c.env.DB);
4647

48+
const filename = await generateAudio(response, c.env.OPENAI_API_KEY, c.env.BUCKET);
49+
4750
return c.json({
4851
id: `${Date.now()}`,
4952
from: 'bot',
5053
text: response,
5154
type: 'response',
55+
audio: `${c.env.R2_URL}/${filename}`,
5256
});
5357
});
5458

Diff for: apps/api/src/routes/createTranscript.ts

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { OpenAPIHono, createRoute } from "@hono/zod-openapi";
2+
import { MessageSchema } from '@src/dtos/message.dto';
3+
import { generateTranscription } from '@src/services/whisper.service';
4+
import { App } from "@src/types";
5+
6+
const app = new OpenAPIHono<App>();
7+
8+
const route = createRoute({
9+
tags: ['simulation'],
10+
method: 'post',
11+
path: '/',
12+
responses: {
13+
200: {
14+
content: {
15+
'application/json': {
16+
schema: MessageSchema,
17+
},
18+
},
19+
description: 'Retrieve new simulation',
20+
},
21+
},
22+
public: true,
23+
});
24+
25+
app.openapi(route, async (c) => {
26+
const body = await c.req.parseBody();
27+
const file = body.file as File;
28+
const answer = await generateTranscription(file, c.env.AI);
29+
30+
return c.json({
31+
id: `${Date.now()}`,
32+
from: 'user',
33+
text: answer,
34+
type: 'transcription'
35+
},);
36+
});
37+
38+
export default app;

Diff for: apps/api/src/services/openai.service.ts

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import OpenAI from "openai";
2+
3+
export const generateTranscription = async (file: File, key: string) => {
4+
const openai = new OpenAI({
5+
apiKey: key,
6+
});
7+
console.log('name', file.name);
8+
console.log('type', file.type);
9+
const transcription = await openai.audio.transcriptions.create({
10+
file: file,
11+
model: "whisper-1",
12+
});
13+
14+
return transcription.text;
15+
}
16+
17+
export const generateAudio = async (input: string, key: string, bucket: R2Bucket) => {
18+
const openai = new OpenAI({
19+
apiKey: key,
20+
});
21+
const file = await openai.audio.speech.create({
22+
model: "tts-1",
23+
voice: "alloy",
24+
input,
25+
});
26+
const blob = await file.blob();
27+
const fileName = `audios/${Date.now()}.mp3`;
28+
await bucket.put(fileName, blob);
29+
return fileName;
30+
}

Diff for: apps/api/src/services/whisper.service.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import { Ai } from '@cloudflare/ai';
22
import { HTTPException } from 'hono/http-exception';
33

44
export const generateTranscription = async (file: File, binding: any) => {
5-
5+
console.log('name', file.name);
6+
console.log('type', file.type);
67
const blob = await file.arrayBuffer();
78
const input = {
89
audio: [...new Uint8Array(blob)],
@@ -18,3 +19,4 @@ export const generateTranscription = async (file: File, binding: any) => {
1819

1920
return response.text;
2021
}
22+

Diff for: apps/api/wrangler.toml

+5
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,8 @@ database_id = "ca1cba03-9281-4bab-ac79-0ae16b39b88a"
99

1010
[ai]
1111
binding = "AI"
12+
13+
[[r2_buckets]]
14+
binding = "BUCKET"
15+
bucket_name = "files"
16+
preview_bucket_name = "preview-files"

Diff for: apps/webapp/angular.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@
5151
"src/assets"
5252
],
5353
"styles": [
54-
"src/styles.scss"
54+
"src/styles.scss",
55+
"node_modules/ngx-toastr/toastr.css"
5556
],
5657
"scripts": []
5758
},

0 commit comments

Comments
 (0)