refactor and setup langgraph flow
Browse files- src/chatbot/form_management/acceptance_criteria.json +32 -0
- src/chatbot/form_management/form_management.py +89 -0
- src/chatbot/graph.png +0 -0
- src/chatbot/graph_manager.py +27 -7
- src/chatbot/nodes.py +62 -14
- src/{vlm → chatbot/vlm}/kie.py +6 -5
- src/{vlm → chatbot/vlm}/prompts.py +0 -0
- src/poetry.lock +250 -3
- src/pyproject.toml +2 -1
- src/utils/utils.py +0 -0
src/chatbot/form_management/acceptance_criteria.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"fields": [
|
| 3 |
+
{
|
| 4 |
+
"fieldName": "Project Name",
|
| 5 |
+
"priority": 1,
|
| 6 |
+
"description": "The name of the project or purpose for the payment.",
|
| 7 |
+
"validationRules": [
|
| 8 |
+
"Must be associated with environmental or sustainability projects."
|
| 9 |
+
],
|
| 10 |
+
"exampleInput": "โครงการ \"การจัดการคาร์บอนเครดิตในป่าเพื่อการพัฒนาที่ยั่งยืน\""
|
| 11 |
+
},
|
| 12 |
+
{
|
| 13 |
+
"fieldName": "Date",
|
| 14 |
+
"priority": 2,
|
| 15 |
+
"description": "The date of the transaction.",
|
| 16 |
+
"validationRules": [
|
| 17 |
+
"Must be a date that is in the past or present."
|
| 18 |
+
],
|
| 19 |
+
"exampleInput": "3 เมษายน 2567"
|
| 20 |
+
},
|
| 21 |
+
{
|
| 22 |
+
"fieldName": "Total Payment Amount",
|
| 23 |
+
"priority": 3,
|
| 24 |
+
"description": "The total amount paid.",
|
| 25 |
+
"validationRules": [
|
| 26 |
+
"Must be a positive amount."
|
| 27 |
+
],
|
| 28 |
+
"exampleInput": "3 เมษายน 2567"
|
| 29 |
+
}
|
| 30 |
+
]
|
| 31 |
+
}
|
| 32 |
+
|
src/chatbot/form_management/form_management.py
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
class Form:
|
| 2 |
+
class PaymentDetailsTable:
|
| 3 |
+
def __init__(self, column_headers = None, row_entries = None):
|
| 4 |
+
self.column_headers = column_headers
|
| 5 |
+
self.row_entries = row_entries
|
| 6 |
+
|
| 7 |
+
def __init__(self, receipt_title = None, project_name = None, date = None, receipt_number = None, payer_name = None, column_headers = None, row_entries = None, total_payment_amount = None, incompleteness_description = None):
|
| 8 |
+
self.receipt_title = receipt_title
|
| 9 |
+
self.project_name = project_name
|
| 10 |
+
self.date = date
|
| 11 |
+
self.receipt_number = receipt_number
|
| 12 |
+
self.payer_name = payer_name
|
| 13 |
+
self.payment_details_table = self.PaymentDetailsTable(column_headers, row_entries)
|
| 14 |
+
self.total_payment_amount = total_payment_amount
|
| 15 |
+
self.incompleteness_description = incompleteness_description
|
| 16 |
+
|
| 17 |
+
def get_info_as_dict(self):
|
| 18 |
+
return {
|
| 19 |
+
"receipt_title": self.receipt_title,
|
| 20 |
+
"project_name": self.project_name,
|
| 21 |
+
"date": self.date,
|
| 22 |
+
"receipt_number": self.receipt_number,
|
| 23 |
+
"payer_name": self.payer_name,
|
| 24 |
+
"payment_details_table": {
|
| 25 |
+
"column_headers": self.payment_details_table.column_headers,
|
| 26 |
+
"row_entries": self.payment_details_table.row_entries
|
| 27 |
+
},
|
| 28 |
+
"total_payment_amount": self.total_payment_amount,
|
| 29 |
+
"incompleteness_description": self.incompleteness_description
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
# Getter and Setter for receipt_title
|
| 33 |
+
def get_receipt_title(self):
|
| 34 |
+
return self.receipt_title
|
| 35 |
+
|
| 36 |
+
def set_receipt_title(self, receipt_title):
|
| 37 |
+
self.receipt_title = receipt_title
|
| 38 |
+
|
| 39 |
+
# Getter and Setter for project_name
|
| 40 |
+
def get_project_name(self):
|
| 41 |
+
return self.project_name
|
| 42 |
+
|
| 43 |
+
def set_project_name(self, project_name):
|
| 44 |
+
self.project_name = project_name
|
| 45 |
+
|
| 46 |
+
# Getter and Setter for date
|
| 47 |
+
def get_date(self):
|
| 48 |
+
return self.date
|
| 49 |
+
|
| 50 |
+
def set_date(self, date):
|
| 51 |
+
self.date = date
|
| 52 |
+
|
| 53 |
+
# Getter and Setter for receipt_number
|
| 54 |
+
def get_receipt_number(self):
|
| 55 |
+
return self.receipt_number
|
| 56 |
+
|
| 57 |
+
def set_receipt_number(self, receipt_number):
|
| 58 |
+
self.receipt_number = receipt_number
|
| 59 |
+
|
| 60 |
+
# Getter and Setter for payer_name
|
| 61 |
+
def get_payer_name(self):
|
| 62 |
+
return self.payer_name
|
| 63 |
+
|
| 64 |
+
def set_payer_name(self, payer_name):
|
| 65 |
+
self.payer_name = payer_name
|
| 66 |
+
|
| 67 |
+
# Getter and Setter for payment_details_table
|
| 68 |
+
def get_payment_details_table(self):
|
| 69 |
+
return self.payment_details_table
|
| 70 |
+
|
| 71 |
+
def set_payment_details_table(self, payment_details_table):
|
| 72 |
+
self.payment_details_table = self.PaymentDetailsTable(**payment_details_table)
|
| 73 |
+
|
| 74 |
+
# Getter and Setter for total_payment_amount
|
| 75 |
+
def get_total_payment_amount(self):
|
| 76 |
+
return self.total_payment_amount
|
| 77 |
+
|
| 78 |
+
def set_total_payment_amount(self, total_payment_amount):
|
| 79 |
+
self.total_payment_amount = total_payment_amount
|
| 80 |
+
|
| 81 |
+
# Getter and Setter for incompleteness_description
|
| 82 |
+
def get_incompleteness_description(self):
|
| 83 |
+
return self.incompleteness_description
|
| 84 |
+
|
| 85 |
+
def set_incompleteness_description(self, incompleteness_description):
|
| 86 |
+
self.incompleteness_description = incompleteness_description
|
| 87 |
+
|
| 88 |
+
# # Example Usage
|
| 89 |
+
# form = Form()
|
src/chatbot/graph.png
ADDED
|
src/chatbot/graph_manager.py
CHANGED
|
@@ -5,10 +5,13 @@ from langgraph.graph import StateGraph, START, END
|
|
| 5 |
from langgraph.checkpoint.memory import MemorySaver
|
| 6 |
from nodes import (
|
| 7 |
State,
|
| 8 |
-
|
|
|
|
| 9 |
)
|
|
|
|
| 10 |
from form_management.form_management import Form
|
| 11 |
import sys
|
|
|
|
| 12 |
|
| 13 |
class GraphManager:
|
| 14 |
def __init__(self):
|
|
@@ -22,13 +25,29 @@ class GraphManager:
|
|
| 22 |
graph_memory = MemorySaver()
|
| 23 |
graph_builder = StateGraph(State)
|
| 24 |
|
| 25 |
-
graph_builder.add_node("speaker_chatbot",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
|
| 27 |
graph_builder.add_edge(START, "speaker_chatbot")
|
| 28 |
graph_builder.add_edge("speaker_chatbot", END)
|
| 29 |
|
| 30 |
self.graph = graph_builder.compile(checkpointer=graph_memory)
|
| 31 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
def process_user_input(self, user_input, session_id):
|
| 33 |
"""
|
| 34 |
Process the user input and update the graph state.
|
|
@@ -51,9 +70,10 @@ class GraphManager:
|
|
| 51 |
return snapshot[0]["messages"][-1].content
|
| 52 |
|
| 53 |
graph_manager = GraphManager()
|
|
|
|
| 54 |
|
| 55 |
-
# Example usage
|
| 56 |
-
response = graph_manager.process_user_input(
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
)
|
|
|
|
| 5 |
from langgraph.checkpoint.memory import MemorySaver
|
| 6 |
from nodes import (
|
| 7 |
State,
|
| 8 |
+
speaker_chatbot_node,
|
| 9 |
+
tool_node
|
| 10 |
)
|
| 11 |
+
from langgraph.prebuilt import tools_condition
|
| 12 |
from form_management.form_management import Form
|
| 13 |
import sys
|
| 14 |
+
from IPython.display import Image, display
|
| 15 |
|
| 16 |
class GraphManager:
|
| 17 |
def __init__(self):
|
|
|
|
| 25 |
graph_memory = MemorySaver()
|
| 26 |
graph_builder = StateGraph(State)
|
| 27 |
|
| 28 |
+
graph_builder.add_node("speaker_chatbot", speaker_chatbot_node)
|
| 29 |
+
graph_builder.add_node("tools", tool_node)
|
| 30 |
+
|
| 31 |
+
graph_builder.add_conditional_edges(
|
| 32 |
+
"speaker_chatbot",
|
| 33 |
+
tools_condition,
|
| 34 |
+
)
|
| 35 |
+
# Any time a tool is called, we return to the chatbot to decide the next step
|
| 36 |
+
graph_builder.add_edge("tools", "speaker_chatbot")
|
| 37 |
|
| 38 |
graph_builder.add_edge(START, "speaker_chatbot")
|
| 39 |
graph_builder.add_edge("speaker_chatbot", END)
|
| 40 |
|
| 41 |
self.graph = graph_builder.compile(checkpointer=graph_memory)
|
| 42 |
|
| 43 |
+
def save_graph_image(self):
|
| 44 |
+
"""
|
| 45 |
+
Save the graph as a PNG image.
|
| 46 |
+
"""
|
| 47 |
+
image = Image(self.graph.get_graph().draw_mermaid_png())
|
| 48 |
+
with open("graph.png", "wb") as f:
|
| 49 |
+
f.write(image.data)
|
| 50 |
+
|
| 51 |
def process_user_input(self, user_input, session_id):
|
| 52 |
"""
|
| 53 |
Process the user input and update the graph state.
|
|
|
|
| 70 |
return snapshot[0]["messages"][-1].content
|
| 71 |
|
| 72 |
graph_manager = GraphManager()
|
| 73 |
+
graph_manager.save_graph_image()
|
| 74 |
|
| 75 |
+
# # Example usage
|
| 76 |
+
# response = graph_manager.process_user_input(
|
| 77 |
+
# "hi",
|
| 78 |
+
# 1
|
| 79 |
+
# )
|
src/chatbot/nodes.py
CHANGED
|
@@ -4,28 +4,77 @@ from typing import Annotated
|
|
| 4 |
from typing_extensions import TypedDict
|
| 5 |
from langgraph.graph.message import add_messages
|
| 6 |
from langchain.tools import tool
|
| 7 |
-
from langgraph.prebuilt import create_react_agent
|
| 8 |
from langgraph.checkpoint.memory import MemorySaver
|
| 9 |
|
| 10 |
from agent_llm_engine import llm_overall_agent
|
| 11 |
from prompts.agent_prompts import speaker_system_message, auditor_system_message
|
| 12 |
from form_management.form_management import Form
|
|
|
|
|
|
|
| 13 |
|
| 14 |
-
# placeholder form
|
| 15 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
|
| 17 |
class State(TypedDict):
|
| 18 |
messages: Annotated[list, add_messages]
|
| 19 |
session_id: str
|
|
|
|
| 20 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
@tool
|
| 22 |
-
def
|
| 23 |
"""
|
| 24 |
-
|
|
|
|
|
|
|
| 25 |
"""
|
| 26 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
|
| 28 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
|
| 30 |
speaker_memory = MemorySaver()
|
| 31 |
speaker_agent = create_react_agent(
|
|
@@ -35,7 +84,7 @@ speaker_agent = create_react_agent(
|
|
| 35 |
checkpointer=speaker_memory
|
| 36 |
)
|
| 37 |
|
| 38 |
-
def
|
| 39 |
config = {"configurable": {"thread_id": state["session_id"]}}
|
| 40 |
|
| 41 |
response = speaker_agent.invoke(
|
|
@@ -54,6 +103,8 @@ def speaker_chatbot(state: State):
|
|
| 54 |
"session_id": state["session_id"]
|
| 55 |
}
|
| 56 |
|
|
|
|
|
|
|
| 57 |
auditor_memory = MemorySaver()
|
| 58 |
auditor_agent = create_react_agent(
|
| 59 |
llm_overall_agent,
|
|
@@ -62,11 +113,8 @@ auditor_agent = create_react_agent(
|
|
| 62 |
checkpointer=speaker_memory
|
| 63 |
)
|
| 64 |
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
form_info = form.get_info_as_dict()
|
| 68 |
-
|
| 69 |
# auditor looks at form info and acceptance criteria and gives speaker feedback
|
| 70 |
|
| 71 |
-
|
| 72 |
-
pass
|
|
|
|
| 4 |
from typing_extensions import TypedDict
|
| 5 |
from langgraph.graph.message import add_messages
|
| 6 |
from langchain.tools import tool
|
| 7 |
+
from langgraph.prebuilt import create_react_agent, ToolNode
|
| 8 |
from langgraph.checkpoint.memory import MemorySaver
|
| 9 |
|
| 10 |
from agent_llm_engine import llm_overall_agent
|
| 11 |
from prompts.agent_prompts import speaker_system_message, auditor_system_message
|
| 12 |
from form_management.form_management import Form
|
| 13 |
+
from vlm.kie import receipt_kie
|
| 14 |
+
import ast
|
| 15 |
|
| 16 |
+
# placeholder, init empty form info
|
| 17 |
+
form_info = {
|
| 18 |
+
"receipt_title": "",
|
| 19 |
+
"project_name": "",
|
| 20 |
+
"date": "",
|
| 21 |
+
"receipt_number": "",
|
| 22 |
+
"payer_name": "",
|
| 23 |
+
"payment_details_table": {
|
| 24 |
+
"column_headers": "",
|
| 25 |
+
"row_entries": "",
|
| 26 |
+
},
|
| 27 |
+
"total_payment_amount": "",
|
| 28 |
+
"incompleteness_description": ""
|
| 29 |
+
}
|
| 30 |
|
| 31 |
class State(TypedDict):
|
| 32 |
messages: Annotated[list, add_messages]
|
| 33 |
session_id: str
|
| 34 |
+
form_info: dict
|
| 35 |
|
| 36 |
+
# @tool
|
| 37 |
+
# def placeholder_tool(input: str) -> str:
|
| 38 |
+
# """
|
| 39 |
+
# Placeholder tool that does nothing.
|
| 40 |
+
# """
|
| 41 |
+
# return "This is a placeholder tool."
|
| 42 |
+
|
| 43 |
+
# session_id: str might need to be added later when there are concurrent users
|
| 44 |
@tool
|
| 45 |
+
def apply_ocr(input: str) -> str:
|
| 46 |
"""
|
| 47 |
+
Apply optical-character-recognition (OCR) to the base64 string (input image) and initalize the form.
|
| 48 |
+
Feedback will then be provided on whether the form is complete or not.
|
| 49 |
+
Use this when the user provides a base64 string.
|
| 50 |
"""
|
| 51 |
+
kie_info = receipt_kie(input)
|
| 52 |
+
# overwrite form with kie info
|
| 53 |
+
try:
|
| 54 |
+
form_info = ast.literal_eval(kie_info)
|
| 55 |
+
except:
|
| 56 |
+
print("KIE ERROR")
|
| 57 |
+
|
| 58 |
+
feedback = auditor_feedback(form_info)
|
| 59 |
+
|
| 60 |
+
return feedback
|
| 61 |
|
| 62 |
+
@tool
|
| 63 |
+
def edit_form(key: str, value: str) -> str:
|
| 64 |
+
"""
|
| 65 |
+
This is used to edit the form data.
|
| 66 |
+
The target field will be assigned with the provided value.
|
| 67 |
+
Feedback will then be provided on whether the form is complete or not.
|
| 68 |
+
Use this when the user wants to edit the form data.
|
| 69 |
+
"""
|
| 70 |
+
|
| 71 |
+
form_info[key] = value
|
| 72 |
+
feedback = auditor_feedback(form_info)
|
| 73 |
+
|
| 74 |
+
return feedback
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
tools = [apply_ocr, edit_form]
|
| 78 |
|
| 79 |
speaker_memory = MemorySaver()
|
| 80 |
speaker_agent = create_react_agent(
|
|
|
|
| 84 |
checkpointer=speaker_memory
|
| 85 |
)
|
| 86 |
|
| 87 |
+
def speaker_chatbot_node(state: State):
|
| 88 |
config = {"configurable": {"thread_id": state["session_id"]}}
|
| 89 |
|
| 90 |
response = speaker_agent.invoke(
|
|
|
|
| 103 |
"session_id": state["session_id"]
|
| 104 |
}
|
| 105 |
|
| 106 |
+
tool_node = ToolNode(tools=[apply_ocr, edit_form])
|
| 107 |
+
|
| 108 |
auditor_memory = MemorySaver()
|
| 109 |
auditor_agent = create_react_agent(
|
| 110 |
llm_overall_agent,
|
|
|
|
| 113 |
checkpointer=speaker_memory
|
| 114 |
)
|
| 115 |
|
| 116 |
+
# provides feedback based on form info
|
| 117 |
+
def auditor_feedback(form_info):
|
|
|
|
|
|
|
| 118 |
# auditor looks at form info and acceptance criteria and gives speaker feedback
|
| 119 |
|
| 120 |
+
return "Form is complete."
|
|
|
src/{vlm → chatbot/vlm}/kie.py
RENAMED
|
@@ -6,8 +6,8 @@ import openai
|
|
| 6 |
import base64
|
| 7 |
from dotenv import load_dotenv
|
| 8 |
import os
|
| 9 |
-
from prompts import kie_prompt
|
| 10 |
-
|
| 11 |
# Load environment variables from .env file
|
| 12 |
load_dotenv()
|
| 13 |
client = openai.OpenAI()
|
|
@@ -47,6 +47,7 @@ def receipt_kie(image_path: str) -> str:
|
|
| 47 |
|
| 48 |
return response.output_text
|
| 49 |
|
| 50 |
-
# test case
|
| 51 |
-
res = receipt_kie(r"C:\Users\Gavin\Desktop\hello-earth\data\jpeg_raw_data\bill\กองทุนพัฒนาบ้านห้วยทราย อ.แม่ออน จ.เชียงใหม่_page-0004.jpg")
|
| 52 |
-
|
|
|
|
|
|
| 6 |
import base64
|
| 7 |
from dotenv import load_dotenv
|
| 8 |
import os
|
| 9 |
+
from vlm.prompts import kie_prompt
|
| 10 |
+
import ast
|
| 11 |
# Load environment variables from .env file
|
| 12 |
load_dotenv()
|
| 13 |
client = openai.OpenAI()
|
|
|
|
| 47 |
|
| 48 |
return response.output_text
|
| 49 |
|
| 50 |
+
# # test case
|
| 51 |
+
# res = receipt_kie(r"C:\Users\Gavin\Desktop\hello-earth\data\jpeg_raw_data\bill\กองทุนพัฒนาบ้านห้วยทราย อ.แม่ออน จ.เชียงใหม่_page-0004.jpg")
|
| 52 |
+
# res = ast.literal_eval(res)
|
| 53 |
+
# print(res)
|
src/{vlm → chatbot/vlm}/prompts.py
RENAMED
|
File without changes
|
src/poetry.lock
CHANGED
|
@@ -46,6 +46,22 @@ doc = ["Sphinx (>=8.2,<9.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)",
|
|
| 46 |
test = ["anyio[trio]", "blockbuster (>=1.5.23)", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1) ; python_version >= \"3.10\"", "uvloop (>=0.21) ; platform_python_implementation == \"CPython\" and platform_system != \"Windows\" and python_version < \"3.14\""]
|
| 47 |
trio = ["trio (>=0.26.1)"]
|
| 48 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
[[package]]
|
| 50 |
name = "audioop-lts"
|
| 51 |
version = "0.2.1"
|
|
@@ -308,12 +324,24 @@ description = "Cross-platform colored terminal text."
|
|
| 308 |
optional = false
|
| 309 |
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
| 310 |
groups = ["main"]
|
| 311 |
-
markers = "platform_system == \"Windows\""
|
| 312 |
files = [
|
| 313 |
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
|
| 314 |
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
| 315 |
]
|
| 316 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 317 |
[[package]]
|
| 318 |
name = "distro"
|
| 319 |
version = "1.9.0"
|
|
@@ -340,6 +368,21 @@ files = [
|
|
| 340 |
[package.dependencies]
|
| 341 |
python-dotenv = "*"
|
| 342 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 343 |
[[package]]
|
| 344 |
name = "fastapi"
|
| 345 |
version = "0.115.12"
|
|
@@ -692,6 +735,73 @@ files = [
|
|
| 692 |
[package.extras]
|
| 693 |
all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"]
|
| 694 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 695 |
[[package]]
|
| 696 |
name = "jinja2"
|
| 697 |
version = "3.1.6"
|
|
@@ -1108,6 +1218,21 @@ files = [
|
|
| 1108 |
{file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"},
|
| 1109 |
]
|
| 1110 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1111 |
[[package]]
|
| 1112 |
name = "mdurl"
|
| 1113 |
version = "0.1.2"
|
|
@@ -1441,6 +1566,38 @@ sql-other = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-d
|
|
| 1441 |
test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)"]
|
| 1442 |
xml = ["lxml (>=4.9.2)"]
|
| 1443 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1444 |
[[package]]
|
| 1445 |
name = "pillow"
|
| 1446 |
version = "11.2.1"
|
|
@@ -1541,6 +1698,49 @@ tests = ["check-manifest", "coverage (>=7.4.2)", "defusedxml", "markdown2", "ole
|
|
| 1541 |
typing = ["typing-extensions ; python_version < \"3.10\""]
|
| 1542 |
xmp = ["defusedxml"]
|
| 1543 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1544 |
[[package]]
|
| 1545 |
name = "pycparser"
|
| 1546 |
version = "2.22"
|
|
@@ -1707,7 +1907,6 @@ description = "Pygments is a syntax highlighting package written in Python."
|
|
| 1707 |
optional = false
|
| 1708 |
python-versions = ">=3.8"
|
| 1709 |
groups = ["main"]
|
| 1710 |
-
markers = "sys_platform != \"emscripten\""
|
| 1711 |
files = [
|
| 1712 |
{file = "pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"},
|
| 1713 |
{file = "pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f"},
|
|
@@ -2190,6 +2389,26 @@ postgresql-psycopgbinary = ["psycopg[binary] (>=3.0.7)"]
|
|
| 2190 |
pymysql = ["pymysql"]
|
| 2191 |
sqlcipher = ["sqlcipher3_binary"]
|
| 2192 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2193 |
[[package]]
|
| 2194 |
name = "starlette"
|
| 2195 |
version = "0.46.2"
|
|
@@ -2306,6 +2525,22 @@ notebook = ["ipywidgets (>=6)"]
|
|
| 2306 |
slack = ["slack-sdk"]
|
| 2307 |
telegram = ["requests"]
|
| 2308 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2309 |
[[package]]
|
| 2310 |
name = "typer"
|
| 2311 |
version = "0.15.3"
|
|
@@ -2402,6 +2637,18 @@ h11 = ">=0.8"
|
|
| 2402 |
[package.extras]
|
| 2403 |
standard = ["colorama (>=0.4) ; sys_platform == \"win32\"", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1) ; sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\"", "watchfiles (>=0.13)", "websockets (>=10.4)"]
|
| 2404 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2405 |
[[package]]
|
| 2406 |
name = "websockets"
|
| 2407 |
version = "15.0.1"
|
|
@@ -2730,4 +2977,4 @@ cffi = ["cffi (>=1.11)"]
|
|
| 2730 |
[metadata]
|
| 2731 |
lock-version = "2.1"
|
| 2732 |
python-versions = ">=3.12.4,<4.0.0"
|
| 2733 |
-
content-hash = "
|
|
|
|
| 46 |
test = ["anyio[trio]", "blockbuster (>=1.5.23)", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1) ; python_version >= \"3.10\"", "uvloop (>=0.21) ; platform_python_implementation == \"CPython\" and platform_system != \"Windows\" and python_version < \"3.14\""]
|
| 47 |
trio = ["trio (>=0.26.1)"]
|
| 48 |
|
| 49 |
+
[[package]]
|
| 50 |
+
name = "asttokens"
|
| 51 |
+
version = "3.0.0"
|
| 52 |
+
description = "Annotate AST trees with source code positions"
|
| 53 |
+
optional = false
|
| 54 |
+
python-versions = ">=3.8"
|
| 55 |
+
groups = ["main"]
|
| 56 |
+
files = [
|
| 57 |
+
{file = "asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2"},
|
| 58 |
+
{file = "asttokens-3.0.0.tar.gz", hash = "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7"},
|
| 59 |
+
]
|
| 60 |
+
|
| 61 |
+
[package.extras]
|
| 62 |
+
astroid = ["astroid (>=2,<4)"]
|
| 63 |
+
test = ["astroid (>=2,<4)", "pytest", "pytest-cov", "pytest-xdist"]
|
| 64 |
+
|
| 65 |
[[package]]
|
| 66 |
name = "audioop-lts"
|
| 67 |
version = "0.2.1"
|
|
|
|
| 324 |
optional = false
|
| 325 |
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
| 326 |
groups = ["main"]
|
| 327 |
+
markers = "platform_system == \"Windows\" or sys_platform == \"win32\""
|
| 328 |
files = [
|
| 329 |
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
|
| 330 |
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
| 331 |
]
|
| 332 |
|
| 333 |
+
[[package]]
|
| 334 |
+
name = "decorator"
|
| 335 |
+
version = "5.2.1"
|
| 336 |
+
description = "Decorators for Humans"
|
| 337 |
+
optional = false
|
| 338 |
+
python-versions = ">=3.8"
|
| 339 |
+
groups = ["main"]
|
| 340 |
+
files = [
|
| 341 |
+
{file = "decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a"},
|
| 342 |
+
{file = "decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360"},
|
| 343 |
+
]
|
| 344 |
+
|
| 345 |
[[package]]
|
| 346 |
name = "distro"
|
| 347 |
version = "1.9.0"
|
|
|
|
| 368 |
[package.dependencies]
|
| 369 |
python-dotenv = "*"
|
| 370 |
|
| 371 |
+
[[package]]
|
| 372 |
+
name = "executing"
|
| 373 |
+
version = "2.2.0"
|
| 374 |
+
description = "Get the currently executing AST node of a frame, and other information"
|
| 375 |
+
optional = false
|
| 376 |
+
python-versions = ">=3.8"
|
| 377 |
+
groups = ["main"]
|
| 378 |
+
files = [
|
| 379 |
+
{file = "executing-2.2.0-py2.py3-none-any.whl", hash = "sha256:11387150cad388d62750327a53d3339fad4888b39a6fe233c3afbb54ecffd3aa"},
|
| 380 |
+
{file = "executing-2.2.0.tar.gz", hash = "sha256:5d108c028108fe2551d1a7b2e8b713341e2cb4fc0aa7dcf966fa4327a5226755"},
|
| 381 |
+
]
|
| 382 |
+
|
| 383 |
+
[package.extras]
|
| 384 |
+
tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich ; python_version >= \"3.11\""]
|
| 385 |
+
|
| 386 |
[[package]]
|
| 387 |
name = "fastapi"
|
| 388 |
version = "0.115.12"
|
|
|
|
| 735 |
[package.extras]
|
| 736 |
all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"]
|
| 737 |
|
| 738 |
+
[[package]]
|
| 739 |
+
name = "ipython"
|
| 740 |
+
version = "9.2.0"
|
| 741 |
+
description = "IPython: Productive Interactive Computing"
|
| 742 |
+
optional = false
|
| 743 |
+
python-versions = ">=3.11"
|
| 744 |
+
groups = ["main"]
|
| 745 |
+
files = [
|
| 746 |
+
{file = "ipython-9.2.0-py3-none-any.whl", hash = "sha256:fef5e33c4a1ae0759e0bba5917c9db4eb8c53fee917b6a526bd973e1ca5159f6"},
|
| 747 |
+
{file = "ipython-9.2.0.tar.gz", hash = "sha256:62a9373dbc12f28f9feaf4700d052195bf89806279fc8ca11f3f54017d04751b"},
|
| 748 |
+
]
|
| 749 |
+
|
| 750 |
+
[package.dependencies]
|
| 751 |
+
colorama = {version = "*", markers = "sys_platform == \"win32\""}
|
| 752 |
+
decorator = "*"
|
| 753 |
+
ipython-pygments-lexers = "*"
|
| 754 |
+
jedi = ">=0.16"
|
| 755 |
+
matplotlib-inline = "*"
|
| 756 |
+
pexpect = {version = ">4.3", markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\""}
|
| 757 |
+
prompt_toolkit = ">=3.0.41,<3.1.0"
|
| 758 |
+
pygments = ">=2.4.0"
|
| 759 |
+
stack_data = "*"
|
| 760 |
+
traitlets = ">=5.13.0"
|
| 761 |
+
|
| 762 |
+
[package.extras]
|
| 763 |
+
all = ["ipython[doc,matplotlib,test,test-extra]"]
|
| 764 |
+
black = ["black"]
|
| 765 |
+
doc = ["docrepr", "exceptiongroup", "intersphinx_registry", "ipykernel", "ipython[test]", "matplotlib", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "sphinx_toml (==0.0.4)", "typing_extensions"]
|
| 766 |
+
matplotlib = ["matplotlib"]
|
| 767 |
+
test = ["packaging", "pytest", "pytest-asyncio (<0.22)", "testpath"]
|
| 768 |
+
test-extra = ["curio", "ipykernel", "ipython[test]", "jupyter_ai", "matplotlib (!=3.2.0)", "nbclient", "nbformat", "numpy (>=1.23)", "pandas", "trio"]
|
| 769 |
+
|
| 770 |
+
[[package]]
|
| 771 |
+
name = "ipython-pygments-lexers"
|
| 772 |
+
version = "1.1.1"
|
| 773 |
+
description = "Defines a variety of Pygments lexers for highlighting IPython code."
|
| 774 |
+
optional = false
|
| 775 |
+
python-versions = ">=3.8"
|
| 776 |
+
groups = ["main"]
|
| 777 |
+
files = [
|
| 778 |
+
{file = "ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c"},
|
| 779 |
+
{file = "ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81"},
|
| 780 |
+
]
|
| 781 |
+
|
| 782 |
+
[package.dependencies]
|
| 783 |
+
pygments = "*"
|
| 784 |
+
|
| 785 |
+
[[package]]
|
| 786 |
+
name = "jedi"
|
| 787 |
+
version = "0.19.2"
|
| 788 |
+
description = "An autocompletion tool for Python that can be used for text editors."
|
| 789 |
+
optional = false
|
| 790 |
+
python-versions = ">=3.6"
|
| 791 |
+
groups = ["main"]
|
| 792 |
+
files = [
|
| 793 |
+
{file = "jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9"},
|
| 794 |
+
{file = "jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0"},
|
| 795 |
+
]
|
| 796 |
+
|
| 797 |
+
[package.dependencies]
|
| 798 |
+
parso = ">=0.8.4,<0.9.0"
|
| 799 |
+
|
| 800 |
+
[package.extras]
|
| 801 |
+
docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"]
|
| 802 |
+
qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"]
|
| 803 |
+
testing = ["Django", "attrs", "colorama", "docopt", "pytest (<9.0.0)"]
|
| 804 |
+
|
| 805 |
[[package]]
|
| 806 |
name = "jinja2"
|
| 807 |
version = "3.1.6"
|
|
|
|
| 1218 |
{file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"},
|
| 1219 |
]
|
| 1220 |
|
| 1221 |
+
[[package]]
|
| 1222 |
+
name = "matplotlib-inline"
|
| 1223 |
+
version = "0.1.7"
|
| 1224 |
+
description = "Inline Matplotlib backend for Jupyter"
|
| 1225 |
+
optional = false
|
| 1226 |
+
python-versions = ">=3.8"
|
| 1227 |
+
groups = ["main"]
|
| 1228 |
+
files = [
|
| 1229 |
+
{file = "matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca"},
|
| 1230 |
+
{file = "matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90"},
|
| 1231 |
+
]
|
| 1232 |
+
|
| 1233 |
+
[package.dependencies]
|
| 1234 |
+
traitlets = "*"
|
| 1235 |
+
|
| 1236 |
[[package]]
|
| 1237 |
name = "mdurl"
|
| 1238 |
version = "0.1.2"
|
|
|
|
| 1566 |
test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)"]
|
| 1567 |
xml = ["lxml (>=4.9.2)"]
|
| 1568 |
|
| 1569 |
+
[[package]]
|
| 1570 |
+
name = "parso"
|
| 1571 |
+
version = "0.8.4"
|
| 1572 |
+
description = "A Python Parser"
|
| 1573 |
+
optional = false
|
| 1574 |
+
python-versions = ">=3.6"
|
| 1575 |
+
groups = ["main"]
|
| 1576 |
+
files = [
|
| 1577 |
+
{file = "parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18"},
|
| 1578 |
+
{file = "parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d"},
|
| 1579 |
+
]
|
| 1580 |
+
|
| 1581 |
+
[package.extras]
|
| 1582 |
+
qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"]
|
| 1583 |
+
testing = ["docopt", "pytest"]
|
| 1584 |
+
|
| 1585 |
+
[[package]]
|
| 1586 |
+
name = "pexpect"
|
| 1587 |
+
version = "4.9.0"
|
| 1588 |
+
description = "Pexpect allows easy control of interactive console applications."
|
| 1589 |
+
optional = false
|
| 1590 |
+
python-versions = "*"
|
| 1591 |
+
groups = ["main"]
|
| 1592 |
+
markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\""
|
| 1593 |
+
files = [
|
| 1594 |
+
{file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"},
|
| 1595 |
+
{file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"},
|
| 1596 |
+
]
|
| 1597 |
+
|
| 1598 |
+
[package.dependencies]
|
| 1599 |
+
ptyprocess = ">=0.5"
|
| 1600 |
+
|
| 1601 |
[[package]]
|
| 1602 |
name = "pillow"
|
| 1603 |
version = "11.2.1"
|
|
|
|
| 1698 |
typing = ["typing-extensions ; python_version < \"3.10\""]
|
| 1699 |
xmp = ["defusedxml"]
|
| 1700 |
|
| 1701 |
+
[[package]]
|
| 1702 |
+
name = "prompt-toolkit"
|
| 1703 |
+
version = "3.0.51"
|
| 1704 |
+
description = "Library for building powerful interactive command lines in Python"
|
| 1705 |
+
optional = false
|
| 1706 |
+
python-versions = ">=3.8"
|
| 1707 |
+
groups = ["main"]
|
| 1708 |
+
files = [
|
| 1709 |
+
{file = "prompt_toolkit-3.0.51-py3-none-any.whl", hash = "sha256:52742911fde84e2d423e2f9a4cf1de7d7ac4e51958f648d9540e0fb8db077b07"},
|
| 1710 |
+
{file = "prompt_toolkit-3.0.51.tar.gz", hash = "sha256:931a162e3b27fc90c86f1b48bb1fb2c528c2761475e57c9c06de13311c7b54ed"},
|
| 1711 |
+
]
|
| 1712 |
+
|
| 1713 |
+
[package.dependencies]
|
| 1714 |
+
wcwidth = "*"
|
| 1715 |
+
|
| 1716 |
+
[[package]]
|
| 1717 |
+
name = "ptyprocess"
|
| 1718 |
+
version = "0.7.0"
|
| 1719 |
+
description = "Run a subprocess in a pseudo terminal"
|
| 1720 |
+
optional = false
|
| 1721 |
+
python-versions = "*"
|
| 1722 |
+
groups = ["main"]
|
| 1723 |
+
markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\""
|
| 1724 |
+
files = [
|
| 1725 |
+
{file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"},
|
| 1726 |
+
{file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"},
|
| 1727 |
+
]
|
| 1728 |
+
|
| 1729 |
+
[[package]]
|
| 1730 |
+
name = "pure-eval"
|
| 1731 |
+
version = "0.2.3"
|
| 1732 |
+
description = "Safely evaluate AST nodes without side effects"
|
| 1733 |
+
optional = false
|
| 1734 |
+
python-versions = "*"
|
| 1735 |
+
groups = ["main"]
|
| 1736 |
+
files = [
|
| 1737 |
+
{file = "pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0"},
|
| 1738 |
+
{file = "pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42"},
|
| 1739 |
+
]
|
| 1740 |
+
|
| 1741 |
+
[package.extras]
|
| 1742 |
+
tests = ["pytest"]
|
| 1743 |
+
|
| 1744 |
[[package]]
|
| 1745 |
name = "pycparser"
|
| 1746 |
version = "2.22"
|
|
|
|
| 1907 |
optional = false
|
| 1908 |
python-versions = ">=3.8"
|
| 1909 |
groups = ["main"]
|
|
|
|
| 1910 |
files = [
|
| 1911 |
{file = "pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"},
|
| 1912 |
{file = "pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f"},
|
|
|
|
| 2389 |
pymysql = ["pymysql"]
|
| 2390 |
sqlcipher = ["sqlcipher3_binary"]
|
| 2391 |
|
| 2392 |
+
[[package]]
|
| 2393 |
+
name = "stack-data"
|
| 2394 |
+
version = "0.6.3"
|
| 2395 |
+
description = "Extract data from python stack frames and tracebacks for informative displays"
|
| 2396 |
+
optional = false
|
| 2397 |
+
python-versions = "*"
|
| 2398 |
+
groups = ["main"]
|
| 2399 |
+
files = [
|
| 2400 |
+
{file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"},
|
| 2401 |
+
{file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"},
|
| 2402 |
+
]
|
| 2403 |
+
|
| 2404 |
+
[package.dependencies]
|
| 2405 |
+
asttokens = ">=2.1.0"
|
| 2406 |
+
executing = ">=1.2.0"
|
| 2407 |
+
pure-eval = "*"
|
| 2408 |
+
|
| 2409 |
+
[package.extras]
|
| 2410 |
+
tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"]
|
| 2411 |
+
|
| 2412 |
[[package]]
|
| 2413 |
name = "starlette"
|
| 2414 |
version = "0.46.2"
|
|
|
|
| 2525 |
slack = ["slack-sdk"]
|
| 2526 |
telegram = ["requests"]
|
| 2527 |
|
| 2528 |
+
[[package]]
|
| 2529 |
+
name = "traitlets"
|
| 2530 |
+
version = "5.14.3"
|
| 2531 |
+
description = "Traitlets Python configuration system"
|
| 2532 |
+
optional = false
|
| 2533 |
+
python-versions = ">=3.8"
|
| 2534 |
+
groups = ["main"]
|
| 2535 |
+
files = [
|
| 2536 |
+
{file = "traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f"},
|
| 2537 |
+
{file = "traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7"},
|
| 2538 |
+
]
|
| 2539 |
+
|
| 2540 |
+
[package.extras]
|
| 2541 |
+
docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"]
|
| 2542 |
+
test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,<8.2)", "pytest-mock", "pytest-mypy-testing"]
|
| 2543 |
+
|
| 2544 |
[[package]]
|
| 2545 |
name = "typer"
|
| 2546 |
version = "0.15.3"
|
|
|
|
| 2637 |
[package.extras]
|
| 2638 |
standard = ["colorama (>=0.4) ; sys_platform == \"win32\"", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1) ; sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\"", "watchfiles (>=0.13)", "websockets (>=10.4)"]
|
| 2639 |
|
| 2640 |
+
[[package]]
|
| 2641 |
+
name = "wcwidth"
|
| 2642 |
+
version = "0.2.13"
|
| 2643 |
+
description = "Measures the displayed width of unicode strings in a terminal"
|
| 2644 |
+
optional = false
|
| 2645 |
+
python-versions = "*"
|
| 2646 |
+
groups = ["main"]
|
| 2647 |
+
files = [
|
| 2648 |
+
{file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"},
|
| 2649 |
+
{file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"},
|
| 2650 |
+
]
|
| 2651 |
+
|
| 2652 |
[[package]]
|
| 2653 |
name = "websockets"
|
| 2654 |
version = "15.0.1"
|
|
|
|
| 2977 |
[metadata]
|
| 2978 |
lock-version = "2.1"
|
| 2979 |
python-versions = ">=3.12.4,<4.0.0"
|
| 2980 |
+
content-hash = "efbddde7effbf9adb8d0fd2294ffca2d5f4460bf12f75cfab57a0a47ca868c0e"
|
src/pyproject.toml
CHANGED
|
@@ -13,7 +13,8 @@ dependencies = [
|
|
| 13 |
"dotenv (>=0.9.9,<0.10.0)",
|
| 14 |
"langgraph (>=0.4.1,<0.5.0)",
|
| 15 |
"langchain (>=0.3.24,<0.4.0)",
|
| 16 |
-
"langchain-openai (>=0.3.14,<0.4.0)"
|
|
|
|
| 17 |
]
|
| 18 |
|
| 19 |
|
|
|
|
| 13 |
"dotenv (>=0.9.9,<0.10.0)",
|
| 14 |
"langgraph (>=0.4.1,<0.5.0)",
|
| 15 |
"langchain (>=0.3.24,<0.4.0)",
|
| 16 |
+
"langchain-openai (>=0.3.14,<0.4.0)",
|
| 17 |
+
"ipython (>=9.2.0,<10.0.0)"
|
| 18 |
]
|
| 19 |
|
| 20 |
|
src/utils/utils.py
DELETED
|
File without changes
|