lucas-wa commited on
Commit
d1cad4b
1 Parent(s): 6558cd8

Adding build options

Browse files
.dockerignore CHANGED
@@ -28,8 +28,8 @@ yarn-debug.log*
28
  yarn-error.log*
29
 
30
  # local env files
31
- .env
32
- .env*.local
33
 
34
  # vercel
35
  .vercel
 
28
  yarn-error.log*
29
 
30
  # local env files
31
+ *.env
32
+ *.env*.local
33
 
34
  # vercel
35
  .vercel
Dockerfile CHANGED
@@ -6,7 +6,7 @@ RUN apt-get install -y python3 pip
6
 
7
  WORKDIR /code
8
 
9
- COPY server/* /code/server/
10
 
11
  RUN pip install --no-cache-dir --upgrade -r /code/server/requirements.txt --break-system-packages
12
 
 
6
 
7
  WORKDIR /code
8
 
9
+ COPY server/ /code/server/
10
 
11
  RUN pip install --no-cache-dir --upgrade -r /code/server/requirements.txt --break-system-packages
12
 
server/app.py CHANGED
@@ -1,6 +1,38 @@
 
 
1
  from inference import rag_chain
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
- assunto = "Bioquimica e Biofisica"
4
- query = f"Quero que você gere questões de biologia, sendo do assunto: {assunto}."
5
- res = rag_chain.invoke(f"""{query}""")
6
- print(res)
 
1
+ from fastapi import FastAPI
2
+ from fastapi.middleware.cors import CORSMiddleware
3
  from inference import rag_chain
4
+ from pydantic import BaseModel
5
+ from fastapi.staticfiles import StaticFiles
6
+
7
+ class Body(BaseModel):
8
+ subject: str
9
+
10
+
11
+ app = FastAPI()
12
+
13
+ app.add_middleware(
14
+ CORSMiddleware,
15
+ allow_origins=["*"],
16
+ allow_methods=["*"],
17
+ allow_headers=["*"],
18
+ )
19
+
20
+ @app.post("/generate_questions")
21
+ async def generate_questions(body: Body):
22
+ subject = body.subject
23
+ query = f"Quero que você gere questões de biologia, sendo do assunto: {subject}."
24
+ res = rag_chain.invoke(f"""{query}""")
25
+ return res
26
+
27
+ app.mount("/", StaticFiles(directory="static", html=True), name="static")
28
+
29
+ if __name__ == "__main__":
30
+ import uvicorn
31
+ uvicorn.run("app:app", host="0.0.0.0", port=8000)
32
+
33
+
34
+
35
+
36
+
37
+
38
 
 
 
 
 
server/data/load_data.py CHANGED
@@ -6,33 +6,44 @@ from langchain.retrievers.self_query.base import SelfQueryRetriever
6
  from llm.gemini import gemini_embeddings, llm
7
  from utils.questions_parser import parse_question
8
 
9
- if "DATA_PATH" not in os.environ:
10
- raise ValueError("DATA_PATH environment variable is not set")
11
 
12
- DATA_PATH = os.environ["DATA_PATH"]
 
 
13
 
14
- data_loader = TextLoader(DATA_PATH, encoding = 'UTF-8').load()
15
 
16
- questions = list(
17
- map(lambda x: "##Questão" + x, data_loader[0].page_content.split("##Questão"))
18
- )
19
 
20
- docs = []
 
21
 
22
- for question in questions:
23
- try:
24
- docs.append(parse_question(question))
25
- except Exception as e:
26
- print(e, question)
27
 
28
- db = Chroma.from_documents(docs, gemini_embeddings)
29
- vectorstore = Chroma.from_documents(
30
- documents=docs, embedding=gemini_embeddings, persist_directory="./chroma_db"
31
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
 
33
- vectorstore_disk = Chroma(
34
- persist_directory="./chroma_db", embedding_function=gemini_embeddings
35
- )
36
  metadata_field_info = [
37
  AttributeInfo(
38
  name="topico",
 
6
  from llm.gemini import gemini_embeddings, llm
7
  from utils.questions_parser import parse_question
8
 
9
+ try:
 
10
 
11
+ vectorstore = Chroma(
12
+ persist_directory="./chroma_db", embedding_function=gemini_embeddings
13
+ )
14
 
15
+ except Exception as e:
16
 
17
+ print(e)
 
 
18
 
19
+ if "DATA_PATH" not in os.environ:
20
+ raise ValueError("DATA_PATH environment variable is not set")
21
 
22
+ DATA_PATH = os.environ["DATA_PATH"]
 
 
 
 
23
 
24
+ data_loader = TextLoader(DATA_PATH, encoding="UTF-8").load()
25
+
26
+ questions = list(
27
+ map(lambda x: "##Questão" + x, data_loader[0].page_content.split("##Questão"))
28
+ )
29
+
30
+ docs = []
31
+
32
+ for question in questions:
33
+ try:
34
+ docs.append(parse_question(question))
35
+ except Exception as e:
36
+ print(e, question)
37
+
38
+ db = Chroma.from_documents(docs, gemini_embeddings)
39
+ vectorstore = Chroma.from_documents(
40
+ documents=docs, embedding=gemini_embeddings, persist_directory="./chroma_db"
41
+ )
42
+
43
+ vectorstore_disk = Chroma(
44
+ persist_directory="./chroma_db", embedding_function=gemini_embeddings
45
+ )
46
 
 
 
 
47
  metadata_field_info = [
48
  AttributeInfo(
49
  name="topico",
server/llm/__init__.py ADDED
File without changes
server/requirements.txt CHANGED
@@ -2,9 +2,8 @@ langchain==0.1.6
2
  chromadb==0.5.0
3
  lark==1.1.9
4
  langchain-google-genai==1.0.1
5
- # langchain-text-splitters==0.0.1
6
  langchain-core==0.1.22
7
  langchain-community==0.0.20
8
  langsmith==0.0.87
9
- python-daemon==2.1.2
10
- localstack==0.12.0
 
2
  chromadb==0.5.0
3
  lark==1.1.9
4
  langchain-google-genai==1.0.1
 
5
  langchain-core==0.1.22
6
  langchain-community==0.0.20
7
  langsmith==0.0.87
8
+ # python-daemon==2.1.2
9
+ # langchain-text-splitters==0.0.1
web/package-lock.json CHANGED
@@ -9,11 +9,13 @@
9
  "version": "0.0.0",
10
  "dependencies": {
11
  "@radix-ui/react-select": "^2.0.0",
 
12
  "class-variance-authority": "^0.7.0",
13
  "clsx": "^2.1.1",
14
  "lucide-react": "^0.377.0",
15
  "react": "^18.2.0",
16
  "react-dom": "^18.2.0",
 
17
  "tailwind-merge": "^2.3.0",
18
  "tailwindcss-animate": "^1.0.7"
19
  },
@@ -1349,6 +1351,29 @@
1349
  }
1350
  }
1351
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1352
  "node_modules/@radix-ui/react-slot": {
1353
  "version": "1.0.2",
1354
  "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.2.tgz",
@@ -4789,6 +4814,18 @@
4789
  }
4790
  }
4791
  },
 
 
 
 
 
 
 
 
 
 
 
 
4792
  "node_modules/read-cache": {
4793
  "version": "1.0.0",
4794
  "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
 
9
  "version": "0.0.0",
10
  "dependencies": {
11
  "@radix-ui/react-select": "^2.0.0",
12
+ "@radix-ui/react-separator": "^1.0.3",
13
  "class-variance-authority": "^0.7.0",
14
  "clsx": "^2.1.1",
15
  "lucide-react": "^0.377.0",
16
  "react": "^18.2.0",
17
  "react-dom": "^18.2.0",
18
+ "react-toastify": "^10.0.5",
19
  "tailwind-merge": "^2.3.0",
20
  "tailwindcss-animate": "^1.0.7"
21
  },
 
1351
  }
1352
  }
1353
  },
1354
+ "node_modules/@radix-ui/react-separator": {
1355
+ "version": "1.0.3",
1356
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.0.3.tgz",
1357
+ "integrity": "sha512-itYmTy/kokS21aiV5+Z56MZB54KrhPgn6eHDKkFeOLR34HMN2s8PaN47qZZAGnvupcjxHaFZnW4pQEh0BvvVuw==",
1358
+ "dependencies": {
1359
+ "@babel/runtime": "^7.13.10",
1360
+ "@radix-ui/react-primitive": "1.0.3"
1361
+ },
1362
+ "peerDependencies": {
1363
+ "@types/react": "*",
1364
+ "@types/react-dom": "*",
1365
+ "react": "^16.8 || ^17.0 || ^18.0",
1366
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
1367
+ },
1368
+ "peerDependenciesMeta": {
1369
+ "@types/react": {
1370
+ "optional": true
1371
+ },
1372
+ "@types/react-dom": {
1373
+ "optional": true
1374
+ }
1375
+ }
1376
+ },
1377
  "node_modules/@radix-ui/react-slot": {
1378
  "version": "1.0.2",
1379
  "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.2.tgz",
 
4814
  }
4815
  }
4816
  },
4817
+ "node_modules/react-toastify": {
4818
+ "version": "10.0.5",
4819
+ "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-10.0.5.tgz",
4820
+ "integrity": "sha512-mNKt2jBXJg4O7pSdbNUfDdTsK9FIdikfsIE/yUCxbAEXl4HMyJaivrVFcn3Elvt5xvCQYhUZm+hqTIu1UXM3Pw==",
4821
+ "dependencies": {
4822
+ "clsx": "^2.1.0"
4823
+ },
4824
+ "peerDependencies": {
4825
+ "react": ">=18",
4826
+ "react-dom": ">=18"
4827
+ }
4828
+ },
4829
  "node_modules/read-cache": {
4830
  "version": "1.0.0",
4831
  "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
web/package.json CHANGED
@@ -11,11 +11,13 @@
11
  },
12
  "dependencies": {
13
  "@radix-ui/react-select": "^2.0.0",
 
14
  "class-variance-authority": "^0.7.0",
15
  "clsx": "^2.1.1",
16
  "lucide-react": "^0.377.0",
17
  "react": "^18.2.0",
18
  "react-dom": "^18.2.0",
 
19
  "tailwind-merge": "^2.3.0",
20
  "tailwindcss-animate": "^1.0.7"
21
  },
 
11
  },
12
  "dependencies": {
13
  "@radix-ui/react-select": "^2.0.0",
14
+ "@radix-ui/react-separator": "^1.0.3",
15
  "class-variance-authority": "^0.7.0",
16
  "clsx": "^2.1.1",
17
  "lucide-react": "^0.377.0",
18
  "react": "^18.2.0",
19
  "react-dom": "^18.2.0",
20
+ "react-toastify": "^10.0.5",
21
  "tailwind-merge": "^2.3.0",
22
  "tailwindcss-animate": "^1.0.7"
23
  },
web/src/App.jsx CHANGED
@@ -6,38 +6,82 @@ import {
6
  SelectValue,
7
  } from "@/components/ui/select"
8
  import { ChevronLeft, Menu } from "lucide-react"
9
- import { useEffect, useRef, useState } from "react";
 
 
10
 
11
  function App() {
12
 
13
- const selectRef = useRef(null);
14
  const [subject, setSubject] = useState("");
15
 
16
  const [menuState, setMenuState] = useState(true);
17
  const [isLoading, setIsLoading] = useState(false);
18
- const [questions, setQuestions] = useState("");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
  const handleSubmit = async (e) => {
21
  e.preventDefault();
22
  setIsLoading(true);
23
  try {
24
- const res = await fetch("https://abac-35-243-250-231.ngrok-free.app/question" + "/" + subject, {
25
  method: "POST",
26
  headers: {
27
  "Content-Type": "application/json"
28
  },
29
- // body: JSON.stringify({
30
- // assunto: subject
31
- // })
32
  });
33
  console.log(res)
34
  if (res.ok) {
35
  const data = await res.json();
36
  console.log(data)
37
- setQuestions(data.question.split("###"));
 
 
 
 
 
 
 
 
 
 
 
38
  }
39
  } catch (err) {
40
  console.error(err);
 
 
 
 
 
 
 
 
 
 
41
  }
42
  setIsLoading(false);
43
  }
@@ -51,26 +95,25 @@ function App() {
51
  setMenuState(false);
52
  }
53
  }
54
- // console.log(selectRef.current.value)
55
  window.addEventListener("resize", handleResize);
56
  return () => window.removeEventListener("resize", handleResize);
57
  }
58
  , []);
59
 
60
  return (
61
- <div className="font-sans text-white min-h-screen bg-slate-900 flex flex-col relative">
62
  <header className="p-10 flex items-center gap-2.5">
63
- <Menu className="md:hidden" onClick={e => setMenuState(prev => !prev)} />
64
  <h1 className="text-3xl font-bold">
65
- PerguntAI
66
  </h1>
67
  </header>
68
- <main className="flex-1 flex">
69
  {
70
  menuState &&
71
  <form
72
  onSubmit={handleSubmit}
73
- className="p-10 flex flex-col gap-2.5 absolute top-0 bg-black/70 h-full z-10 md:static md:h-full md:bg-transparent">
74
  <div className="md:sr-only">
75
  <ChevronLeft className="w-10 h-10" onClick={e => setMenuState(prev => !prev)} />
76
  </div>
@@ -95,24 +138,35 @@ function App() {
95
  </SelectContent>
96
  </Select>
97
  <button className="h-10 bg-purple-500 rounded px-2.5 py-1 mt-5 hover:brightness-110 transition-all flex items-center justify-center disabled:hover:brightness-75 disabled:brightness-75"
98
- disabled={isLoading}>
99
  {
100
  isLoading ?
101
- <div className="animate-spin h-5 w-5 border-2 border-white border-r-purple-500 rounded-full "></div>
102
  :
103
  "Enviar"
104
  }
105
  </button>
106
  </form>
107
  }
108
- <section className="p-10 flex-1 md:border-l-2 md:border-l-white flex flex-col gap-2.5">
109
  <h2 className="text-2xl font-bold">Questões</h2>
110
- <div className="w-full h-full flex flex-col gap-5 ring-2 ring-white rounded bg-slate-950 p-2.5">
111
  {questions ?
112
- questions.map((question, index) => <p className="" key={index}>{question}</p>)
113
- : "Ainda sem questões"}
 
 
 
 
 
 
 
 
 
 
114
  </div>
115
  </section>
 
116
  </main>
117
  </div>
118
  )
 
6
  SelectValue,
7
  } from "@/components/ui/select"
8
  import { ChevronLeft, Menu } from "lucide-react"
9
+ import { useEffect, useState } from "react";
10
+ import { ToastContainer, toast } from "react-toastify"
11
+ import 'react-toastify/dist/ReactToastify.css';
12
 
13
  function App() {
14
 
 
15
  const [subject, setSubject] = useState("");
16
 
17
  const [menuState, setMenuState] = useState(true);
18
  const [isLoading, setIsLoading] = useState(false);
19
+ const [questions, setQuestions] = useState([
20
+ {
21
+ question: "Qual a cor do céu?",
22
+ options: ["Azul", "Verde", "Amarelo", "Vermelho"],
23
+ answer: "Azul"
24
+ },
25
+ {
26
+ question: "Qual a cor da grama?",
27
+ options: ["Azul", "Verde", "Amarelo", "Vermelho"],
28
+ answer: "Verde"
29
+ },
30
+ {
31
+ question: "Qual a cor do sol?",
32
+ options: ["Azul", "Verde", "Amarelo", "Vermelho"],
33
+ answer: "Amarelo"
34
+ },
35
+ {
36
+ question: "Qual a cor do sangue?",
37
+ options: ["Azul", "Verde", "Amarelo", "Vermelho"],
38
+ answer: "Vermelho"
39
+ }
40
+
41
+ ]);
42
 
43
  const handleSubmit = async (e) => {
44
  e.preventDefault();
45
  setIsLoading(true);
46
  try {
47
+ const res = await fetch("/generate_questions", {
48
  method: "POST",
49
  headers: {
50
  "Content-Type": "application/json"
51
  },
52
+ body: JSON.stringify({
53
+ subject
54
+ })
55
  });
56
  console.log(res)
57
  if (res.ok) {
58
  const data = await res.json();
59
  console.log(data)
60
+ setQuestions(data.questions);
61
+ } else {
62
+ toast.error("Erro ao gerar questões", {
63
+ position: "top-right",
64
+ autoClose: 5000,
65
+ hideProgressBar: false,
66
+ closeOnClick: true,
67
+ pauseOnHover: true,
68
+ draggable: true,
69
+ progress: undefined,
70
+ className: "bg-slate-900 text-white font-semibold",
71
+ });
72
  }
73
  } catch (err) {
74
  console.error(err);
75
+ toast.error("Erro ao gerar questões", {
76
+ position: "top-right",
77
+ autoClose: 5000,
78
+ hideProgressBar: false,
79
+ closeOnClick: true,
80
+ pauseOnHover: true,
81
+ draggable: true,
82
+ progress: undefined,
83
+ className: "bg-slate-900 text-white font-semibold",
84
+ });
85
  }
86
  setIsLoading(false);
87
  }
 
95
  setMenuState(false);
96
  }
97
  }
 
98
  window.addEventListener("resize", handleResize);
99
  return () => window.removeEventListener("resize", handleResize);
100
  }
101
  , []);
102
 
103
  return (
104
+ <div className="font-sans h-screen text-white min-h-screen bg-slate-900 flex flex-col relative overflow-hidden">
105
  <header className="p-10 flex items-center gap-2.5">
106
+ <Menu className="md:hidden" onClick={() => setMenuState(prev => !prev)} />
107
  <h1 className="text-3xl font-bold">
108
+ Pergunt.<span className="text-transparent bg-clip-text bg-gradient-to-r from-green-300 to bg-blue-500">AÍ</span>
109
  </h1>
110
  </header>
111
+ <main className="flex-1 flex overflow-hidden">
112
  {
113
  menuState &&
114
  <form
115
  onSubmit={handleSubmit}
116
+ className="p-10 flex flex-col gap-2.5 absolute top-0 bg-black/95 h-full z-10 md:static md:h-full md:bg-transparent">
117
  <div className="md:sr-only">
118
  <ChevronLeft className="w-10 h-10" onClick={e => setMenuState(prev => !prev)} />
119
  </div>
 
138
  </SelectContent>
139
  </Select>
140
  <button className="h-10 bg-purple-500 rounded px-2.5 py-1 mt-5 hover:brightness-110 transition-all flex items-center justify-center disabled:hover:brightness-75 disabled:brightness-75"
141
+ disabled={isLoading || !subject}>
142
  {
143
  isLoading ?
144
+ <div className="animate-spin h-5 w-5 border-2 border-white border-r-purple-500 rounded-full"></div>
145
  :
146
  "Enviar"
147
  }
148
  </button>
149
  </form>
150
  }
151
+ <section className="p-10 flex-1 md:border-l-2 md:border-l-white flex flex-col gap-2.5 ">
152
  <h2 className="text-2xl font-bold">Questões</h2>
153
+ <div className="w-full h-full flex flex-col gap-5 rounded p-2.5 overflow-y-scroll">
154
  {questions ?
155
+ questions.map(({ question, options, answer }, index) => (
156
+ <div key={index} className="bg-slate-950 ring-2 ring-white p-2.5 rounded">
157
+ {question}<br /><br />
158
+ {options.map((option, i) => (
159
+ <div key={i}>
160
+ {option}
161
+ </div>
162
+ ))}<br />
163
+ Resposta correta: {answer}
164
+ </div>
165
+ ))
166
+ : <div className="p-2.5 bg-slate-950 ring-2 ring-white rounded">{"Ainda sem questões"}</div>}
167
  </div>
168
  </section>
169
+ <ToastContainer />
170
  </main>
171
  </div>
172
  )
web/src/components/ui/separator.jsx ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as SeparatorPrimitive from "@radix-ui/react-separator"
5
+
6
+ import { cn } from "@/lib/utils"
7
+
8
+ const Separator = React.forwardRef((
9
+ { className, orientation = "horizontal", decorative = true, ...props },
10
+ ref
11
+ ) => (
12
+ <SeparatorPrimitive.Root
13
+ ref={ref}
14
+ decorative={decorative}
15
+ orientation={orientation}
16
+ className={cn(
17
+ "shrink-0 bg-border",
18
+ orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
19
+ className
20
+ )}
21
+ {...props} />
22
+ ))
23
+ Separator.displayName = SeparatorPrimitive.Root.displayName
24
+
25
+ export { Separator }
web/src/index.css CHANGED
@@ -27,3 +27,19 @@
27
  --radius: 0.5rem;
28
  }
29
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  --radius: 0.5rem;
28
  }
29
  }
30
+
31
+ ::-webkit-scrollbar {
32
+ /* Customize the scrollbar width */
33
+ width: .5rem;
34
+ background-color: transparent;
35
+ }
36
+
37
+ ::-webkit-scrollbar-track {
38
+ /* Customize the scrollbar track */
39
+ }
40
+
41
+ ::-webkit-scrollbar-thumb {
42
+ /* Customize the scrollbar thumb */
43
+ background-color: #C0C0C0;
44
+ border-radius: .5rem;
45
+ }