Spaces:
Paused
Paused
Dobin Yim
commited on
Commit
Β·
9046e9c
1
Parent(s):
74aa61e
Final App V0
Browse files- .env +2 -0
- Dockerfile +11 -0
- Excel Review.pdf +0 -0
- chainlit.md +14 -0
- final.py +333 -0
- requirements.txt +24 -0
- uploads/fall23.zip +3 -0
.env
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
OPENAI_API_KEY=sk-proj-Ag0GaxKAAre2MFgXdFUWT3BlbkFJEAR66bo4a45j4Sa5DwML
|
2 |
+
PYTHONPATH=.
|
Dockerfile
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
FROM python:3.11
|
2 |
+
RUN useradd -m -u 1000 user
|
3 |
+
USER user
|
4 |
+
ENV HOME=/home/user \
|
5 |
+
PATH=/home/user/.local/bin:$PATH
|
6 |
+
WORKDIR $HOME/app
|
7 |
+
COPY --chown=user . $HOME/app
|
8 |
+
COPY ./requirements.txt ~/app/requirements.txt
|
9 |
+
RUN pip install -r requirements.txt
|
10 |
+
COPY . .
|
11 |
+
CMD ["chainlit", "run", "final.py", "--port", "7860"]
|
Excel Review.pdf
ADDED
Binary file (46.6 kB). View file
|
|
chainlit.md
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Final Project ππ€
|
2 |
+
|
3 |
+
Hi there, Developer! π We're excited to have you on board. Chainlit is a powerful tool designed to help you prototype, debug and share applications built on top of LLMs.
|
4 |
+
|
5 |
+
## Useful Links π
|
6 |
+
|
7 |
+
- **Documentation:** Get started with our comprehensive [Chainlit Documentation](https://docs.chainlit.io) π
|
8 |
+
- **Discord Community:** Join our friendly [Chainlit Discord](https://discord.gg/k73SQ3FyUh) to ask questions, share your projects, and connect with other developers! π¬
|
9 |
+
|
10 |
+
We can't wait to see what you create with Chainlit! Happy coding! π»π
|
11 |
+
|
12 |
+
## Welcome screen
|
13 |
+
|
14 |
+
To modify the welcome screen, edit the `chainlit.md` file at the root of your project. If you do not want a welcome screen, just leave this file empty.
|
final.py
ADDED
@@ -0,0 +1,333 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# -*- coding: utf-8 -*-
|
2 |
+
"""AIE3final.py
|
3 |
+
______
|
4 |
+
Automated Grading System for AIE3 Final Project
|
5 |
+
______
|
6 |
+
"""
|
7 |
+
|
8 |
+
# Import necessary libraries
|
9 |
+
import logging
|
10 |
+
import sys
|
11 |
+
import os
|
12 |
+
import re
|
13 |
+
import zipfile
|
14 |
+
import tempfile
|
15 |
+
from typing import List, Dict, Tuple
|
16 |
+
from dotenv import load_dotenv
|
17 |
+
from langchain_community.document_loaders import PyMuPDFLoader
|
18 |
+
from langchain.text_splitter import RecursiveCharacterTextSplitter
|
19 |
+
from langchain.schema import Document
|
20 |
+
from langchain_core.messages import AIMessage
|
21 |
+
from langchain_openai import OpenAIEmbeddings
|
22 |
+
from sentence_transformers import SentenceTransformer
|
23 |
+
from qdrant_client import QdrantClient
|
24 |
+
from qdrant_client.models import VectorParams, Distance, PointStruct, ScoredPoint
|
25 |
+
from docx import Document as DocxDocument
|
26 |
+
from transformers import AutoModelForCausalLM, AutoTokenizer
|
27 |
+
import torch
|
28 |
+
import getpass
|
29 |
+
from langchain_core.prompts import ChatPromptTemplate
|
30 |
+
from langchain_openai import ChatOpenAI
|
31 |
+
import openai
|
32 |
+
import json
|
33 |
+
import numpy as np
|
34 |
+
from sklearn.metrics.pairwise import cosine_similarity
|
35 |
+
import chainlit as cl
|
36 |
+
import asyncio
|
37 |
+
|
38 |
+
# Load environment variables
|
39 |
+
load_dotenv()
|
40 |
+
OPENAI_API_KEY = os.environ["OPENAI_API_KEY"]
|
41 |
+
openai.api_key = OPENAI_API_KEY
|
42 |
+
|
43 |
+
# Set up logging
|
44 |
+
logging.basicConfig(level=logging.INFO)
|
45 |
+
logger = logging.getLogger(__name__)
|
46 |
+
|
47 |
+
# Define constants
|
48 |
+
REFERENCE_DOCUMENT_PATH = './Excel Review.pdf'
|
49 |
+
UPLOAD_FOLDER = './uploads'
|
50 |
+
|
51 |
+
# Ensure the upload folder exists
|
52 |
+
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
|
53 |
+
|
54 |
+
def unzip_file(file_path: str, output_dir: str):
|
55 |
+
with zipfile.ZipFile(file_path, 'r') as zip_ref:
|
56 |
+
for member in zip_ref.namelist():
|
57 |
+
if not member.startswith('__MACOSX/'):
|
58 |
+
zip_ref.extract(member, output_dir)
|
59 |
+
|
60 |
+
def read_pdf(file_path: str) -> List[Document]:
|
61 |
+
loader = PyMuPDFLoader(file_path)
|
62 |
+
return loader.load()
|
63 |
+
|
64 |
+
def read_docx(file_path: str) -> Document:
|
65 |
+
doc = DocxDocument(file_path)
|
66 |
+
text = "\n".join([p.text for p in doc.paragraphs])
|
67 |
+
return Document(page_content=text, metadata={"source": file_path})
|
68 |
+
|
69 |
+
def read_files_from_directory(directory: str) -> List[Document]:
|
70 |
+
documents = []
|
71 |
+
for root, _, files in os.walk(directory):
|
72 |
+
for file in files:
|
73 |
+
file_path = os.path.join(root, file)
|
74 |
+
if os.path.basename(file_path).startswith('~$'):
|
75 |
+
continue # Skip temporary files
|
76 |
+
if file_path.endswith('.docx'):
|
77 |
+
documents.append(read_docx(file_path))
|
78 |
+
elif file_path.endswith('.pdf'):
|
79 |
+
documents.extend(read_pdf(file_path))
|
80 |
+
return documents
|
81 |
+
|
82 |
+
def extract_json(message: AIMessage) -> List[dict]:
|
83 |
+
text = message.content
|
84 |
+
pattern = r"```json(.*?)```"
|
85 |
+
matches = re.findall(pattern, text, re.DOTALL)
|
86 |
+
try:
|
87 |
+
return [json.loads(match.strip()) for match in matches]
|
88 |
+
except Exception:
|
89 |
+
raise ValueError(f"Failed to parse: {message}")
|
90 |
+
|
91 |
+
qa_chat_model = ChatOpenAI(
|
92 |
+
model="gpt-4o-mini",
|
93 |
+
temperature=0
|
94 |
+
)
|
95 |
+
|
96 |
+
ref_prompt = f"""
|
97 |
+
You are given a reference documents. The document contains a mix of instructions, guides, questions, and answers.
|
98 |
+
Your task is to go through the reference document and extract questions and answers from the document step-by-step.
|
99 |
+
Use the keyword 'Question #' to identify the start of each question.
|
100 |
+
Retain the following words until the 'Answer:' as the question.
|
101 |
+
Use the keyword 'Answer:' to identify the start of each answer.
|
102 |
+
Retain the follwing words until the 'Question:' as the answer, until the end of the document.
|
103 |
+
Remove any white spaces such as carriage returns.
|
104 |
+
Return the question-answer pairs as a key-value pair as Dict type.
|
105 |
+
---
|
106 |
+
|
107 |
+
Reference Document Content:
|
108 |
+
{{source}}
|
109 |
+
|
110 |
+
Please extract the question-answer pairs and return them as JSON.
|
111 |
+
"""
|
112 |
+
|
113 |
+
ref_prompt_template = ChatPromptTemplate.from_template(ref_prompt)
|
114 |
+
ref_generation_chain = ref_prompt_template | qa_chat_model
|
115 |
+
|
116 |
+
student_prompt = f"""
|
117 |
+
You are given a student assignment document. The document may contain a mix of instructions, guides, questions, and answers.
|
118 |
+
Your task is to go through the student document and extract answers to questions from the document step-by-step.
|
119 |
+
Use the reference document as a guide.
|
120 |
+
Use the keyword 'Question #' to identify each question.
|
121 |
+
Then for its associated values, search the student document for the answer.
|
122 |
+
If you do not see any answer in the student document, return 'No answer found'.
|
123 |
+
Do not make up any answer.
|
124 |
+
Remove any white spaces such as carriage returns.
|
125 |
+
Return the original question and the student answer pairs as a key-value pair as Dict type.
|
126 |
+
---
|
127 |
+
|
128 |
+
Reference Content:
|
129 |
+
{{source}}
|
130 |
+
|
131 |
+
Student Content:
|
132 |
+
{{student}}
|
133 |
+
|
134 |
+
Please extract the question-answer pairs and return them as JSON.
|
135 |
+
"""
|
136 |
+
|
137 |
+
student_prompt_template = ChatPromptTemplate.from_template(student_prompt)
|
138 |
+
student_response_chain = student_prompt_template | qa_chat_model
|
139 |
+
|
140 |
+
def split_documents(documents: List[Document]) -> List[Document]:
|
141 |
+
text_splitter = RecursiveCharacterTextSplitter(
|
142 |
+
chunk_size=500,
|
143 |
+
chunk_overlap=100,
|
144 |
+
length_function=len,
|
145 |
+
is_separator_regex=False
|
146 |
+
)
|
147 |
+
split_docs = text_splitter.split_documents(documents)
|
148 |
+
total_tokens = sum(len(doc.page_content) for doc in split_docs) # Approximate token count
|
149 |
+
return split_docs, total_tokens
|
150 |
+
|
151 |
+
def generate_embeddings(docs: List[Document]) -> List[List[float]]:
|
152 |
+
embeddings_model = OpenAIEmbeddings(model="text-embedding-3-small")
|
153 |
+
embeddings = embeddings_model.embed_documents([doc.page_content for doc in docs])
|
154 |
+
total_tokens = sum(len(doc.page_content) for doc in docs) # Approximate token count
|
155 |
+
return embeddings, total_tokens
|
156 |
+
|
157 |
+
def prepare_files():
|
158 |
+
unzip_file('./uploads/fall23_small.zip', './temp')
|
159 |
+
documents = read_files_from_directory('./temp/fall23_small')
|
160 |
+
reference_document = read_pdf(REFERENCE_DOCUMENT_PATH)
|
161 |
+
return documents, reference_document
|
162 |
+
|
163 |
+
def process_student(documents, reference):
|
164 |
+
test_doc = documents[0]
|
165 |
+
student_result = student_response_chain.invoke({"source": reference.keys(),"student": test_doc })
|
166 |
+
student_gen_tokens = student_result.usage_metadata["total_tokens"]
|
167 |
+
student_result = dict(extract_json(student_result)[0])
|
168 |
+
return student_result, student_gen_tokens
|
169 |
+
|
170 |
+
def process_reference(reference_document):
|
171 |
+
result = ref_generation_chain.invoke({"source": reference_document})
|
172 |
+
ref_gen_tokens = result.usage_metadata["total_tokens"]
|
173 |
+
reference = dict(extract_json(result)[0])
|
174 |
+
|
175 |
+
answers = {}
|
176 |
+
for key in reference:
|
177 |
+
if key.startswith('Question'):
|
178 |
+
question_number = key.split('#')[1]
|
179 |
+
answer_key = f'Answer #{question_number}'
|
180 |
+
answers[key] = reference[answer_key]
|
181 |
+
|
182 |
+
return reference, answers, ref_gen_tokens
|
183 |
+
|
184 |
+
def split_docs(answers, student_result):
|
185 |
+
split_reference_docs, ref_tokens = {}, 0
|
186 |
+
split_student_docs, student_tokens = {}, 0
|
187 |
+
for key, value in answers.items():
|
188 |
+
split_docs, tokens = split_documents([Document(page_content=value)])
|
189 |
+
split_reference_docs[key] = split_docs
|
190 |
+
ref_tokens += tokens
|
191 |
+
|
192 |
+
for key, value in student_result.items():
|
193 |
+
split_docs, tokens = split_documents([Document(page_content=value)])
|
194 |
+
split_student_docs[key] = split_docs
|
195 |
+
student_tokens += tokens
|
196 |
+
|
197 |
+
reference_embeddings = {key: generate_embeddings(value)[0] for key, value in split_reference_docs.items()}
|
198 |
+
student_embeddings = {key: generate_embeddings(value)[0] for key, value in split_student_docs.items()}
|
199 |
+
|
200 |
+
return reference_embeddings, student_embeddings, ref_tokens, student_tokens
|
201 |
+
|
202 |
+
def compute_cosine_similarity(reference_embeddings: dict, student_embeddings: dict) -> float:
|
203 |
+
similarity_results = {}
|
204 |
+
for key in reference_embeddings.keys():
|
205 |
+
if key not in student_embeddings:
|
206 |
+
similarity_results[key] = 0
|
207 |
+
continue
|
208 |
+
reference_vector = np.array(reference_embeddings[key]).reshape(1, -1)
|
209 |
+
student_vector = np.array(student_embeddings[key]).reshape(1, -1)
|
210 |
+
if reference_vector.shape[1] != student_vector.shape[1]:
|
211 |
+
min_dim = min(reference_vector.shape[1], student_vector.shape[1])
|
212 |
+
reference_vector = reference_vector[:, :min_dim]
|
213 |
+
student_vector = student_vector[:, :min_dim]
|
214 |
+
similarity = cosine_similarity(reference_vector, student_vector)[0][0]
|
215 |
+
similarity_results[key] = similarity
|
216 |
+
|
217 |
+
total_similarity = sum(similarity_results.values())
|
218 |
+
num_questions = len(similarity_results)
|
219 |
+
average_similarity = total_similarity / num_questions if num_questions else 0
|
220 |
+
|
221 |
+
return average_similarity
|
222 |
+
|
223 |
+
|
224 |
+
def llm_similarity(answers, student_result):
|
225 |
+
score_prompt = f"""
|
226 |
+
You are given two dictionaries representing instructor solution and student answers.
|
227 |
+
Your task is to go through each question to grade the correctness of student answer.
|
228 |
+
Use the keyword 'Question #' to identify each question.
|
229 |
+
Then for its associated values, compare student answer against the instructor answer.
|
230 |
+
If the instructor answer has numerical values, check to make sure the student answer has the same number,
|
231 |
+
whether it is expressed in numbers or text.
|
232 |
+
If you do not see any answer in the student answer, assign score 0 for that answer.
|
233 |
+
For student answer that is similar to instructor, assign a full score of 1.
|
234 |
+
If the student answer is similar enough, assign a partial score of 0.5.
|
235 |
+
Otherwise, assign a score of 0.
|
236 |
+
Return the original question and the student score pairs as a key-value pair as Dict type.
|
237 |
+
---
|
238 |
+
|
239 |
+
Reference Content:
|
240 |
+
{{source}}
|
241 |
+
|
242 |
+
Student Content:
|
243 |
+
{{student}}
|
244 |
+
|
245 |
+
Please extract the question-answer pairs and return them as JSON.
|
246 |
+
"""
|
247 |
+
|
248 |
+
score_prompt_template = ChatPromptTemplate.from_template(score_prompt)
|
249 |
+
student_score_chain = score_prompt_template | qa_chat_model
|
250 |
+
|
251 |
+
student_score = student_score_chain.invoke({"source": answers, "student": student_result })
|
252 |
+
llm_score_tokens = student_score.usage_metadata["total_tokens"]
|
253 |
+
student_score = dict(extract_json(student_score)[0])
|
254 |
+
|
255 |
+
total_score = sum(student_score.values())
|
256 |
+
num_questions = len(student_score)
|
257 |
+
average_score = total_score / num_questions if num_questions else 0
|
258 |
+
|
259 |
+
return average_score, llm_score_tokens
|
260 |
+
|
261 |
+
def process_data() -> Tuple[float, float, int, int, int]:
|
262 |
+
documents, reference_document = prepare_files()
|
263 |
+
reference, answers, ref_gen_tokens = process_reference(reference_document)
|
264 |
+
student_result, student_gen_tokens = process_student(documents, reference)
|
265 |
+
reference_embeddings, student_embeddings, ref_tokens, student_tokens = split_docs(answers, student_result)
|
266 |
+
student_total_tokens = student_gen_tokens + student_tokens
|
267 |
+
ref_total_tokens = ref_gen_tokens + ref_tokens
|
268 |
+
|
269 |
+
average_similarity = compute_cosine_similarity(reference_embeddings, student_embeddings)
|
270 |
+
average_score, llm_score_tokens = llm_similarity(answers, student_result)
|
271 |
+
llm_total_tokens = ref_gen_tokens + student_gen_tokens + llm_score_tokens
|
272 |
+
|
273 |
+
return average_similarity, average_score, ref_total_tokens, student_total_tokens, llm_total_tokens
|
274 |
+
|
275 |
+
async def process_grading():
|
276 |
+
average_similarity, average_score, ref_total_tokens, student_total_tokens, llm_total_tokens = process_data()
|
277 |
+
|
278 |
+
await cl.Message(content=f"Total tokens used for reference documents: {ref_total_tokens}").send()
|
279 |
+
await cl.Message(content=f"Total tokens used for student documents: {student_total_tokens}").send()
|
280 |
+
await cl.Message(content=f"Total tokens used by LLM: {llm_total_tokens}").send()
|
281 |
+
await cl.Message(content=f"Score: {average_similarity}").send()
|
282 |
+
await cl.Message(content=f"Average Score: {average_score}").send()
|
283 |
+
|
284 |
+
@cl.on_chat_start
|
285 |
+
async def start_chat():
|
286 |
+
await cl.Message(content="Do you want to proceed with the grading? (yes/no)").send()
|
287 |
+
|
288 |
+
|
289 |
+
|
290 |
+
# Define a global flag to track the processing state
|
291 |
+
user_wants_to_continue = False
|
292 |
+
|
293 |
+
@cl.on_message
|
294 |
+
async def on_message(message: cl.Message):
|
295 |
+
global user_wants_to_continue
|
296 |
+
|
297 |
+
if message.content.lower() == 'yes' and not user_wants_to_continue:
|
298 |
+
# Start processing
|
299 |
+
processing_message = cl.Message(content="Processing files...")
|
300 |
+
await processing_message.send() # Send the message immediately
|
301 |
+
await asyncio.sleep(0.5) # Short delay to ensure the message is displayed
|
302 |
+
await process_grading()
|
303 |
+
|
304 |
+
# Ask user if they want to continue after processing is done
|
305 |
+
user_wants_to_continue = True
|
306 |
+
await cl.Message(content="Do you want to continue? (yes/no)").send()
|
307 |
+
|
308 |
+
elif user_wants_to_continue:
|
309 |
+
if message.content.lower() == 'yes':
|
310 |
+
user_wants_to_continue = False # Reset the flag
|
311 |
+
await cl.Message(content="Restarting the app...").send()
|
312 |
+
await asyncio.sleep(1) # Give time for the message to be sent
|
313 |
+
python = sys.executable
|
314 |
+
os.execl(python, python, *sys.argv) # Restart the app
|
315 |
+
|
316 |
+
elif message.content.lower() == 'no':
|
317 |
+
user_wants_to_continue = False # Reset the flag
|
318 |
+
await cl.Message(content="Okay, thank you for using the grading app. Restarting...").send()
|
319 |
+
await asyncio.sleep(1) # Give time for the message to be sent
|
320 |
+
python = sys.executable
|
321 |
+
os.execl(python, python, *sys.argv) # Restart the app
|
322 |
+
|
323 |
+
else:
|
324 |
+
await cl.Message(content="Invalid response. Please type 'yes' or 'no'.").send()
|
325 |
+
|
326 |
+
elif message.content.lower() == 'no':
|
327 |
+
await cl.Message(content="Okay, thank you for using the grading app. Restarting...").send()
|
328 |
+
await asyncio.sleep(1) # Give time for the message to be sent
|
329 |
+
python = sys.executable
|
330 |
+
os.execl(python, python, *sys.argv) # Restart the app
|
331 |
+
|
332 |
+
else:
|
333 |
+
await cl.Message(content="Please type 'yes' to start processing or 'no' to exit.").send()
|
requirements.txt
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
chainlit
|
2 |
+
langchain
|
3 |
+
langchain-core
|
4 |
+
langgraph
|
5 |
+
langchain-community
|
6 |
+
langchain_huggingface
|
7 |
+
langchain_openai
|
8 |
+
langchain-text-splitters
|
9 |
+
peft
|
10 |
+
bitsandbytes
|
11 |
+
accelerate
|
12 |
+
qdrant-client
|
13 |
+
python-dotenv
|
14 |
+
pymupdf
|
15 |
+
huggingface_hub
|
16 |
+
pandas
|
17 |
+
sentence-transformers
|
18 |
+
python-docx
|
19 |
+
docx2pdf
|
20 |
+
python-dotenv
|
21 |
+
transformers
|
22 |
+
torch
|
23 |
+
|
24 |
+
|
uploads/fall23.zip
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:f83797e21c0153a03ef19ff14315ffff3de8730560610bd7b96e2eb066518930
|
3 |
+
size 2092284
|