Spaces:
Sleeping
Sleeping
Commit ·
eb5a3ff
0
Parent(s):
Initial commit with RAG, FastAPI and Gradio UI
Browse files- .gitignore +25 -0
- README.md +54 -0
- agent.py +107 -0
- api.py +47 -0
- gradio_app.py +71 -0
- requirements.txt +147 -0
.gitignore
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Virtual Environments
|
| 2 |
+
venv/
|
| 3 |
+
env/
|
| 4 |
+
.venv/
|
| 5 |
+
|
| 6 |
+
# Environment Variables
|
| 7 |
+
.env
|
| 8 |
+
*.env
|
| 9 |
+
|
| 10 |
+
# Python Cache
|
| 11 |
+
__pycache__/
|
| 12 |
+
*.pyc
|
| 13 |
+
*.pyo
|
| 14 |
+
*.pyd
|
| 15 |
+
|
| 16 |
+
# ChromaDB local vector storage
|
| 17 |
+
chroma_db/
|
| 18 |
+
|
| 19 |
+
# IDEs
|
| 20 |
+
.vscode/
|
| 21 |
+
.idea/
|
| 22 |
+
|
| 23 |
+
# OS generated files
|
| 24 |
+
.DS_Store
|
| 25 |
+
Thumbs.db
|
README.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Task Prompting Tool
|
| 2 |
+
|
| 3 |
+
A tool designed for project managers and team leaders to generate developer-ready prompts. By providing a task description, specifying a field (e.g., Backend, Frontend), and uploading relevant context files, the underlying LLM (OpenAI or Google Gemini) will construct a comprehensive prompt ready to be handed to developers.
|
| 4 |
+
|
| 5 |
+
## Prerequisites
|
| 6 |
+
|
| 7 |
+
- Python 3.8+
|
| 8 |
+
- API keys for OpenAI and/or Google Gen AI.
|
| 9 |
+
|
| 10 |
+
## Setup Instructions
|
| 11 |
+
|
| 12 |
+
**1. Create Hand-configured Keys in `.env`**
|
| 13 |
+
Edit the `.env` file and insert your API keys and models as preferred:
|
| 14 |
+
```env
|
| 15 |
+
OPENAI_API_KEY="your-openai-api-key"
|
| 16 |
+
GOOGLE_API_KEY="your-google-api-key"
|
| 17 |
+
LLM_PROVIDER="google" # Options: "google" or "openai"
|
| 18 |
+
OPENAI_MODEL="gpt-4.1-mini"
|
| 19 |
+
GOOGLE_MODEL="gemini-3.1-flash-lite-preview"
|
| 20 |
+
```
|
| 21 |
+
|
| 22 |
+
**2. Setup Virtual Environment & Install Dependencies**
|
| 23 |
+
Open a terminal and run the following commands in the project directory:
|
| 24 |
+
|
| 25 |
+
```bash
|
| 26 |
+
python3 -m venv venv
|
| 27 |
+
source venv/bin/activate
|
| 28 |
+
pip install -r requirements.txt
|
| 29 |
+
```
|
| 30 |
+
|
| 31 |
+
*(On Windows, activate the virtual environment using `venv\Scripts\activate`)*
|
| 32 |
+
|
| 33 |
+
## Running the Application
|
| 34 |
+
|
| 35 |
+
This project features both a FastAPI backend (providing an API) and a Gradio frontend (providing a UI).
|
| 36 |
+
|
| 37 |
+
### Method 1: Using the UI (Recommended)
|
| 38 |
+
You can directly run the Gradio application to access the user interface.
|
| 39 |
+
|
| 40 |
+
```bash
|
| 41 |
+
source venv/bin/activate
|
| 42 |
+
python gradio_app.py
|
| 43 |
+
```
|
| 44 |
+
After executing, an interface will open at `http://127.0.0.1:7860/` by default. You can open your browser to this URL to interact with the Task Prompting Tool.
|
| 45 |
+
|
| 46 |
+
### Method 2: Running the API Server
|
| 47 |
+
If you'd like to integrate this logic into another system or frontend, run the FastAPI backend:
|
| 48 |
+
|
| 49 |
+
```bash
|
| 50 |
+
source venv/bin/activate
|
| 51 |
+
python api.py
|
| 52 |
+
```
|
| 53 |
+
The server will run at `http://0.0.0.0:8000`.
|
| 54 |
+
- View API Documentation at `http://127.0.0.1:8000/docs` to test endpoints interactively.
|
agent.py
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from dotenv import load_dotenv
|
| 3 |
+
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
|
| 4 |
+
from langchain_google_genai import ChatGoogleGenerativeAI, GoogleGenerativeAIEmbeddings
|
| 5 |
+
from langchain_core.prompts import ChatPromptTemplate
|
| 6 |
+
from langchain_core.output_parsers import StrOutputParser
|
| 7 |
+
from langchain_core.documents import Document
|
| 8 |
+
from langchain_community.vectorstores import Chroma
|
| 9 |
+
from langchain_text_splitters import RecursiveCharacterTextSplitter
|
| 10 |
+
|
| 11 |
+
load_dotenv()
|
| 12 |
+
|
| 13 |
+
def get_llm():
|
| 14 |
+
provider = os.getenv("LLM_PROVIDER", "google").lower()
|
| 15 |
+
|
| 16 |
+
if provider == "openai":
|
| 17 |
+
return ChatOpenAI(
|
| 18 |
+
model=os.getenv("OPENAI_MODEL", "gpt-4.1-mini"),
|
| 19 |
+
temperature=0.7
|
| 20 |
+
)
|
| 21 |
+
elif provider == "google":
|
| 22 |
+
return ChatGoogleGenerativeAI(
|
| 23 |
+
model=os.getenv("GOOGLE_MODEL", "gemini-3.1-flash-lite-preview"),
|
| 24 |
+
temperature=0.7
|
| 25 |
+
)
|
| 26 |
+
else:
|
| 27 |
+
raise ValueError(f"Unknown LLM Provider: {provider}")
|
| 28 |
+
|
| 29 |
+
def get_embeddings():
|
| 30 |
+
provider = os.getenv("LLM_PROVIDER", "google").lower()
|
| 31 |
+
if provider == "openai":
|
| 32 |
+
return OpenAIEmbeddings(model="text-embedding-3-small")
|
| 33 |
+
elif provider == "google":
|
| 34 |
+
return GoogleGenerativeAIEmbeddings(model="models/gemini-embedding-001")
|
| 35 |
+
else:
|
| 36 |
+
raise ValueError(f"Unknown LLM Provider: {provider}")
|
| 37 |
+
|
| 38 |
+
def process_and_retrieve_context(description: str, field: str, files_data: list[dict]) -> str:
|
| 39 |
+
"""Takes a list of file dictionaries and retrieves relevant context using ChromaDB."""
|
| 40 |
+
if not files_data:
|
| 41 |
+
return "No extra files provided."
|
| 42 |
+
|
| 43 |
+
docs = []
|
| 44 |
+
for file in files_data:
|
| 45 |
+
docs.append(Document(
|
| 46 |
+
page_content=file["content"],
|
| 47 |
+
metadata={"source": file["filename"]}
|
| 48 |
+
))
|
| 49 |
+
|
| 50 |
+
# Split the documents
|
| 51 |
+
text_splitter = RecursiveCharacterTextSplitter(
|
| 52 |
+
chunk_size=1000,
|
| 53 |
+
chunk_overlap=200
|
| 54 |
+
)
|
| 55 |
+
splits = text_splitter.split_documents(docs)
|
| 56 |
+
|
| 57 |
+
# Store locally in chromadb directory and use it to retrieve
|
| 58 |
+
vectorstore = Chroma.from_documents(
|
| 59 |
+
documents=splits,
|
| 60 |
+
embedding=get_embeddings(),
|
| 61 |
+
persist_directory="./chroma_db"
|
| 62 |
+
)
|
| 63 |
+
|
| 64 |
+
# Use description and field to retrieve relevant chunks
|
| 65 |
+
query = f"Field: {field}. Task: {description}"
|
| 66 |
+
retriever = vectorstore.as_retriever(search_kwargs={"k": 5})
|
| 67 |
+
|
| 68 |
+
retrieved_docs = retriever.invoke(query)
|
| 69 |
+
|
| 70 |
+
context = ""
|
| 71 |
+
for idx, doc in enumerate(retrieved_docs):
|
| 72 |
+
context += f"\n--- Retrieved Chunk {idx+1} from {doc.metadata.get('source', 'Unknown')} ---\n{doc.page_content}\n"
|
| 73 |
+
|
| 74 |
+
return context
|
| 75 |
+
|
| 76 |
+
def generate_task_prompt(description: str, field: str, files_data: list[dict]) -> str:
|
| 77 |
+
llm = get_llm()
|
| 78 |
+
|
| 79 |
+
# Get filtered context via RAG
|
| 80 |
+
files_context = process_and_retrieve_context(description, field, files_data)
|
| 81 |
+
|
| 82 |
+
system_prompt = (
|
| 83 |
+
"You are an expert technical project manager and architect. "
|
| 84 |
+
"Your goal is to take a task description provided by a project manager, context about the field (e.g., backend, frontend), "
|
| 85 |
+
"and any uploaded file context, and produce a high-quality, developer-ready task prompt.\n\n"
|
| 86 |
+
"Return ONLY the finalized prompt ready to be handed to a developer."
|
| 87 |
+
)
|
| 88 |
+
|
| 89 |
+
human_prompt = (
|
| 90 |
+
"Field/Domain: {field}\n"
|
| 91 |
+
"Task Description:\n{description}\n\n"
|
| 92 |
+
"Relevant Code/Files Context:\n{files_context}\n\n"
|
| 93 |
+
"Please generate a comprehensive developer prompt."
|
| 94 |
+
)
|
| 95 |
+
|
| 96 |
+
prompt = ChatPromptTemplate.from_messages([
|
| 97 |
+
("system", system_prompt),
|
| 98 |
+
("human", human_prompt),
|
| 99 |
+
])
|
| 100 |
+
|
| 101 |
+
chain = prompt | llm | StrOutputParser()
|
| 102 |
+
|
| 103 |
+
return chain.invoke({
|
| 104 |
+
"field": field,
|
| 105 |
+
"description": description,
|
| 106 |
+
"files_context": files_context
|
| 107 |
+
})
|
api.py
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastapi import FastAPI, UploadFile, File, Form
|
| 2 |
+
from typing import List, Optional
|
| 3 |
+
import uvicorn
|
| 4 |
+
from agent import generate_task_prompt
|
| 5 |
+
|
| 6 |
+
import io
|
| 7 |
+
import pypdf
|
| 8 |
+
import docx2txt
|
| 9 |
+
|
| 10 |
+
app = FastAPI(title="Task Prompting API")
|
| 11 |
+
|
| 12 |
+
@app.post("/generate_prompt")
|
| 13 |
+
async def generate_prompt(
|
| 14 |
+
description: str = Form(...),
|
| 15 |
+
field: str = Form(...),
|
| 16 |
+
files: Optional[List[UploadFile]] = File(None)
|
| 17 |
+
):
|
| 18 |
+
files_data = []
|
| 19 |
+
|
| 20 |
+
if files:
|
| 21 |
+
for file in files:
|
| 22 |
+
content = await file.read()
|
| 23 |
+
filename_lower = file.filename.lower()
|
| 24 |
+
|
| 25 |
+
try:
|
| 26 |
+
if filename_lower.endswith(".pdf"):
|
| 27 |
+
reader = pypdf.PdfReader(io.BytesIO(content))
|
| 28 |
+
text = "\n".join([page.extract_text() or "" for page in reader.pages])
|
| 29 |
+
files_data.append({"filename": file.filename, "content": text})
|
| 30 |
+
elif filename_lower.endswith(".docx"):
|
| 31 |
+
text = docx2txt.process(io.BytesIO(content))
|
| 32 |
+
files_data.append({"filename": file.filename, "content": text})
|
| 33 |
+
else:
|
| 34 |
+
decoded_content = content.decode('utf-8')
|
| 35 |
+
files_data.append({"filename": file.filename, "content": decoded_content})
|
| 36 |
+
except Exception as e:
|
| 37 |
+
print(f"Error processing {file.filename}: {e}")
|
| 38 |
+
pass # Skip files that fail encoding or extraction
|
| 39 |
+
|
| 40 |
+
try:
|
| 41 |
+
generated_prompt = generate_task_prompt(description, field, files_data)
|
| 42 |
+
return {"status": "success", "prompt": generated_prompt}
|
| 43 |
+
except Exception as e:
|
| 44 |
+
return {"status": "error", "message": str(e)}
|
| 45 |
+
|
| 46 |
+
if __name__ == "__main__":
|
| 47 |
+
uvicorn.run("api:app", host="0.0.0.0", port=8000, reload=True)
|
gradio_app.py
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
import requests
|
| 3 |
+
import os
|
| 4 |
+
|
| 5 |
+
from agent import generate_task_prompt
|
| 6 |
+
|
| 7 |
+
import pypdf
|
| 8 |
+
import docx2txt
|
| 9 |
+
|
| 10 |
+
def process_request(description, field, uploaded_files):
|
| 11 |
+
files_data = []
|
| 12 |
+
|
| 13 |
+
if uploaded_files:
|
| 14 |
+
for file_path in uploaded_files:
|
| 15 |
+
filename = os.path.basename(file_path)
|
| 16 |
+
lower_name = filename.lower()
|
| 17 |
+
try:
|
| 18 |
+
if lower_name.endswith(".pdf"):
|
| 19 |
+
reader = pypdf.PdfReader(file_path)
|
| 20 |
+
content = "\n".join([page.extract_text() or "" for page in reader.pages])
|
| 21 |
+
elif lower_name.endswith(".docx"):
|
| 22 |
+
content = docx2txt.process(file_path)
|
| 23 |
+
else:
|
| 24 |
+
with open(file_path, "r", encoding="utf-8") as f:
|
| 25 |
+
content = f.read()
|
| 26 |
+
files_data.append({"filename": filename, "content": content})
|
| 27 |
+
except Exception as e:
|
| 28 |
+
print(f"Skipping binary/unreadable file: {filename}")
|
| 29 |
+
|
| 30 |
+
try:
|
| 31 |
+
return generate_task_prompt(description, field, files_data)
|
| 32 |
+
except Exception as e:
|
| 33 |
+
return f"Error occurred: {str(e)}"
|
| 34 |
+
|
| 35 |
+
# Gradio Interface
|
| 36 |
+
with gr.Blocks(title="Task Prompting Tool") as demo:
|
| 37 |
+
gr.Markdown("# 🚀 Developer Task Prompting Tool (RAG Enabled)")
|
| 38 |
+
gr.Markdown("Generate high-quality, developer-ready prompts using advanced ChromaDB chunking for very large projects.")
|
| 39 |
+
|
| 40 |
+
with gr.Row():
|
| 41 |
+
with gr.Column(scale=2):
|
| 42 |
+
field_input = gr.Dropdown(
|
| 43 |
+
choices=["Backend", "Frontend", "Fullstack", "DevOps", "Data Science", "Mobile", "Other"],
|
| 44 |
+
label="Field / Application Area",
|
| 45 |
+
value="Backend"
|
| 46 |
+
)
|
| 47 |
+
desc_input = gr.Textbox(
|
| 48 |
+
label="Task Description",
|
| 49 |
+
placeholder="Describe what needs to be done...",
|
| 50 |
+
lines=5
|
| 51 |
+
)
|
| 52 |
+
file_input = gr.File(
|
| 53 |
+
label="Upload Context Files (Code, MD, JSON, etc.)",
|
| 54 |
+
file_count="multiple"
|
| 55 |
+
)
|
| 56 |
+
submit_btn = gr.Button("Generate Prompt", variant="primary")
|
| 57 |
+
|
| 58 |
+
with gr.Column(scale=3):
|
| 59 |
+
output_text = gr.Textbox(
|
| 60 |
+
label="Generated Task Prompt",
|
| 61 |
+
lines=15
|
| 62 |
+
)
|
| 63 |
+
|
| 64 |
+
submit_btn.click(
|
| 65 |
+
fn=process_request,
|
| 66 |
+
inputs=[desc_input, field_input, file_input],
|
| 67 |
+
outputs=output_text
|
| 68 |
+
)
|
| 69 |
+
|
| 70 |
+
if __name__ == "__main__":
|
| 71 |
+
demo.launch(server_name="0.0.0.0", server_port=7860)
|
requirements.txt
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
aiofiles==24.1.0
|
| 2 |
+
aiohappyeyeballs==2.6.1
|
| 3 |
+
aiohttp==3.13.5
|
| 4 |
+
aiosignal==1.4.0
|
| 5 |
+
annotated-doc==0.0.4
|
| 6 |
+
annotated-types==0.7.0
|
| 7 |
+
anyio==4.13.0
|
| 8 |
+
attrs==26.1.0
|
| 9 |
+
bcrypt==5.0.0
|
| 10 |
+
beautifulsoup4==4.14.3
|
| 11 |
+
brotli==1.2.0
|
| 12 |
+
bs4==0.0.2
|
| 13 |
+
build==1.4.2
|
| 14 |
+
certifi==2026.2.25
|
| 15 |
+
cffi==2.0.0
|
| 16 |
+
charset-normalizer==3.4.7
|
| 17 |
+
chromadb==1.5.5
|
| 18 |
+
click==8.3.2
|
| 19 |
+
cryptography==46.0.6
|
| 20 |
+
dataclasses-json==0.6.7
|
| 21 |
+
distro==1.9.0
|
| 22 |
+
docx2txt==0.9
|
| 23 |
+
durationpy==0.10
|
| 24 |
+
fastapi==0.135.3
|
| 25 |
+
ffmpy==1.0.0
|
| 26 |
+
filelock==3.25.2
|
| 27 |
+
filetype==1.2.0
|
| 28 |
+
flatbuffers==25.12.19
|
| 29 |
+
frozenlist==1.8.0
|
| 30 |
+
fsspec==2026.3.0
|
| 31 |
+
google-auth==2.49.1
|
| 32 |
+
google-genai==1.70.0
|
| 33 |
+
googleapis-common-protos==1.74.0
|
| 34 |
+
gradio==6.11.0
|
| 35 |
+
gradio_client==2.4.0
|
| 36 |
+
greenlet==3.3.2
|
| 37 |
+
groovy==0.1.2
|
| 38 |
+
grpcio==1.80.0
|
| 39 |
+
h11==0.16.0
|
| 40 |
+
hf-gradio==0.3.0
|
| 41 |
+
hf-xet==1.4.3
|
| 42 |
+
httpcore==1.0.9
|
| 43 |
+
httptools==0.7.1
|
| 44 |
+
httpx==0.28.1
|
| 45 |
+
httpx-sse==0.4.3
|
| 46 |
+
huggingface_hub==1.9.0
|
| 47 |
+
idna==3.11
|
| 48 |
+
importlib_metadata==8.7.1
|
| 49 |
+
importlib_resources==6.5.2
|
| 50 |
+
Jinja2==3.1.6
|
| 51 |
+
jiter==0.13.0
|
| 52 |
+
jsonpatch==1.33
|
| 53 |
+
jsonpointer==3.1.1
|
| 54 |
+
jsonschema==4.26.0
|
| 55 |
+
jsonschema-specifications==2025.9.1
|
| 56 |
+
kubernetes==35.0.0
|
| 57 |
+
langchain==1.2.15
|
| 58 |
+
langchain-classic==1.0.3
|
| 59 |
+
langchain-community==0.4.1
|
| 60 |
+
langchain-core==1.2.25
|
| 61 |
+
langchain-google-genai==4.2.1
|
| 62 |
+
langchain-openai==1.1.12
|
| 63 |
+
langchain-text-splitters==1.1.1
|
| 64 |
+
langgraph==1.1.6
|
| 65 |
+
langgraph-checkpoint==4.0.1
|
| 66 |
+
langgraph-prebuilt==1.0.9
|
| 67 |
+
langgraph-sdk==0.3.12
|
| 68 |
+
langsmith==0.7.25
|
| 69 |
+
markdown-it-py==4.0.0
|
| 70 |
+
MarkupSafe==3.0.3
|
| 71 |
+
marshmallow==3.26.2
|
| 72 |
+
mdurl==0.1.2
|
| 73 |
+
mmh3==5.2.1
|
| 74 |
+
mpmath==1.3.0
|
| 75 |
+
multidict==6.7.1
|
| 76 |
+
mypy_extensions==1.1.0
|
| 77 |
+
numpy==2.4.4
|
| 78 |
+
oauthlib==3.3.1
|
| 79 |
+
onnxruntime==1.24.4
|
| 80 |
+
openai==2.30.0
|
| 81 |
+
opentelemetry-api==1.40.0
|
| 82 |
+
opentelemetry-exporter-otlp-proto-common==1.40.0
|
| 83 |
+
opentelemetry-exporter-otlp-proto-grpc==1.40.0
|
| 84 |
+
opentelemetry-proto==1.40.0
|
| 85 |
+
opentelemetry-sdk==1.40.0
|
| 86 |
+
opentelemetry-semantic-conventions==0.61b0
|
| 87 |
+
orjson==3.11.8
|
| 88 |
+
ormsgpack==1.12.2
|
| 89 |
+
overrides==7.7.0
|
| 90 |
+
packaging==26.0
|
| 91 |
+
pandas==3.0.2
|
| 92 |
+
pillow==12.2.0
|
| 93 |
+
propcache==0.4.1
|
| 94 |
+
protobuf==6.33.6
|
| 95 |
+
pyasn1==0.6.3
|
| 96 |
+
pyasn1_modules==0.4.2
|
| 97 |
+
pybase64==1.4.3
|
| 98 |
+
pycparser==3.0
|
| 99 |
+
pydantic==2.12.5
|
| 100 |
+
pydantic-settings==2.13.1
|
| 101 |
+
pydantic_core==2.41.5
|
| 102 |
+
pydub==0.25.1
|
| 103 |
+
Pygments==2.20.0
|
| 104 |
+
pypdf==6.9.2
|
| 105 |
+
PyPika==0.51.1
|
| 106 |
+
pyproject_hooks==1.2.0
|
| 107 |
+
python-dateutil==2.9.0.post0
|
| 108 |
+
python-dotenv==1.2.2
|
| 109 |
+
python-multipart==0.0.22
|
| 110 |
+
pytz==2026.1.post1
|
| 111 |
+
PyYAML==6.0.3
|
| 112 |
+
referencing==0.37.0
|
| 113 |
+
regex==2026.3.32
|
| 114 |
+
requests==2.33.1
|
| 115 |
+
requests-oauthlib==2.0.0
|
| 116 |
+
requests-toolbelt==1.0.0
|
| 117 |
+
rich==14.3.3
|
| 118 |
+
rpds-py==0.30.0
|
| 119 |
+
safehttpx==0.1.7
|
| 120 |
+
semantic-version==2.10.0
|
| 121 |
+
shellingham==1.5.4
|
| 122 |
+
six==1.17.0
|
| 123 |
+
sniffio==1.3.1
|
| 124 |
+
soupsieve==2.8.3
|
| 125 |
+
SQLAlchemy==2.0.49
|
| 126 |
+
starlette==1.0.0
|
| 127 |
+
sympy==1.14.0
|
| 128 |
+
tenacity==9.1.4
|
| 129 |
+
tiktoken==0.12.0
|
| 130 |
+
tokenizers==0.22.2
|
| 131 |
+
tomlkit==0.13.3
|
| 132 |
+
tqdm==4.67.3
|
| 133 |
+
typer==0.24.1
|
| 134 |
+
typing-inspect==0.9.0
|
| 135 |
+
typing-inspection==0.4.2
|
| 136 |
+
typing_extensions==4.15.0
|
| 137 |
+
urllib3==2.6.3
|
| 138 |
+
uuid_utils==0.14.1
|
| 139 |
+
uvicorn==0.43.0
|
| 140 |
+
uvloop==0.22.1
|
| 141 |
+
watchfiles==1.1.1
|
| 142 |
+
websocket-client==1.9.0
|
| 143 |
+
websockets==16.0
|
| 144 |
+
xxhash==3.6.0
|
| 145 |
+
yarl==1.23.0
|
| 146 |
+
zipp==3.23.0
|
| 147 |
+
zstandard==0.25.0
|