deakin-it-help-desk
This repo is a RAG APP for Deakin IT HELP DESK
Science Score: 31.0%
This score indicates how likely this project is to be science-related based on various indicators:
-
✓CITATION.cff file
Found CITATION.cff file -
✓codemeta.json file
Found codemeta.json file -
○.zenodo.json file
-
○DOI references
-
○Academic publication links
-
○Academic email domains
-
○Institutional organization owner
-
○JOSS paper metadata
-
○Scientific vocabulary similarity
Low similarity (8.3%) to scientific vocabulary
Repository
This repo is a RAG APP for Deakin IT HELP DESK
Basic Info
- Host: GitHub
- Owner: OmarMohammed88
- Language: Python
- Default Branch: main
- Size: 210 KB
Statistics
- Stars: 0
- Watchers: 2
- Forks: 0
- Open Issues: 0
- Releases: 0
Metadata Files
README.md
Deakin IT Help Desk - RAG Application
This repository contains the implementation of a Retrieval-Augmented Generation (RAG) application designed for the Deakin IT Help Desk. The app is used for automating and improving the process of responding to IT-related queries.
Table of Contents
Installation
To set up the environment for running the RAG application, follow these steps:
1. Load Anaconda module
First, load the Anaconda3 module:
```bash module load Anaconda3
conda env create -f environment.yml
source activate
conda activate rag_app ```
Download Database and Datasets
Ensure the application functions correctly, you need to download the necessary database and datasets. - Download the required vector database files from this Google Drive link. - Vector_Database
- [Datasets](https://drive.google.com/drive/folders/1EDnGRVnUS7HEuUPpsPwPgbmQqs20fxsq?usp=drive_link)
Running the Application
Once the environment is set up and the necessary data is downloaded, you can run the application with the following command:
sbatch run_rag.sh
Owner
- Name: Omar Mohamed Ahmed
- Login: OmarMohammed88
- Kind: user
- Location: Egypt
- Company: omarmohamed.8809@gmail.com
- Website: https://www.linkedin.com/in/omarmohamed88/
- Repositories: 1
- Profile: https://github.com/OmarMohammed88
Experienced Researcher with a Growing history of working in research, Skilled in Computer Science, Medical Image Processing, NLP, DS/DL/ML
Citation (citation_run.py)
from sentence_transformers import SentenceTransformer
from langchain.embeddings.base import Embeddings
import torch
from langchain import LLMChain, PromptTemplate
from langchain.chains import RetrievalQA, StuffDocumentsChain
from langchain.vectorstores import Chroma
import gradio as gr
import json
import os
from langchain_community.llms import VLLM
import difflib
from sklearn.metrics.pairwise import cosine_similarity
import numpy as np
from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline
from langchain.llms import HuggingFacePipeline
import subprocess
model_name='microsoft/phi-4'
class SentenceTransformerEmbeddings(Embeddings):
def __init__(self, model_name="nomic-ai/nomic-embed-text-v1.5", device=None, batch_size=32):
super().__init__()
self.device = device or ("cuda" if torch.cuda.is_available() else "cpu")
self.model = SentenceTransformer(model_name, trust_remote_code=True, device=self.device)
self.batch_size = batch_size # Control batch size
def embed_documents(self, texts):
texts = ["search_document: "+i for i in texts]
return self.model.encode(
texts,
convert_to_numpy=True,
device=self.device,
batch_size=self.batch_size
).tolist()
def embed_query(self, text):
return self.model.encode(
['search_query: '+text],
convert_to_numpy=True,
device=self.device
)[0].tolist()
def extract_answers(answers):
answers = answers.split("<|im_start|>assistant<|im_sep|>")[-1]
return answers
def get_title(links):
titles = [i.metadata['source'].split("/weka/s223795137/Crawl_data/crawled_pages/")[-1].split("_")[0] for i in links]
matches = set() # Use a set to avoid duplicates
for word in list(set(titles)):
close_keys = difflib.get_close_matches(word, data_swap.keys(), n=1, cutoff=0.6)
matches.update(close_keys)
return list(matches)
with open("crawled_pages/crawled_pages.json") as f:
data = json.load(f)
def swap_keys_and_values(my_dict):
"""Swap the keys and values in the dictionary."""
return {value: key for key, value in my_dict.items()}
data_swap = swap_keys_and_values(data)
def get_values_by_keys(my_dict, keys):
"""Return the values from the dictionary based on a list of keys."""
return [my_dict[key] for key in keys if key in my_dict]
def calculate_query_doc_similarity(query, vectorstore, k=5):
"""
Calculate cosine similarities between a query and the top k retrieved documents.
Args:
query (str): The input query string.
vectorstore: The vector store instance (e.g., Chroma).
k (int): Number of top documents to retrieve (default: 5).
Returns:
dict: Contains doc_similarity_pairs and average_similarity.
"""
# Initialize retriever
retriever = vectorstore.as_retriever(search_kwargs={"k": k})
# Step 1: Get the query embedding
embedding_function = vectorstore.embeddings # Use the same embedding function
query_embedding = embedding_function.embed_query(query)
# Step 2: Retrieve top k documents
retrieved_docs = retriever.get_relevant_documents(query)
# Step 3: Recompute embeddings for retrieved documents
doc_embeddings = [embedding_function.embed_query(doc.page_content) for doc in retrieved_docs]
query_embedding = np.array(query_embedding).reshape(1, -1)
doc_embeddings = np.array(doc_embeddings)
# Compute similarities
similarities = cosine_similarity(query_embedding, doc_embeddings)[0] if doc_embeddings.size > 0 else np.array([])
# Sort similarities in descending order
sorted_similarities = np.sort(similarities)[::-1]
# Compute average similarity
average_similarity = np.mean(similarities) if similarities.size > 0 else 0.0
return sorted_similarities[:2], average_similarity
def get_most_related_keys(titles, dictionary, top_n=5):
"""
Find the top N keys in a dictionary most related to a given list of titles based on cosine similarity.
Args:
titles (list of str): List of title strings to compare against.
dictionary (dict): Dictionary with keys (strings) and values.
top_n (int): Number of top related keys to return (default: 5).
Returns:
list: List of tuples (title, [(key, similarity_score)]) sorted by similarity in descending order.
"""
embedding_function = vectorstore.embeddings # Use the same embedding function
# Step 1: Embed all dictionary keys
key_embeddings = np.array(embedding_function.embed_documents(list(dictionary.keys())))
# Initialize list to store results
most_related = []
# Step 2: For each title, find the most similar keys
for title in titles:
# Embed the current title
title_embedding = np.array(embedding_function.embed_query(title)).reshape(1, -1)
# Step 3: Calculate cosine similarity for the current title and all dictionary keys
cos_sim = cosine_similarity(title_embedding, key_embeddings)
# Step 4: Get the top N most similar keys
top_n_indices = np.argsort(cos_sim[0])[-top_n:][::-1] # Sort and reverse for descending order
# Step 5: Collect the top N most similar keys and their similarity scores
related_keys = [(list(dictionary.keys())[i], cos_sim[0][i]) for i in top_n_indices]
# Append the result for the current title
most_related.append(related_keys)
# Return the results
if len(most_related):
most_related = [i[0] for i in most_related[0]]
return most_related
import datetime
chat_history_file = "chat_history.json"
def log_interaction(query, response, filename="chat_history.json"):
"""Logs the user query and model response to a JSON file."""
# Create an empty list if file doesn't exist
if not os.path.exists(filename):
history = []
else:
with open(filename, "r", encoding="utf-8") as file:
try:
history = json.load(file) # Load existing history
except json.JSONDecodeError:
history = [] # If file is empty or corrupted, reset it
# New entry
entry = {
"timestamp": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"user_query": query,
"model_response": response
}
# Append new entry and save back to JSON file
history.append(entry)
with open(filename, "w", encoding="utf-8") as file:
json.dump(history, file, ensure_ascii=False, indent=4)
def query_rag_model(query, k):
# Update the retriever's 'k' value
retriever = vectorstore.as_retriever(search_kwargs={"k": k})
rag_chain = RetrievalQA(
retriever=retriever,
combine_documents_chain=stuff_chain
)
# Run the RAG pipeline
response = rag_chain.run(query)
k
# Extract the answer
response = extract_answers(response)
citations = rag_chain.retriever.get_relevant_documents(query)
# response = extract_answers(response)
citation_links = get_values_by_keys(data_swap,get_title(citations))
top2_Score , sim_score = calculate_query_doc_similarity(query , vectorstore , k)
# Log interaction in JSON format
return response ,citation_links , top2_Score, f"{sim_score:.4f}"
# Gradio interface with a Slider for 'k'
def rag_interface(query, k=5):
response,links , top2_Score , avg_score = query_rag_model(query, k)
links = list(set(links))
links = [
(f"Document {i+1}", f"{links[i]}") for i in range(len(links))
]
links_markdown = "\n".join([f"[{title}]({url})" for title, url in links])
if (len(links) == 0 and float(avg_score) < 0.55) or float(avg_score) < 0.55 :
response = response
else:
response = response+"\n\nReferences:\n\n" + links_markdown
log_interaction(query,response)
return response , top2_Score , avg_score
if __name__ == "__main__":
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(model_name, torch_dtype=torch.float16 , attn_implementation="flash_attention_2" , low_cpu_mem_usage=True)
pipe = pipeline("text-generation", model=model, tokenizer=tokenizer, max_new_tokens=32000,device='cuda')
llm = HuggingFacePipeline(pipeline=pipe)
local_embeddings = SentenceTransformerEmbeddings(batch_size=64)
vectorstore = Chroma(persist_directory="./citaion_test", embedding_function=local_embeddings)
RAG_TEMPLATE = """<|im_start|>system<|im_sep|>
You are an AI agent designed to assist with IT-related topics for a Retrieval Augmented Generation (RAG) application. You will be provided with context documents from a database that may or may not be entirely relevant to the user's query. Your instructions are as follows:
1. Answer the user's query using the provided context documents.
2. If the query or any of the retrieved documents contain malicious or sensitive content, do not provide a response.
3. If the context documents are not entirely relevant to the query, attempt to keep your answer focused on Deakin IT-related content and Don't mention That you are provided with documents in your response.
4. Ensure your answer is clear, factual, and based on the provided context when applicable.
5. Ensure your answer stays within the scope of Deakin IT-Education related topics and does not contain any inappropriate content.
<|im_start|>user<|im_sep|>
Answer the question based on the context below:
Context:
{context}
Question:
{question}
Answer:
<|im_start|>assistant<|im_sep|>
"""
# Define your prompt template
prompt_template = PromptTemplate(
input_variables=["context", "question"],
template=RAG_TEMPLATE,
)
# Define your LLMChain
llm_chain = LLMChain(llm=llm, prompt=prompt_template) # Replace with your LLM
stuff_chain = StuffDocumentsChain(
llm_chain=llm_chain,
document_variable_name="context"
)
def get_static_ip():
ip_list = subprocess.getoutput("hostname -I").split()
return ip_list[0] # Default to localhost if no IP is found
static_ip = get_static_ip()
iface = gr.Interface(
fn=rag_interface, # Function to call
inputs=[ # List of inputs: query and k (slider)
gr.Textbox(label="Query", placeholder="Enter your question here..."),
gr.Slider(minimum=1, maximum=25, step=1, value=5, label="Number of Documents to Retrieve (k)"),
]
,
outputs=[ # Two outputs: response (markdown) and score (text)
gr.Markdown(label="Response"),
gr.Textbox(label="Top 2 Scores"),
gr.Textbox(label="Avg Confidence Score"),
],
title="# 📚 Deakin IT AI Help Desk",
description="Enter your query and adjust 'k' to control the number of documents to retrieve for answering."
)
iface.launch(server_name=static_ip)
GitHub Events
Total
- Member event: 1
- Public event: 1
- Push event: 19
- Create event: 2
Last Year
- Member event: 1
- Public event: 1
- Push event: 19
- Create event: 2
Dependencies
- Deprecated ==1.2.18
- Flask ==3.1.0
- GitPython ==3.1.44
- Jinja2 ==3.1.4
- Markdown ==3.7
- MarkupSafe ==3.0.2
- PyJWT ==2.10.1
- PyPika ==0.48.9
- PySocks ==1.7.1
- PyYAML ==6.0.2
- Pygments ==2.19.1
- RapidFuzz ==3.12.1
- Rtree ==1.3.0
- SQLAlchemy ==2.0.38
- Werkzeug ==3.1.3
- XlsxWriter ==3.2.2
- absl-py ==2.1.0
- accelerate ==1.2.1
- aiofiles ==24.1.0
- aiohappyeyeballs ==2.4.4
- aiohttp ==3.11.11
- aiohttp-cors ==0.7.0
- aiosignal ==1.3.2
- airportsdata ==20241001
- annotated-types ==0.7.0
- anyio ==4.8.0
- appdirs ==1.4.4
- asgiref ==3.8.1
- astor ==0.8.1
- asttokens ==3.0.0
- async-timeout ==5.0.1
- attrs ==24.3.0
- automated-interpretability ==0.0.6
- babe ==0.0.7
- backoff ==2.2.1
- bcrypt ==4.2.1
- beartype ==0.14.1
- beautifulsoup4 ==4.13.3
- better-abc ==0.0.3
- bidict ==0.23.1
- bitsandbytes ==0.45.3
- blake3 ==1.0.2
- blinker ==1.9.0
- blobfile ==3.0.0
- boostedblob ==0.15.6
- build ==1.2.2.post1
- cachetools ==5.5.1
- certifi ==2024.12.14
- cffi ==1.17.1
- chardet ==5.2.0
- charset-normalizer ==3.4.0
- chroma-hnswlib ==0.7.6
- chromadb ==0.6.3
- click ==8.1.8
- cloudpickle ==3.1.1
- coloredlogs ==15.0.1
- colorful ==0.5.6
- comm ==0.2.2
- compressed-tensors ==0.8.1
- config2py ==0.1.36
- contourpy ==1.3.1
- cryptography ==44.0.1
- ctransformers ==0.2.27
- cut-cross-entropy ==25.1.1
- cycler ==0.12.1
- dataclasses-json ==0.6.7
- datasets ==2.21.0
- debugpy ==1.8.12
- decorator ==5.2.1
- depyf ==0.18.0
- diffusers ==0.32.2
- dill ==0.3.8
- diskcache ==5.6.3
- distlib ==0.3.9
- distro ==1.9.0
- docker-pycreds ==0.4.0
- docling ==2.25.1
- docling-core ==2.21.1
- docling-ibm-models ==3.4.1
- docling-parse ==3.4.0
- docstring_parser ==0.16
- dol ==0.3.9
- durationpy ==0.9
- easyocr ==1.7.2
- eindex-callum ==0.1.2
- einops ==0.7.0
- emoji ==2.14.1
- et_xmlfile ==2.0.0
- eval_type_backport ==0.2.2
- evaluate ==0.4.3
- exceptiongroup ==1.2.2
- executing ==2.2.0
- fancy-einsum ==0.0.3
- fastapi ==0.115.6
- fastchat ==0.1.0
- fastjsonschema ==2.21.1
- ffmpy ==0.5.0
- filelock ==3.17.0
- filetype ==1.2.0
- fire ==0.7.0
- flash_attn ==2.7.4.post1
- flatbuffers ==25.2.10
- fonttools ==4.56.0
- frozenlist ==1.5.0
- fsspec ==2024.6.1
- gdown ==5.2.0
- gguf ==0.10.0
- gitdb ==4.0.12
- google-api-core ==2.24.0
- google-auth ==2.37.0
- googleapis-common-protos ==1.66.0
- gprof2dot ==2024.6.6
- gradio ==5.16.1
- gradio_client ==1.7.0
- graze ==0.1.29
- greenlet ==3.1.1
- grpcio ==1.69.0
- h11 ==0.14.0
- hf_transfer ==0.1.9
- html5lib ==1.1
- httpcore ==1.0.7
- httptools ==0.6.4
- httpx ==0.27.2
- httpx-sse ==0.4.0
- huggingface-hub ==0.29.1
- humanfriendly ==10.0
- i2 ==0.1.46
- idna ==3.10
- imageio ==2.37.0
- importlib-metadata ==5.2.0
- importlib_resources ==6.5.2
- iniconfig ==2.0.0
- interegular ==0.3.3
- ipykernel ==6.29.5
- ipython ==8.32.0
- ipywidgets ==8.1.5
- itsdangerous ==2.2.0
- jaxtyping ==0.2.36
- jedi ==0.19.2
- jiter ==0.8.2
- joblib ==1.4.2
- jsonlines ==3.1.0
- jsonpatch ==1.33
- jsonpointer ==3.0.0
- jsonref ==1.1.0
- jsonschema ==4.23.0
- jsonschema-specifications ==2024.10.1
- jupyter_client ==8.6.3
- jupyter_core ==5.7.2
- jupyterlab_widgets ==3.0.13
- kiwisolver ==1.4.8
- kubernetes ==32.0.0
- langchain ==0.3.20
- langchain-chroma ==0.2.2
- langchain-community ==0.3.17
- langchain-core ==0.3.41
- langchain-docling ==0.2.0
- langchain-nomic ==0.1.4
- langchain-ollama ==0.2.3
- langchain-text-splitters ==0.3.6
- langdetect ==1.0.9
- langsmith ==0.3.8
- lark ==1.2.2
- latex2mathml ==3.77.0
- lazy_loader ==0.4
- lingua ==4.15.0
- lingua-language-detector ==2.0.2
- linkify-it-py ==2.0.3
- litellm ==1.59.0
- llvmlite ==0.44.0
- lm-format-enforcer ==0.10.9
- loguru ==0.7.3
- lxml ==5.3.1
- markdown-it-py ==3.0.0
- marko ==2.1.2
- marshmallow ==3.26.1
- matplotlib ==3.10.1
- matplotlib-inline ==0.1.7
- mdit-py-plugins ==0.4.2
- mdurl ==0.1.2
- memray ==1.15.0
- mistral_common ==1.5.1
- mmh3 ==5.1.0
- monotonic ==1.6
- mpire ==2.10.2
- mpmath ==1.3.0
- msgpack ==1.1.0
- msgspec ==0.19.0
- multidict ==6.1.0
- multiprocess ==0.70.16
- mypy-extensions ==1.0.0
- natsort ==8.4.0
- nbformat ==5.10.4
- nest-asyncio ==1.6.0
- networkx ==3.4.2
- ninja ==1.11.1.3
- nltk ==3.9.1
- nnsight ==0.3.7
- nomic ==3.4.1
- numba ==0.61.0
- numpy ==1.26.4
- nvidia-cublas-cu12 ==12.4.5.8
- nvidia-cuda-cupti-cu12 ==12.4.127
- nvidia-cuda-nvrtc-cu12 ==12.4.127
- nvidia-cuda-runtime-cu12 ==12.4.127
- nvidia-cudnn-cu12 ==9.1.0.70
- nvidia-cufft-cu12 ==11.2.1.3
- nvidia-curand-cu12 ==10.3.5.147
- nvidia-cusolver-cu12 ==11.6.1.9
- nvidia-cusparse-cu12 ==12.3.1.170
- nvidia-ml-py ==12.560.30
- nvidia-nccl-cu12 ==2.21.5
- nvidia-nvjitlink-cu12 ==12.4.127
- nvidia-nvtx-cu12 ==12.4.127
- oauthlib ==3.2.2
- olefile ==0.47
- ollama ==0.4.7
- onnxruntime ==1.20.1
- openai ==1.59.8
- opencensus ==0.11.4
- opencensus-context ==0.1.3
- opencv-python-headless ==4.11.0.86
- openpyxl ==3.1.5
- opentelemetry-api ==1.30.0
- opentelemetry-exporter-otlp-proto-common ==1.30.0
- opentelemetry-exporter-otlp-proto-grpc ==1.30.0
- opentelemetry-instrumentation ==0.51b0
- opentelemetry-instrumentation-asgi ==0.51b0
- opentelemetry-instrumentation-fastapi ==0.51b0
- opentelemetry-proto ==1.30.0
- opentelemetry-sdk ==1.30.0
- opentelemetry-semantic-conventions ==0.51b0
- opentelemetry-util-http ==0.51b0
- orjson ==3.10.15
- outlines ==0.1.11
- outlines_core ==0.1.26
- overrides ==7.7.0
- packaging ==24.2
- pandarallel ==1.6.5
- pandas ==2.2.3
- parallel-pandas ==0.6.5
- parso ==0.8.4
- partial-json-parser ==0.2.1.1.post5
- patsy ==1.0.1
- peft ==0.14.0
- pexpect ==4.9.0
- pillow ==10.4.0
- plotly ==5.24.1
- plotly-express ==0.4.1
- pluggy ==1.5.0
- polib ==1.2.0
- posthog ==3.14.1
- prometheus-fastapi-instrumentator ==7.0.2
- prometheus_client ==0.21.1
- prompt_toolkit ==3.0.50
- propcache ==0.2.1
- proto-plus ==1.25.0
- protobuf ==5.29.3
- psutil ==7.0.0
- ptyprocess ==0.7.0
- pure_eval ==0.2.3
- py-cpuinfo ==9.0.0
- py-spy ==0.4.0
- py2store ==0.1.20
- pyarrow ==18.1.0
- pyasn1 ==0.6.1
- pyasn1_modules ==0.4.1
- pybind11 ==2.13.6
- pyclipper ==1.3.0.post6
- pycountry ==24.6.1
- pycparser ==2.22
- pycryptodomex ==3.21.0
- pydantic ==2.10.5
- pydantic-settings ==2.7.1
- pydantic_core ==2.27.2
- pydub ==0.25.1
- pynndescent ==0.5.13
- pyparsing ==3.2.0
- pypdf ==5.3.0
- pypdfium2 ==4.30.1
- pyproject_hooks ==1.2.0
- pytest ==8.3.4
- pytest-profiling ==1.8.1
- python-bidi ==0.6.6
- python-dateutil ==2.9.0.post0
- python-docx ==1.1.2
- python-dotenv ==1.0.1
- python-engineio ==4.11.2
- python-iso639 ==2025.2.18
- python-magic ==0.4.27
- python-multipart ==0.0.20
- python-oxmsg ==0.0.2
- python-pptx ==1.0.2
- python-socketio ==5.12.1
- pytz ==2024.2
- pyzmq ==26.2.1
- ray ==2.40.0
- referencing ==0.36.1
- regex ==2024.11.6
- requests ==2.32.3
- requests-oauthlib ==2.0.0
- requests-toolbelt ==1.0.0
- rich ==13.9.4
- rouge-score ==0.1.2
- routellm ==0.2.0
- rpds-py ==0.22.3
- rsa ==4.9
- ruff ==0.9.6
- sae-lens ==5.4.1
- safehttpx ==0.1.6
- safetensors ==0.4.5
- schedulefree ==1.4
- scikit-image ==0.25.2
- scikit-learn ==1.6.0
- scipy ==1.15.1
- seaborn ==0.13.2
- semantic-version ==2.10.0
- semchunk ==2.2.2
- sentence-transformers ==3.4.1
- sentencepiece ==0.2.0
- sentry-sdk ==2.20.0
- setproctitle ==1.3.4
- sglang ==0.4.1.post6
- shapely ==2.0.7
- shellingham ==1.5.4
- shortuuid ==1.0.13
- shtab ==1.7.1
- simple-parsing ==0.1.7
- simple-websocket ==1.1.0
- six ==1.17.0
- smart-open ==7.1.0
- smmap ==5.0.2
- sniffio ==1.3.1
- soupsieve ==2.6
- stack-data ==0.6.3
- starlette ==0.41.3
- statsmodels ==0.14.4
- steering-vectors ==0.10.2
- sympy ==1.13.1
- tabulate ==0.9.0
- tenacity ==9.0.0
- termcolor ==2.5.0
- textual ==0.78.0
- threadpoolctl ==3.5.0
- tifffile ==2025.2.18
- tiktoken ==0.7.0
- tokenizers ==0.21.0
- toml ==0.10.2
- tomli ==2.2.1
- tomlkit ==0.13.2
- toolz ==1.0.0
- torch ==2.5.1
- torchvision ==0.20.1
- tornado ==6.4.2
- tqdm ==4.67.1
- traitlets ==5.14.3
- transformer-lens ==1.19.0
- transformers ==4.49.0
- triton ==3.1.0
- trl ==0.9.4
- typeguard ==4.4.1
- typer ==0.12.5
- typing-inspect ==0.9.0
- typing_extensions ==4.12.2
- tyro ==0.9.10
- tzdata ==2024.2
- uc-micro-py ==1.0.3
- umap-learn ==0.5.7
- unsloth_zoo ==2025.1.3
- unstructured ==0.16.21
- unstructured-client ==0.30.1
- urllib3 ==2.3.0
- uvicorn ==0.34.0
- uvloop ==0.21.0
- virtualenv ==20.29.2
- vllm ==0.6.6.post1
- wandb ==0.19.4
- watchfiles ==1.0.4
- wcwidth ==0.2.13
- webencodings ==0.5.1
- websocket-client ==1.8.0
- websockets ==14.2
- widgetsnbextension ==4.0.13
- wordcloud ==1.9.4
- wrapt ==1.17.2
- wsproto ==1.2.0
- xformers ==0.0.28.post3
- xgboost ==2.1.4
- xgrammar ==0.1.10
- xxhash ==3.5.0
- yarl ==1.18.3
- zipp ==3.21.0
- zstandard ==0.23.0