@learnpack/learnpack 5.0.168 → 5.0.176
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 +13 -13
- package/lib/commands/serve.js +42 -2
- package/{src/creatorDist/assets/index-C_YTggyk.css → lib/creatorDist/assets/index-CrWESWmj.css} +43 -11
- package/lib/creatorDist/assets/index-T7usmMYO.js +32991 -0
- package/lib/creatorDist/index.html +2 -2
- package/lib/utils/api.d.ts +1 -1
- package/lib/utils/api.js +2 -1
- package/lib/utils/readDocuments.d.ts +0 -0
- package/lib/utils/readDocuments.js +1 -0
- package/oclif.manifest.json +1 -1
- package/package.json +3 -1
- package/src/commands/serve.ts +56 -2
- package/src/creator/src/App.tsx +51 -34
- package/src/creator/src/components/ConsumablesManager.tsx +1 -0
- package/src/creator/src/components/FileUploader.tsx +64 -52
- package/src/creator/src/components/Login.tsx +172 -82
- package/src/creator/src/components/ResumeCourseModal.tsx +38 -0
- package/src/creator/src/components/StepWizard.tsx +12 -10
- package/src/creator/src/components/TurnstileChallenge.tsx +2 -7
- package/src/creator/src/components/syllabus/ContentIndex.tsx +1 -0
- package/src/creator/src/components/syllabus/SyllabusEditor.tsx +63 -29
- package/src/creator/src/utils/constants.ts +2 -1
- package/src/creator/src/utils/lib.ts +55 -0
- package/src/creator/src/utils/rigo.ts +12 -5
- package/src/creator/src/utils/store.ts +22 -1
- package/{lib/creatorDist/assets/index-C_YTggyk.css → src/creatorDist/assets/index-CrWESWmj.css} +43 -11
- package/src/creatorDist/assets/index-T7usmMYO.js +32991 -0
- package/src/creatorDist/index.html +2 -2
- package/src/ui/_app/app.js +286 -286
- package/src/ui/app.tar.gz +0 -0
- package/src/utils/api.ts +2 -1
- package/src/utils/readDocuments.ts +0 -0
- package/lib/creatorDist/assets/index-4XkqESUr.js +0 -83719
- package/lib/creatorDist/assets/pdf.worker-DSVOJ9H9.js +0 -56037
- package/src/creatorDist/assets/index-4XkqESUr.js +0 -83719
- package/src/creatorDist/assets/pdf.worker-DSVOJ9H9.js +0 -56037
@@ -10,8 +10,8 @@
|
|
10
10
|
/>
|
11
11
|
|
12
12
|
<title>Learnpack Creator: Craft tutorials in seconds!</title>
|
13
|
-
<script type="module" crossorigin src="/creator/assets/index-
|
14
|
-
<link rel="stylesheet" crossorigin href="/creator/assets/index-
|
13
|
+
<script type="module" crossorigin src="/creator/assets/index-T7usmMYO.js"></script>
|
14
|
+
<link rel="stylesheet" crossorigin href="/creator/assets/index-CrWESWmj.css">
|
15
15
|
</head>
|
16
16
|
<body>
|
17
17
|
<div id="root"></div>
|
package/lib/utils/api.d.ts
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
export declare const RIGOBOT_HOST = "https://rigobot.herokuapp.com";
|
1
|
+
export declare const RIGOBOT_HOST = "https://rigobot-test-cca7d841c9d8.herokuapp.com";
|
2
2
|
type TConsumableSlug = "ai-conversation-message" | "ai-compilation" | "ai-tutorial-generation" | "ai-generation" | "learnpack-publish";
|
3
3
|
export declare const countConsumables: (consumables: any, consumableSlug?: TConsumableSlug) => any;
|
4
4
|
export declare const getConsumable: (token: string, consumableSlug?: TConsumableSlug) => Promise<any>;
|
package/lib/utils/api.js
CHANGED
@@ -6,7 +6,8 @@ const storage = require("node-persist");
|
|
6
6
|
const cli_ux_1 = require("cli-ux");
|
7
7
|
const axios_1 = require("axios");
|
8
8
|
const HOST = "https://breathecode.herokuapp.com";
|
9
|
-
|
9
|
+
// export const RIGOBOT_HOST = "https://rigobot.herokuapp.com"
|
10
|
+
exports.RIGOBOT_HOST = "https://rigobot-test-cca7d841c9d8.herokuapp.com";
|
10
11
|
// export const RIGOBOT_HOST =
|
11
12
|
// "https://8000-charlytoc-rigobot-bmwdeam7cev.ws-us118.gitpod.io"
|
12
13
|
// eslint-disable-next-line
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
"use strict";
|
package/oclif.manifest.json
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":"5.0.
|
1
|
+
{"version":"5.0.176","commands":{"audit":{"id":"audit","description":"learnpack audit is the command in charge of creating an auditory of the repository\n...\nlearnpack audit checks for the following information in a repository:\n 1. The configuration object has slug, repository and description. (Error)\n 2. The command learnpack clean has been run. (Error)\n 3. If a markdown or test file doesn't have any content. (Error)\n 4. The links are accessing to valid servers. (Error)\n 5. The relative images are working (If they have the shortest path to the image or if the images exists in the assets). (Error)\n 6. The external images are working (If they are pointing to a valid server). (Error)\n 7. The exercises directory names are valid. (Error)\n 8. If an exercise doesn't have a README file. (Error)\n 9. The exercises array (Of the config file) has content. (Error)\n 10. The exercses have the same translations. (Warning)\n 11. The .gitignore file exists. (Warning)\n 12. If there is a file within the exercises folder but not inside of any particular exercise's folder. (Warning)\n","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"strict":{"name":"strict","type":"boolean","char":"s","description":"strict mode","allowNo":false}},"args":[]},"breakToken":{"id":"breakToken","description":"Break the token","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"grading":{"name":"grading","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"clean":{"id":"clean","description":"Clean the configuration object\n ...\n Extra documentation goes here\n ","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[]},"download":{"id":"download","description":"Describe the command here\n...\nExtra documentation goes here\n","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"package","description":"The unique string that identifies this package on learnpack","required":false,"hidden":false}]},"init":{"id":"init","description":"Create a new learning package: Book, Tutorial or Exercise","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"grading":{"name":"grading","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"login":{"id":"login","description":"Describe the command here\n ...\n Extra documentation goes here\n ","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"package","description":"The unique string that identifies this package on learnpack","required":false,"hidden":false}]},"logout":{"id":"logout","description":"Describe the command here\n ...\n Extra documentation goes here\n ","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"package","description":"The unique string that identifies this package on learnpack","required":false,"hidden":false}]},"publish":{"id":"publish","description":"Builds the project by copying necessary files and directories into a zip file","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"strict":{"name":"strict","type":"boolean","char":"s","description":"strict mode","allowNo":false},"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"serve":{"id":"serve","description":"Runs a small server to build tutorials","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"port":{"name":"port","type":"option","char":"p","description":"server port"},"host":{"name":"host","type":"option","char":"h","description":"server host"},"debug":{"name":"debug","type":"boolean","char":"d","description":"debugger mode for more verbage","allowNo":false}},"args":[]},"start":{"id":"start","description":"Runs a small server with all the exercise instructions","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"port":{"name":"port","type":"option","char":"p","description":"server port"},"host":{"name":"host","type":"option","char":"h","description":"server host"},"disableGrading":{"name":"disableGrading","type":"boolean","char":"D","description":"disble grading functionality","allowNo":false},"watch":{"name":"watch","type":"boolean","char":"w","description":"Watch for file changes","allowNo":false},"editor":{"name":"editor","type":"option","char":"e","description":"[preview, extension]","options":["extension","preview"]},"version":{"name":"version","type":"option","char":"v","description":"E.g: 1.0.1"},"grading":{"name":"grading","type":"option","char":"g","description":"[isolated, incremental]","options":["isolated","incremental"]},"debug":{"name":"debug","type":"boolean","char":"d","description":"debugger mode for more verbage","allowNo":false}},"args":[]},"test":{"id":"test","description":"Test exercises","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false}},"args":[{"name":"exerciseSlug","description":"The name of the exercise to test","required":false,"hidden":false}]},"translate":{"id":"translate","description":"List all the lessons, the user is able of select many of them to translate to the given languages","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false}},"args":[]}}}
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "@learnpack/learnpack",
|
3
3
|
"description": "Seamlessly build, sell and/or take interactive & auto-graded tutorials, start learning now or build a new tutorial to your audience.",
|
4
|
-
"version": "5.0.
|
4
|
+
"version": "5.0.176",
|
5
5
|
"author": "Alejandro Sanchez @alesanchezr",
|
6
6
|
"contributors": [
|
7
7
|
{
|
@@ -44,10 +44,12 @@
|
|
44
44
|
"espree": "^9.3.2",
|
45
45
|
"eta": "^1.2.0",
|
46
46
|
"express": "^4.17.1",
|
47
|
+
"file-type": "^21.0.0",
|
47
48
|
"form-data": "^4.0.2",
|
48
49
|
"front-matter": "^4.0.2",
|
49
50
|
"html-to-text": "^9.0.5",
|
50
51
|
"js-yaml": "^4.1.0",
|
52
|
+
"jszip": "^3.10.1",
|
51
53
|
"markdown-it": "^14.1.0",
|
52
54
|
"mkdirp": "^3.0.1",
|
53
55
|
"moment": "^2.27.0",
|
package/src/commands/serve.ts
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import { flags } from "@oclif/command"
|
2
|
-
|
3
|
-
// import
|
2
|
+
|
3
|
+
// import { readDocument } from "../utils/readDocuments"
|
4
4
|
import { YoutubeTranscript } from "youtube-transcript"
|
5
5
|
import * as express from "express"
|
6
6
|
import * as cors from "cors"
|
@@ -535,6 +535,60 @@ export default class ServeCommand extends SessionCommand {
|
|
535
535
|
}
|
536
536
|
)
|
537
537
|
|
538
|
+
app.post("/read-document", upload.single("file"), async (req, res) => {
|
539
|
+
console.log("READING A DOCUMENT")
|
540
|
+
// const rigoToken = req.header("x-rigo-token")
|
541
|
+
// if (!rigoToken) {
|
542
|
+
// return res.status(400).json({ error: "Rigo token is required" })
|
543
|
+
// }
|
544
|
+
|
545
|
+
try {
|
546
|
+
// eslint-disable-next-line
|
547
|
+
// @ts-ignore
|
548
|
+
if (!req.file) {
|
549
|
+
return res.status(400).json({ error: "Missing file" })
|
550
|
+
}
|
551
|
+
|
552
|
+
const resultId = `${Date.now()}-${Math.floor(Math.random() * 1e6)}`
|
553
|
+
|
554
|
+
const webhookUrl = `https://9cw5zmww-3000.use2.devtunnels.ms/document/results/result_id/${resultId}/`
|
555
|
+
|
556
|
+
// Construir form-data para enviar al servidor proxy
|
557
|
+
const formData = new FormData()
|
558
|
+
// eslint-disable-next-line
|
559
|
+
// @ts-ignore
|
560
|
+
formData.append("file", req.file.buffer, {
|
561
|
+
// eslint-disable-next-line
|
562
|
+
// @ts-ignore
|
563
|
+
filename: req.file.originalname,
|
564
|
+
// eslint-disable-next-line
|
565
|
+
// @ts-ignore
|
566
|
+
contentType: req.file.mimetype,
|
567
|
+
})
|
568
|
+
formData.append("webhook_callback_url", webhookUrl)
|
569
|
+
|
570
|
+
// Hacer POST al servidor externo
|
571
|
+
const response = await axios.post(
|
572
|
+
`${RIGOBOT_HOST}/v1/learnpack/documents/pdf/read`,
|
573
|
+
formData,
|
574
|
+
{
|
575
|
+
headers: {
|
576
|
+
...formData.getHeaders(),
|
577
|
+
Authorization: `Token `,
|
578
|
+
},
|
579
|
+
maxBodyLength: Infinity,
|
580
|
+
}
|
581
|
+
)
|
582
|
+
console.log("RESPONSE FROM RIGOBOT", response)
|
583
|
+
|
584
|
+
// Responder con el UUID generado
|
585
|
+
return res.json({ resultId })
|
586
|
+
} catch (error) {
|
587
|
+
console.error("❌ Error in /read-document:", error)
|
588
|
+
return res.status(500).json({ error: (error as Error).message })
|
589
|
+
}
|
590
|
+
})
|
591
|
+
|
538
592
|
app.get("/check-preview-image/:slug", async (req, res) => {
|
539
593
|
const { slug } = req.params
|
540
594
|
const file = bucket.file(`courses/${slug}/preview.png`)
|
package/src/creator/src/App.tsx
CHANGED
@@ -6,7 +6,7 @@ import { useNavigate } from "react-router"
|
|
6
6
|
import { useShallow } from "zustand/react/shallow"
|
7
7
|
import useStore from "./utils/store"
|
8
8
|
|
9
|
-
import {
|
9
|
+
import { publicInteractiveCreation, isHuman } from "./utils/rigo"
|
10
10
|
import { checkParams, loginWithToken, parseLesson } from "./utils/lib"
|
11
11
|
|
12
12
|
import { Uploader } from "./components/Uploader"
|
@@ -15,6 +15,7 @@ import { ParamsChecker } from "./components/ParamsChecker"
|
|
15
15
|
import { RIGO_FLOAT_GIT } from "./utils/constants"
|
16
16
|
import TurnstileChallenge from "./components/TurnstileChallenge"
|
17
17
|
// import TurnstileChallenge from "./components/TurnstileChallenge"
|
18
|
+
import ResumeCourseModal from "./components/ResumeCourseModal"
|
18
19
|
|
19
20
|
function App() {
|
20
21
|
const navigate = useNavigate()
|
@@ -26,16 +27,22 @@ function App() {
|
|
26
27
|
push,
|
27
28
|
cleanHistory,
|
28
29
|
setPlanToRedirect,
|
30
|
+
history,
|
29
31
|
uploadedFiles,
|
32
|
+
auth,
|
33
|
+
resetFormState,
|
30
34
|
} = useStore(
|
31
35
|
useShallow((state) => ({
|
32
36
|
formState: state.formState,
|
33
37
|
setFormState: state.setFormState,
|
34
38
|
setAuth: state.setAuth,
|
35
39
|
push: state.push,
|
40
|
+
history: state.history,
|
36
41
|
cleanHistory: state.cleanHistory,
|
37
42
|
setPlanToRedirect: state.setPlanToRedirect,
|
38
43
|
uploadedFiles: state.uploadedFiles,
|
44
|
+
auth: state.auth,
|
45
|
+
resetFormState: state.resetFormState,
|
39
46
|
}))
|
40
47
|
)
|
41
48
|
|
@@ -59,6 +66,7 @@ function App() {
|
|
59
66
|
userId: user.id,
|
60
67
|
rigoToken: user.rigobot.key,
|
61
68
|
user: user,
|
69
|
+
publicToken: "",
|
62
70
|
})
|
63
71
|
}
|
64
72
|
}
|
@@ -100,8 +108,9 @@ function App() {
|
|
100
108
|
try {
|
101
109
|
cleanHistory()
|
102
110
|
|
103
|
-
const res = await
|
104
|
-
|
111
|
+
const res = await publicInteractiveCreation(
|
112
|
+
{
|
113
|
+
courseInfo: `${JSON.stringify(formState)}
|
105
114
|
${
|
106
115
|
uploadedFiles.length > 0
|
107
116
|
? `These files where uploaded by the user: \n\n${JSON.stringify(
|
@@ -109,8 +118,10 @@ ${
|
|
109
118
|
)}`
|
110
119
|
: ""
|
111
120
|
}`,
|
112
|
-
|
113
|
-
|
121
|
+
prevInteractions: "",
|
122
|
+
},
|
123
|
+
auth.publicToken
|
124
|
+
)
|
114
125
|
const lessons = res.parsed.listOfSteps.map((lesson: any) => {
|
115
126
|
return parseLesson(lesson, [])
|
116
127
|
})
|
@@ -126,22 +137,11 @@ ${
|
|
126
137
|
})
|
127
138
|
navigate("/creator/syllabus")
|
128
139
|
setFormState({
|
129
|
-
description: "",
|
130
|
-
duration: 0,
|
131
|
-
targetAudience: "",
|
132
|
-
hasContentIndex: false,
|
133
|
-
contentIndex: "",
|
134
140
|
isCompleted: false,
|
135
141
|
currentStep: "description",
|
136
|
-
variables: [
|
137
|
-
"description",
|
138
|
-
"duration",
|
139
|
-
"hasContentIndex",
|
140
|
-
"verifyHuman",
|
141
|
-
],
|
142
142
|
})
|
143
143
|
} catch (error) {
|
144
|
-
console.error(error)
|
144
|
+
console.error(error, "ERROR CREATING TUTORIAL")
|
145
145
|
toast.error("Something went wrong. Please try again.")
|
146
146
|
setFormState({
|
147
147
|
isCompleted: false,
|
@@ -279,14 +279,19 @@ ${
|
|
279
279
|
isCompleted: false,
|
280
280
|
content: (
|
281
281
|
<TurnstileChallenge
|
282
|
-
siteKey={"
|
282
|
+
siteKey={"0x4AAAAAABeKMBYYinMU4Ib0"}
|
283
283
|
onSuccess={async (token) => {
|
284
|
-
const
|
285
|
-
if (
|
284
|
+
const { human, message, token: jwtToken } = await isHuman(token)
|
285
|
+
if (human) {
|
286
286
|
toast.success("You are a human! 👌🏻")
|
287
|
+
|
288
|
+
setAuth({
|
289
|
+
...auth,
|
290
|
+
publicToken: jwtToken,
|
291
|
+
})
|
287
292
|
setFormState({ isCompleted: true })
|
288
293
|
} else {
|
289
|
-
toast.error(
|
294
|
+
toast.error(message)
|
290
295
|
setFormState({
|
291
296
|
currentStep: "hasContentIndex",
|
292
297
|
})
|
@@ -297,8 +302,6 @@ ${
|
|
297
302
|
},
|
298
303
|
]
|
299
304
|
|
300
|
-
console.log(formState.variables, "FORM STATE VAIRABLEs")
|
301
|
-
|
302
305
|
return steps.filter(
|
303
306
|
(step) =>
|
304
307
|
formState.variables.includes(step.slug) ||
|
@@ -309,22 +312,36 @@ ${
|
|
309
312
|
return (
|
310
313
|
<>
|
311
314
|
<ParamsChecker />
|
312
|
-
{formState.isCompleted ? (
|
315
|
+
{formState.isCompleted && history.length === 0 ? (
|
313
316
|
<Loader
|
314
317
|
text="Learnpack is setting up your tutorial. It may take a moment..."
|
315
318
|
icon={<img src={RIGO_FLOAT_GIT} alt="rigo" className="w-20 h-20" />}
|
316
319
|
/>
|
317
320
|
) : (
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
321
|
+
<>
|
322
|
+
{history.length > 0 && (
|
323
|
+
<ResumeCourseModal
|
324
|
+
onContinue={() => {
|
325
|
+
navigate("/creator/syllabus")
|
326
|
+
}}
|
327
|
+
onStartOver={() => {
|
328
|
+
resetFormState()
|
329
|
+
cleanHistory()
|
330
|
+
}}
|
331
|
+
/>
|
332
|
+
)}
|
333
|
+
<StepWizard
|
334
|
+
hideLastButton={true}
|
335
|
+
formState={formState}
|
336
|
+
steps={buildSteps()}
|
337
|
+
setFormState={setFormState}
|
338
|
+
onFinish={() => {
|
339
|
+
setFormState({
|
340
|
+
isCompleted: true,
|
341
|
+
})
|
342
|
+
}}
|
343
|
+
/>
|
344
|
+
</>
|
328
345
|
)}
|
329
346
|
</>
|
330
347
|
)
|
@@ -1,12 +1,8 @@
|
|
1
1
|
import React, { useRef, useState } from "react"
|
2
|
-
import * as pdfjsLib from "pdfjs-dist"
|
3
|
-
import mammoth from "mammoth"
|
4
2
|
import { SVGS } from "../assets/svgs"
|
5
|
-
import pdfWorker from "pdfjs-dist/build/pdf.worker?worker"
|
6
3
|
import { ContentCard } from "./ContentCard"
|
7
4
|
import useStore from "../utils/store"
|
8
|
-
|
9
|
-
pdfjsLib.GlobalWorkerOptions.workerPort = new pdfWorker()
|
5
|
+
import toast from "react-hot-toast"
|
10
6
|
|
11
7
|
const allowedTypes = [
|
12
8
|
"application/pdf",
|
@@ -21,53 +17,64 @@ export interface ParsedFile {
|
|
21
17
|
}
|
22
18
|
|
23
19
|
interface FileUploaderProps {
|
24
|
-
// onResult: (files: ParsedFile[]) => void
|
25
20
|
styledAs?: "button" | "card"
|
26
21
|
}
|
27
22
|
|
28
23
|
const FileUploader: React.FC<FileUploaderProps> = ({ styledAs = "button" }) => {
|
24
|
+
const rigoToken = useStore((state) => state.auth.rigoToken)
|
29
25
|
const inputRef = useRef<HTMLInputElement>(null)
|
30
26
|
const uploadedFiles = useStore((state) => state.uploadedFiles)
|
31
27
|
const setUploadedFiles = useStore((state) => state.setUploadedFiles)
|
32
28
|
const [isDragging, setIsDragging] = useState(false)
|
33
|
-
|
29
|
+
const [isLoading, setIsLoading] = useState(false)
|
34
30
|
|
35
|
-
const
|
31
|
+
const extractTextFromFile = async (file: File): Promise<ParsedFile> => {
|
36
32
|
const { type, name } = file
|
37
33
|
|
38
|
-
if (type === "
|
39
|
-
const
|
40
|
-
const pdf = await pdfjsLib.getDocument({ data: arrayBuffer }).promise
|
41
|
-
let text = ""
|
42
|
-
|
43
|
-
for (let i = 0; i < pdf.numPages; i++) {
|
44
|
-
const page = await pdf.getPage(i + 1)
|
45
|
-
const content = await page.getTextContent()
|
46
|
-
text += content.items.map((item: any) => item.str).join(" ") + "\n"
|
47
|
-
}
|
48
|
-
|
34
|
+
if (type === "text/plain" || type === "text/markdown") {
|
35
|
+
const text = await file.text()
|
49
36
|
return { name, text }
|
50
37
|
}
|
51
38
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
const
|
58
|
-
|
39
|
+
const formData = new FormData()
|
40
|
+
formData.append("file", file)
|
41
|
+
|
42
|
+
const loadingToast = toast.loading(`Processing ${file.name}...`)
|
43
|
+
try {
|
44
|
+
const res = await fetch("http://localhost:3000/read-document", {
|
45
|
+
method: "POST",
|
46
|
+
headers: {
|
47
|
+
"x-rigo-token": rigoToken,
|
48
|
+
},
|
49
|
+
body: formData,
|
50
|
+
})
|
51
|
+
|
52
|
+
if (!res.ok) throw new Error(`Failed to read ${file.name}`)
|
53
|
+
const data = await res.json()
|
54
|
+
console.log("DATA FROM BACKEND", data)
|
55
|
+
toast.success(`✅ ${file.name} processed`, { id: loadingToast })
|
56
|
+
return { name, text: data.content }
|
57
|
+
} catch (err: any) {
|
58
|
+
toast.error(`❌ ${file.name} failed: ${err.message}`, {
|
59
|
+
id: loadingToast,
|
60
|
+
})
|
61
|
+
return { name, text: "" }
|
59
62
|
}
|
60
|
-
|
61
|
-
const text = await file.text()
|
62
|
-
return { name, text }
|
63
63
|
}
|
64
64
|
|
65
65
|
const parseFiles = async (files: FileList | File[]) => {
|
66
66
|
const validFiles = Array.from(files).filter((file) =>
|
67
67
|
allowedTypes.includes(file.type)
|
68
68
|
)
|
69
|
-
|
69
|
+
if (validFiles.length === 0) {
|
70
|
+
toast.error("No valid files selected")
|
71
|
+
return
|
72
|
+
}
|
73
|
+
|
74
|
+
setIsLoading(true)
|
75
|
+
const parsed = await Promise.all(validFiles.map(extractTextFromFile))
|
70
76
|
setUploadedFiles([...uploadedFiles, ...parsed])
|
77
|
+
setIsLoading(false)
|
71
78
|
}
|
72
79
|
|
73
80
|
const handleInput = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
@@ -86,16 +93,16 @@ const FileUploader: React.FC<FileUploaderProps> = ({ styledAs = "button" }) => {
|
|
86
93
|
return (
|
87
94
|
<div className="flex flex-col gap-2 w-full">
|
88
95
|
{uploadedFiles.length > 0 && styledAs === "card" && (
|
89
|
-
<div className="w-full flex flex-row gap-2 flex-wrap justify-center items-center
|
96
|
+
<div className="w-full flex flex-row gap-2 flex-wrap justify-center items-center">
|
90
97
|
{uploadedFiles.map((file, idx) => (
|
91
98
|
<div
|
92
99
|
key={idx}
|
93
|
-
className="p-3 rounded-md bg-white shadow-sm text-sm text-gray-800 text-left
|
100
|
+
className="p-3 rounded-md bg-white shadow-sm text-sm text-gray-800 text-left"
|
94
101
|
title={file.name}
|
95
102
|
>
|
96
103
|
<strong>{file.name.slice(0, 20)}...</strong>
|
97
104
|
<button
|
98
|
-
className="text-gray-600 mt-1 float-right
|
105
|
+
className="text-gray-600 mt-1 float-right cursor-pointer"
|
99
106
|
onClick={() =>
|
100
107
|
setUploadedFiles(uploadedFiles.filter((_, i) => i !== idx))
|
101
108
|
}
|
@@ -106,6 +113,7 @@ const FileUploader: React.FC<FileUploaderProps> = ({ styledAs = "button" }) => {
|
|
106
113
|
))}
|
107
114
|
</div>
|
108
115
|
)}
|
116
|
+
|
109
117
|
{styledAs === "button" && (
|
110
118
|
<div className="flex items-center justify-end gap-2 w-100">
|
111
119
|
<button
|
@@ -113,30 +121,34 @@ const FileUploader: React.FC<FileUploaderProps> = ({ styledAs = "button" }) => {
|
|
113
121
|
className="cursor-pointer blue-on-hover flex items-center justify-center w-6 h-6"
|
114
122
|
onClick={() => inputRef.current?.click()}
|
115
123
|
>
|
116
|
-
{
|
124
|
+
{isLoading ? (
|
125
|
+
<div className="loader w-4 h-4 border-2 border-blue-500 border-t-transparent rounded-full animate-spin" />
|
126
|
+
) : (
|
127
|
+
SVGS.clip
|
128
|
+
)}
|
117
129
|
</button>
|
118
130
|
</div>
|
119
131
|
)}
|
120
132
|
|
121
133
|
{styledAs === "card" && (
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
134
|
+
<ContentCard
|
135
|
+
description={
|
136
|
+
isDragging
|
137
|
+
? "Drop it here"
|
138
|
+
: isLoading
|
139
|
+
? "Processing..."
|
140
|
+
: "Upload a PDF or DOCX file or drag it here"
|
141
|
+
}
|
142
|
+
icon={isDragging ? SVGS.clip : SVGS.pdf}
|
143
|
+
onClick={() => inputRef.current?.click()}
|
144
|
+
onDragOver={(e) => {
|
145
|
+
e.preventDefault()
|
146
|
+
setIsDragging(true)
|
147
|
+
}}
|
148
|
+
onDragLeave={() => setIsDragging(false)}
|
149
|
+
onDrop={handleDrop}
|
150
|
+
className={isDragging ? "border-blue-600 bg-blue-50" : ""}
|
151
|
+
/>
|
140
152
|
)}
|
141
153
|
|
142
154
|
<input
|