simonlee-cb commited on
Commit
c55fe6a
·
1 Parent(s): 9e822e4

feat: working gradio demo

Browse files
agent.py CHANGED
@@ -1,19 +1,12 @@
1
- from openai import OpenAI
2
  import streamlit as st
3
- from typing import TypedDict, Literal, Optional
4
- from pydantic import BaseModel
5
- import base64
6
  from pydantic_ai.messages import (
7
- ModelMessage,
8
  ModelRequest,
9
  ModelResponse,
10
- SystemPromptPart,
11
  UserPromptPart,
12
  TextPart,
13
  ToolCallPart,
14
  ToolReturnPart,
15
- RetryPromptPart,
16
- ModelMessagesTypeAdapter
17
  )
18
  import asyncio
19
  from src.agents.mask_generation_agent import mask_generation_agent, ImageEditDeps
@@ -21,14 +14,22 @@ from src.hopter.client import Hopter, Environment
21
  import os
22
  from src.services.generate_mask import GenerateMaskService
23
  from dotenv import load_dotenv
24
-
25
  load_dotenv()
26
 
 
 
 
 
 
 
 
27
  hopter = Hopter(
28
  api_key=os.getenv("HOPTER_API_KEY"),
29
  environment=Environment.STAGING
30
  )
31
  mask_service = GenerateMaskService(hopter=hopter)
 
32
 
33
  class ChatMessage(TypedDict):
34
  """Format of messages sent to the browser/API."""
@@ -57,6 +58,16 @@ def display_message_part(part):
57
  with st.chat_message("assistant"):
58
  st.markdown(part.content)
59
 
 
 
 
 
 
 
 
 
 
 
60
  async def run_agent(user_input: str, image_b64: str):
61
  messages = [
62
  {
@@ -99,15 +110,10 @@ async def run_agent(user_input: str, image_b64: str):
99
  st.session_state.messages.append(
100
  ModelResponse(parts=[TextPart(content=partial_text)])
101
  )
 
102
 
103
  async def main():
104
- st.title("ChatGPT-like clone")
105
-
106
- def encode_image(uploaded_file):
107
- # Read the file directly from the UploadedFile object
108
- return base64.b64encode(uploaded_file.read()).decode("utf-8")
109
-
110
- image = st.file_uploader("Upload an image", type=["png", "jpg", "jpeg"])
111
 
112
  if "openai_model" not in st.session_state:
113
  st.session_state["openai_model"] = "gpt-4o"
@@ -118,42 +124,35 @@ async def main():
118
  if "image" not in st.session_state:
119
  st.session_state.image = None
120
 
121
- # Display all messages from the conversation so far
122
- # Each message is either a ModelRequest or ModelResponse.
123
- # We iterate over their parts to decide how to display them.
124
- for msg in st.session_state.messages:
125
- if isinstance(msg, ModelRequest) or isinstance(msg, ModelResponse):
126
- for part in msg.parts:
127
- display_message_part(part)
 
 
 
 
 
 
 
 
 
128
 
129
  # Chat input for the user
130
- user_input = st.chat_input("What would you like to edit your image?")
131
-
132
- if user_input:
133
- if image is not None:
134
- st.session_state.image = image
135
-
136
- # We append a new request to the conversation explicitly
137
  st.session_state.messages.append(
138
  ModelRequest(parts=[UserPromptPart(content=user_input)])
139
  )
140
-
141
- # Display user prompt in the UI
142
- with st.chat_message("user"):
143
- if st.session_state.image:
144
- st.image(st.session_state.image)
145
- st.markdown(user_input)
146
 
147
  # Display the assistant's partial response while streaming
148
  with st.chat_message("assistant"):
149
  # Actually run the agent now, streaming the text
150
- if st.session_state.image:
151
- image_data = encode_image(st.session_state.image)
152
- image_url = f"data:image/jpeg;base64,{image_data}"
153
- await run_agent(user_input, image_url)
154
- else:
155
- await run_agent(user_input)
156
-
157
 
158
  if __name__ == "__main__":
159
  asyncio.run(main())
 
 
1
  import streamlit as st
2
+ from typing import TypedDict, Literal
 
 
3
  from pydantic_ai.messages import (
 
4
  ModelRequest,
5
  ModelResponse,
 
6
  UserPromptPart,
7
  TextPart,
8
  ToolCallPart,
9
  ToolReturnPart,
 
 
10
  )
11
  import asyncio
12
  from src.agents.mask_generation_agent import mask_generation_agent, ImageEditDeps
 
14
  import os
15
  from src.services.generate_mask import GenerateMaskService
16
  from dotenv import load_dotenv
17
+ from src.utils import image_path_to_uri
18
  load_dotenv()
19
 
20
+ st.set_page_config(
21
+ page_title="Conversational Image Editor",
22
+ page_icon="🧊",
23
+ layout="wide",
24
+ initial_sidebar_state="collapsed"
25
+ )
26
+
27
  hopter = Hopter(
28
  api_key=os.getenv("HOPTER_API_KEY"),
29
  environment=Environment.STAGING
30
  )
31
  mask_service = GenerateMaskService(hopter=hopter)
32
+ user_msg_input_key = "input_user_msg"
33
 
34
  class ChatMessage(TypedDict):
35
  """Format of messages sent to the browser/API."""
 
58
  with st.chat_message("assistant"):
59
  st.markdown(part.content)
60
 
61
+ # tool call
62
+ elif part.part_kind == 'tool-call':
63
+ with st.chat_message("assistant"):
64
+ st.markdown(f"**{part.tool_name}**: {part.args}")
65
+
66
+ # tool return
67
+ elif part.part_kind == 'tool-return':
68
+ with st.chat_message("assistant"):
69
+ st.markdown(f"**{part.tool_name}**: {part.content}")
70
+
71
  async def run_agent(user_input: str, image_b64: str):
72
  messages = [
73
  {
 
110
  st.session_state.messages.append(
111
  ModelResponse(parts=[TextPart(content=partial_text)])
112
  )
113
+ st.rerun()
114
 
115
  async def main():
116
+ st.title("Conversational Image Editor")
 
 
 
 
 
 
117
 
118
  if "openai_model" not in st.session_state:
119
  st.session_state["openai_model"] = "gpt-4o"
 
124
  if "image" not in st.session_state:
125
  st.session_state.image = None
126
 
127
+ chat_col, image_col = st.columns(2)
128
+ with chat_col:
129
+ # Display all messages from the conversation so far
130
+ # Each message is either a ModelRequest or ModelResponse.
131
+ # We iterate over their parts to decide how to display them.
132
+ for msg in st.session_state.messages:
133
+ if isinstance(msg, ModelRequest) or isinstance(msg, ModelResponse) or isinstance(msg, ToolCallPart) or isinstance(msg, ToolReturnPart):
134
+ for part in msg.parts:
135
+ display_message_part(part)
136
+
137
+ with image_col:
138
+ st.session_state.image = st.file_uploader("Upload an image", type=["png", "jpg", "jpeg"])
139
+ if st.session_state.image:
140
+ st.image(st.session_state.image)
141
+ else:
142
+ st.write("Upload an image to get started")
143
 
144
  # Chat input for the user
145
+ user_input = st.chat_input("What would you like to edit your image?", disabled=not st.session_state.image)
146
+ if user_input and st.session_state.image:
 
 
 
 
 
147
  st.session_state.messages.append(
148
  ModelRequest(parts=[UserPromptPart(content=user_input)])
149
  )
 
 
 
 
 
 
150
 
151
  # Display the assistant's partial response while streaming
152
  with st.chat_message("assistant"):
153
  # Actually run the agent now, streaming the text
154
+ image_url = image_path_to_uri(st.session_state.image)
155
+ await run_agent(user_input, image_url)
 
 
 
 
 
156
 
157
  if __name__ == "__main__":
158
  asyncio.run(main())
app.py CHANGED
@@ -1,13 +1,9 @@
1
  from openai import OpenAI
2
  import streamlit as st
3
- import base64
4
 
5
  st.title("ChatGPT-like clone")
6
 
7
- def encode_image(uploaded_file):
8
- # Read the file directly from the UploadedFile object
9
- return base64.b64encode(uploaded_file.read()).decode("utf-8")
10
-
11
  client = OpenAI(api_key=st.secrets["OPENAI_API_KEY"])
12
  image = st.file_uploader("Upload an image", type=["png", "jpg", "jpeg"])
13
 
@@ -33,8 +29,7 @@ if prompt := st.chat_input("What is up?"):
33
  if image is not None:
34
  st.session_state.image = image
35
  if st.session_state.image:
36
- image_data = encode_image(st.session_state.image)
37
- image_url = f"data:image/jpeg;base64,{image_data}"
38
  st.session_state.messages.append({"role": "user", "content": [
39
  {"type": "text", "text": prompt},
40
  {"type": "image_url", "image_url": {"url": image_url}}
 
1
  from openai import OpenAI
2
  import streamlit as st
3
+ from src.utils import image_path_to_uri
4
 
5
  st.title("ChatGPT-like clone")
6
 
 
 
 
 
7
  client = OpenAI(api_key=st.secrets["OPENAI_API_KEY"])
8
  image = st.file_uploader("Upload an image", type=["png", "jpg", "jpeg"])
9
 
 
29
  if image is not None:
30
  st.session_state.image = image
31
  if st.session_state.image:
32
+ image_url = image_path_to_uri(st.session_state.image)
 
33
  st.session_state.messages.append({"role": "user", "content": [
34
  {"type": "text", "text": prompt},
35
  {"type": "image_url", "image_url": {"url": image_url}}
gradio_app.py ADDED
@@ -0,0 +1,162 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from src.agents.mask_generation_agent import mask_generation_agent, ImageEditDeps
3
+ import os
4
+ from src.hopter.client import Hopter, Environment
5
+ from src.services.generate_mask import GenerateMaskService
6
+ from dotenv import load_dotenv
7
+ from src.utils import image_path_to_uri
8
+ from pydantic_ai.messages import (
9
+ ToolCallPart,
10
+ ToolReturnPart
11
+ )
12
+ from src.agents.mask_generation_agent import EditImageResult
13
+ from pydantic_ai.agent import Agent
14
+ from pydantic_ai.models.openai import OpenAIModel
15
+
16
+ model = OpenAIModel(
17
+ "gpt-4o",
18
+ api_key=os.environ.get("OPENAI_API_KEY"),
19
+ )
20
+
21
+ simple_agent = Agent(
22
+ model,
23
+ system_prompt="You are a helpful assistant that can answer questions and help with tasks.",
24
+ deps_type=ImageEditDeps
25
+ )
26
+
27
+ load_dotenv()
28
+
29
+ def build_user_message(chat_input):
30
+ text = chat_input["text"]
31
+ images = chat_input["files"]
32
+ messages = [
33
+ {
34
+ "role": "user",
35
+ "content": text
36
+ }
37
+ ]
38
+ if images:
39
+ messages.extend([
40
+ {
41
+ "role": "user",
42
+ "content": {"path": image}
43
+ }
44
+ for image in images
45
+ ])
46
+ return messages
47
+
48
+ async def stream_from_agent(chat_input, chatbot, past_messages):
49
+ chatbot.extend(build_user_message(chat_input))
50
+ # Clear the input immediately after submission
51
+ yield {"text": "", "files": []}, chatbot, gr.skip
52
+
53
+ # for agent
54
+ text = chat_input["text"]
55
+ images = [image_path_to_uri(image) for image in chat_input["files"]]
56
+ messages = [
57
+ {
58
+ "type": "text",
59
+ "text": text
60
+ },
61
+ ]
62
+ if images:
63
+ messages.extend([
64
+ {"type": "image_url", "image_url": {"url": image}}
65
+ for image in images
66
+ ])
67
+
68
+ hopter = Hopter(os.environ.get("HOPTER_API_KEY"), environment=Environment.STAGING)
69
+ mask_service = GenerateMaskService(hopter=hopter)
70
+ deps = ImageEditDeps(
71
+ edit_instruction=text,
72
+ image_url=images[0],
73
+ hopter_client=hopter,
74
+ mask_service=mask_service
75
+ )
76
+ async with mask_generation_agent.run_stream(
77
+ messages,
78
+ deps=deps
79
+ ) as result:
80
+ for message in result.new_messages():
81
+ for call in message.parts:
82
+ if isinstance(call, ToolCallPart):
83
+ call_args = (
84
+ call.args.args_json
85
+ if hasattr(call.args, 'args_json')
86
+ else call.args
87
+ )
88
+ metadata = {
89
+ 'title': f'🛠️ Using {call.tool_name}',
90
+ }
91
+ if call.tool_call_id is not None:
92
+ metadata['id'] = call.tool_call_id
93
+
94
+ gr_message = {
95
+ 'role': 'assistant',
96
+ 'content': 'Parameters: ' + call_args,
97
+ 'metadata': metadata,
98
+ }
99
+ chatbot.append(gr_message)
100
+ if isinstance(call, ToolReturnPart):
101
+ for gr_message in chatbot:
102
+ if (
103
+ gr_message.get('metadata', {}).get('id', '')
104
+ == call.tool_call_id
105
+ ):
106
+ if isinstance(call.content, EditImageResult):
107
+ chatbot.append({
108
+ "role": "assistant",
109
+ "content": gr.Image(call.content.edited_image_url),
110
+ "files": [call.content.edited_image_url]
111
+ })
112
+ else:
113
+ gr_message['content'] += (
114
+ f'\nOutput: {call.content}'
115
+ )
116
+ yield gr.skip(), chatbot, gr.skip()
117
+
118
+ chatbot.append({'role': 'assistant', 'content': ''})
119
+ async for message in result.stream_text():
120
+ chatbot[-1]['content'] = message
121
+ yield gr.skip(), chatbot, gr.skip()
122
+ past_messages = result.all_messages()
123
+
124
+ yield gr.Textbox(interactive=True), gr.skip(), past_messages
125
+
126
+ with gr.Blocks() as demo:
127
+ gr.HTML(
128
+ """
129
+ <div style="display: flex; justify-content: center; align-items: center; gap: 2rem; padding: 1rem; width: 100%">
130
+ <img src="https://ai.pydantic.dev/img/logo-white.svg" style="max-width: 200px; height: auto">
131
+ <div>
132
+ <h1 style="margin: 0 0 1rem 0">Image Editing Assistant</h1>
133
+ <h3 style="margin: 0 0 0.5rem 0">
134
+ This assistant edits images according to your instructions.
135
+ </h3>
136
+ </div>
137
+ </div>
138
+ """
139
+ )
140
+
141
+ past_messages = gr.State([])
142
+ chatbot = gr.Chatbot(
143
+ label='Image Editing Assistant',
144
+ type='messages',
145
+ avatar_images=(None, 'https://ai.pydantic.dev/img/logo-white.svg'),
146
+ )
147
+ with gr.Row():
148
+ chat_input = gr.MultimodalTextbox(
149
+ interactive=True,
150
+ file_count="multiple",
151
+ show_label=False,
152
+ placeholder='How would you like to edit this image?',
153
+ sources=["upload", "microphone"]
154
+ )
155
+ generation = chat_input.submit(
156
+ stream_from_agent,
157
+ inputs=[chat_input, chatbot, past_messages],
158
+ outputs=[chat_input, chatbot, past_messages],
159
+ )
160
+
161
+ if __name__ == '__main__':
162
+ demo.launch()
poetry.lock CHANGED
@@ -1,5 +1,16 @@
1
  # This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
2
 
 
 
 
 
 
 
 
 
 
 
 
3
  [[package]]
4
  name = "altair"
5
  version = "5.5.0"
@@ -351,6 +362,26 @@ files = [
351
  [package.extras]
352
  tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"]
353
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
354
  [[package]]
355
  name = "fastavro"
356
  version = "1.10.0"
@@ -397,6 +428,17 @@ lz4 = ["lz4"]
397
  snappy = ["cramjam"]
398
  zstandard = ["zstandard"]
399
 
 
 
 
 
 
 
 
 
 
 
 
400
  [[package]]
401
  name = "filelock"
402
  version = "3.17.0"
@@ -525,6 +567,67 @@ protobuf = ">=3.20.2,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4
525
  [package.extras]
526
  grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"]
527
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
528
  [[package]]
529
  name = "griffe"
530
  version = "1.5.7"
@@ -924,72 +1027,71 @@ testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"]
924
 
925
  [[package]]
926
  name = "markupsafe"
927
- version = "3.0.2"
928
  description = "Safely add untrusted strings to HTML/XML markup."
929
  optional = false
930
- python-versions = ">=3.9"
931
  files = [
932
- {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"},
933
- {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"},
934
- {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"},
935
- {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"},
936
- {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"},
937
- {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"},
938
- {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"},
939
- {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"},
940
- {file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"},
941
- {file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"},
942
- {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"},
943
- {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"},
944
- {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"},
945
- {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"},
946
- {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"},
947
- {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"},
948
- {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"},
949
- {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"},
950
- {file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"},
951
- {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"},
952
- {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"},
953
- {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"},
954
- {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"},
955
- {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"},
956
- {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"},
957
- {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"},
958
- {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"},
959
- {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"},
960
- {file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"},
961
- {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"},
962
- {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"},
963
- {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"},
964
- {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"},
965
- {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"},
966
- {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"},
967
- {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"},
968
- {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"},
969
- {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"},
970
- {file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"},
971
- {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"},
972
- {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"},
973
- {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"},
974
- {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"},
975
- {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"},
976
- {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"},
977
- {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"},
978
- {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"},
979
- {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"},
980
- {file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"},
981
- {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"},
982
- {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a"},
983
- {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff"},
984
- {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13"},
985
- {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144"},
986
- {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29"},
987
- {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0"},
988
- {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0"},
989
- {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178"},
990
- {file = "MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f"},
991
- {file = "MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a"},
992
- {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"},
993
  ]
994
 
995
  [[package]]
@@ -1262,6 +1364,94 @@ files = [
1262
  deprecated = ">=1.2.6"
1263
  opentelemetry-api = "1.30.0"
1264
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1265
  [[package]]
1266
  name = "packaging"
1267
  version = "24.2"
@@ -1762,6 +1952,17 @@ numpy = ">=1.16.4"
1762
  carto = ["pydeck-carto"]
1763
  jupyter = ["ipykernel (>=5.1.2)", "ipython (>=5.8.0)", "ipywidgets (>=7,<8)", "traitlets (>=4.3.2)"]
1764
 
 
 
 
 
 
 
 
 
 
 
 
1765
  [[package]]
1766
  name = "pygments"
1767
  version = "2.19.1"
@@ -1804,6 +2005,17 @@ files = [
1804
  [package.extras]
1805
  cli = ["click (>=5.0)"]
1806
 
 
 
 
 
 
 
 
 
 
 
 
1807
  [[package]]
1808
  name = "pytz"
1809
  version = "2025.1"
@@ -2059,6 +2271,76 @@ files = [
2059
  [package.dependencies]
2060
  pyasn1 = ">=0.1.3"
2061
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2062
  [[package]]
2063
  name = "six"
2064
  version = "1.17.0"
@@ -2092,6 +2374,23 @@ files = [
2092
  {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"},
2093
  ]
2094
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2095
  [[package]]
2096
  name = "streamlit"
2097
  version = "1.42.0"
@@ -2226,6 +2525,17 @@ files = [
2226
  {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"},
2227
  ]
2228
 
 
 
 
 
 
 
 
 
 
 
 
2229
  [[package]]
2230
  name = "tornado"
2231
  version = "6.4.2"
@@ -2267,6 +2577,23 @@ notebook = ["ipywidgets (>=6)"]
2267
  slack = ["slack-sdk"]
2268
  telegram = ["requests"]
2269
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2270
  [[package]]
2271
  name = "types-requests"
2272
  version = "2.32.0.20241016"
@@ -2335,6 +2662,25 @@ h2 = ["h2 (>=4,<5)"]
2335
  socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
2336
  zstd = ["zstandard (>=0.18.0)"]
2337
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2338
  [[package]]
2339
  name = "watchdog"
2340
  version = "6.0.0"
@@ -2377,6 +2723,84 @@ files = [
2377
  [package.extras]
2378
  watchmedo = ["PyYAML (>=3.10)"]
2379
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2380
  [[package]]
2381
  name = "wrapt"
2382
  version = "1.17.2"
@@ -2487,4 +2911,4 @@ type = ["pytest-mypy"]
2487
  [metadata]
2488
  lock-version = "2.0"
2489
  python-versions = "3.10"
2490
- content-hash = "bafe1276871675a1d904b4309d57185b79d491027371bcd5afda1aa59551457e"
 
1
  # This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
2
 
3
+ [[package]]
4
+ name = "aiofiles"
5
+ version = "23.2.1"
6
+ description = "File support for asyncio."
7
+ optional = false
8
+ python-versions = ">=3.7"
9
+ files = [
10
+ {file = "aiofiles-23.2.1-py3-none-any.whl", hash = "sha256:19297512c647d4b27a2cf7c34caa7e405c0d60b5560618a29a9fe027b18b0107"},
11
+ {file = "aiofiles-23.2.1.tar.gz", hash = "sha256:84ec2218d8419404abcb9f0c02df3f34c6e0a68ed41072acfb1cef5cbc29051a"},
12
+ ]
13
+
14
  [[package]]
15
  name = "altair"
16
  version = "5.5.0"
 
362
  [package.extras]
363
  tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"]
364
 
365
+ [[package]]
366
+ name = "fastapi"
367
+ version = "0.115.8"
368
+ description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
369
+ optional = false
370
+ python-versions = ">=3.8"
371
+ files = [
372
+ {file = "fastapi-0.115.8-py3-none-any.whl", hash = "sha256:753a96dd7e036b34eeef8babdfcfe3f28ff79648f86551eb36bfc1b0bf4a8cbf"},
373
+ {file = "fastapi-0.115.8.tar.gz", hash = "sha256:0ce9111231720190473e222cdf0f07f7206ad7e53ea02beb1d2dc36e2f0741e9"},
374
+ ]
375
+
376
+ [package.dependencies]
377
+ pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0"
378
+ starlette = ">=0.40.0,<0.46.0"
379
+ typing-extensions = ">=4.8.0"
380
+
381
+ [package.extras]
382
+ all = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=3.1.5)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"]
383
+ standard = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "httpx (>=0.23.0)", "jinja2 (>=3.1.5)", "python-multipart (>=0.0.18)", "uvicorn[standard] (>=0.12.0)"]
384
+
385
  [[package]]
386
  name = "fastavro"
387
  version = "1.10.0"
 
428
  snappy = ["cramjam"]
429
  zstandard = ["zstandard"]
430
 
431
+ [[package]]
432
+ name = "ffmpy"
433
+ version = "0.5.0"
434
+ description = "A simple Python wrapper for FFmpeg"
435
+ optional = false
436
+ python-versions = "<4.0,>=3.8"
437
+ files = [
438
+ {file = "ffmpy-0.5.0-py3-none-any.whl", hash = "sha256:df3799cf5816daa56d4959a023630ee53c6768b66009dae6d131519ba4b80233"},
439
+ {file = "ffmpy-0.5.0.tar.gz", hash = "sha256:277e131f246d18e9dcfee9bb514c50749031c43582ce5ef82c57b51e3d3955c3"},
440
+ ]
441
+
442
  [[package]]
443
  name = "filelock"
444
  version = "3.17.0"
 
567
  [package.extras]
568
  grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"]
569
 
570
+ [[package]]
571
+ name = "gradio"
572
+ version = "5.16.1"
573
+ description = "Python library for easily interacting with trained machine learning models"
574
+ optional = false
575
+ python-versions = ">=3.10"
576
+ files = [
577
+ {file = "gradio-5.16.1-py3-none-any.whl", hash = "sha256:a49f194ca314a09e4f7655a8fbcf8efae961a2bbf37877afc546fb506027f4dd"},
578
+ ]
579
+
580
+ [package.dependencies]
581
+ aiofiles = ">=22.0,<24.0"
582
+ anyio = ">=3.0,<5.0"
583
+ fastapi = ">=0.115.2,<1.0"
584
+ ffmpy = "*"
585
+ gradio-client = "1.7.0"
586
+ httpx = ">=0.24.1"
587
+ huggingface-hub = ">=0.28.1"
588
+ jinja2 = "<4.0"
589
+ markupsafe = ">=2.0,<3.0"
590
+ numpy = ">=1.0,<3.0"
591
+ orjson = ">=3.0,<4.0"
592
+ packaging = "*"
593
+ pandas = ">=1.0,<3.0"
594
+ pillow = ">=8.0,<12.0"
595
+ pydantic = ">=2.0"
596
+ pydub = "*"
597
+ python-multipart = ">=0.0.18"
598
+ pyyaml = ">=5.0,<7.0"
599
+ ruff = {version = ">=0.9.3", markers = "sys_platform != \"emscripten\""}
600
+ safehttpx = ">=0.1.6,<0.2.0"
601
+ semantic-version = ">=2.0,<3.0"
602
+ starlette = {version = ">=0.40.0,<1.0", markers = "sys_platform != \"emscripten\""}
603
+ tomlkit = ">=0.12.0,<0.14.0"
604
+ typer = {version = ">=0.12,<1.0", markers = "sys_platform != \"emscripten\""}
605
+ typing-extensions = ">=4.0,<5.0"
606
+ urllib3 = {version = ">=2.0,<3.0", markers = "sys_platform == \"emscripten\""}
607
+ uvicorn = {version = ">=0.14.0", markers = "sys_platform != \"emscripten\""}
608
+
609
+ [package.extras]
610
+ oauth = ["authlib", "itsdangerous"]
611
+
612
+ [[package]]
613
+ name = "gradio-client"
614
+ version = "1.7.0"
615
+ description = "Python library for easily interacting with trained machine learning models"
616
+ optional = false
617
+ python-versions = ">=3.10"
618
+ files = [
619
+ {file = "gradio_client-1.7.0-py3-none-any.whl", hash = "sha256:b403570c67f121ebbbc19ac1f0afa2ab1bab085ce60d96eb190832fe871aa946"},
620
+ {file = "gradio_client-1.7.0.tar.gz", hash = "sha256:87f6ade197951f38bac0431b2a436a8ebb2f33b2ceba2ef8e1e5bef8d8b238e4"},
621
+ ]
622
+
623
+ [package.dependencies]
624
+ fsspec = "*"
625
+ httpx = ">=0.24.1"
626
+ huggingface-hub = ">=0.19.3"
627
+ packaging = "*"
628
+ typing-extensions = ">=4.0,<5.0"
629
+ websockets = ">=10.0,<15.0"
630
+
631
  [[package]]
632
  name = "griffe"
633
  version = "1.5.7"
 
1027
 
1028
  [[package]]
1029
  name = "markupsafe"
1030
+ version = "2.1.5"
1031
  description = "Safely add untrusted strings to HTML/XML markup."
1032
  optional = false
1033
+ python-versions = ">=3.7"
1034
  files = [
1035
+ {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"},
1036
+ {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"},
1037
+ {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"},
1038
+ {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"},
1039
+ {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"},
1040
+ {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"},
1041
+ {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"},
1042
+ {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"},
1043
+ {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"},
1044
+ {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"},
1045
+ {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"},
1046
+ {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"},
1047
+ {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"},
1048
+ {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"},
1049
+ {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"},
1050
+ {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"},
1051
+ {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"},
1052
+ {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"},
1053
+ {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"},
1054
+ {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"},
1055
+ {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"},
1056
+ {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"},
1057
+ {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"},
1058
+ {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"},
1059
+ {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"},
1060
+ {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"},
1061
+ {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"},
1062
+ {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"},
1063
+ {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"},
1064
+ {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"},
1065
+ {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"},
1066
+ {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"},
1067
+ {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"},
1068
+ {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"},
1069
+ {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"},
1070
+ {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"},
1071
+ {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"},
1072
+ {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"},
1073
+ {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"},
1074
+ {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"},
1075
+ {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"},
1076
+ {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"},
1077
+ {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"},
1078
+ {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"},
1079
+ {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"},
1080
+ {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"},
1081
+ {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"},
1082
+ {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"},
1083
+ {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"},
1084
+ {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"},
1085
+ {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"},
1086
+ {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"},
1087
+ {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"},
1088
+ {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"},
1089
+ {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"},
1090
+ {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"},
1091
+ {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"},
1092
+ {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"},
1093
+ {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"},
1094
+ {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"},
 
1095
  ]
1096
 
1097
  [[package]]
 
1364
  deprecated = ">=1.2.6"
1365
  opentelemetry-api = "1.30.0"
1366
 
1367
+ [[package]]
1368
+ name = "orjson"
1369
+ version = "3.10.15"
1370
+ description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy"
1371
+ optional = false
1372
+ python-versions = ">=3.8"
1373
+ files = [
1374
+ {file = "orjson-3.10.15-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:552c883d03ad185f720d0c09583ebde257e41b9521b74ff40e08b7dec4559c04"},
1375
+ {file = "orjson-3.10.15-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:616e3e8d438d02e4854f70bfdc03a6bcdb697358dbaa6bcd19cbe24d24ece1f8"},
1376
+ {file = "orjson-3.10.15-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7c2c79fa308e6edb0ffab0a31fd75a7841bf2a79a20ef08a3c6e3b26814c8ca8"},
1377
+ {file = "orjson-3.10.15-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cb85490aa6bf98abd20607ab5c8324c0acb48d6da7863a51be48505646c814"},
1378
+ {file = "orjson-3.10.15-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:763dadac05e4e9d2bc14938a45a2d0560549561287d41c465d3c58aec818b164"},
1379
+ {file = "orjson-3.10.15-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a330b9b4734f09a623f74a7490db713695e13b67c959713b78369f26b3dee6bf"},
1380
+ {file = "orjson-3.10.15-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a61a4622b7ff861f019974f73d8165be1bd9a0855e1cad18ee167acacabeb061"},
1381
+ {file = "orjson-3.10.15-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:acd271247691574416b3228db667b84775c497b245fa275c6ab90dc1ffbbd2b3"},
1382
+ {file = "orjson-3.10.15-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4759b109c37f635aa5c5cc93a1b26927bfde24b254bcc0e1149a9fada253d2d"},
1383
+ {file = "orjson-3.10.15-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9e992fd5cfb8b9f00bfad2fd7a05a4299db2bbe92e6440d9dd2fab27655b3182"},
1384
+ {file = "orjson-3.10.15-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f95fb363d79366af56c3f26b71df40b9a583b07bbaaf5b317407c4d58497852e"},
1385
+ {file = "orjson-3.10.15-cp310-cp310-win32.whl", hash = "sha256:f9875f5fea7492da8ec2444839dcc439b0ef298978f311103d0b7dfd775898ab"},
1386
+ {file = "orjson-3.10.15-cp310-cp310-win_amd64.whl", hash = "sha256:17085a6aa91e1cd70ca8533989a18b5433e15d29c574582f76f821737c8d5806"},
1387
+ {file = "orjson-3.10.15-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:c4cc83960ab79a4031f3119cc4b1a1c627a3dc09df125b27c4201dff2af7eaa6"},
1388
+ {file = "orjson-3.10.15-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ddbeef2481d895ab8be5185f2432c334d6dec1f5d1933a9c83014d188e102cef"},
1389
+ {file = "orjson-3.10.15-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9e590a0477b23ecd5b0ac865b1b907b01b3c5535f5e8a8f6ab0e503efb896334"},
1390
+ {file = "orjson-3.10.15-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a6be38bd103d2fd9bdfa31c2720b23b5d47c6796bcb1d1b598e3924441b4298d"},
1391
+ {file = "orjson-3.10.15-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ff4f6edb1578960ed628a3b998fa54d78d9bb3e2eb2cfc5c2a09732431c678d0"},
1392
+ {file = "orjson-3.10.15-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0482b21d0462eddd67e7fce10b89e0b6ac56570424662b685a0d6fccf581e13"},
1393
+ {file = "orjson-3.10.15-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bb5cc3527036ae3d98b65e37b7986a918955f85332c1ee07f9d3f82f3a6899b5"},
1394
+ {file = "orjson-3.10.15-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d569c1c462912acdd119ccbf719cf7102ea2c67dd03b99edcb1a3048651ac96b"},
1395
+ {file = "orjson-3.10.15-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:1e6d33efab6b71d67f22bf2962895d3dc6f82a6273a965fab762e64fa90dc399"},
1396
+ {file = "orjson-3.10.15-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c33be3795e299f565681d69852ac8c1bc5c84863c0b0030b2b3468843be90388"},
1397
+ {file = "orjson-3.10.15-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:eea80037b9fae5339b214f59308ef0589fc06dc870578b7cce6d71eb2096764c"},
1398
+ {file = "orjson-3.10.15-cp311-cp311-win32.whl", hash = "sha256:d5ac11b659fd798228a7adba3e37c010e0152b78b1982897020a8e019a94882e"},
1399
+ {file = "orjson-3.10.15-cp311-cp311-win_amd64.whl", hash = "sha256:cf45e0214c593660339ef63e875f32ddd5aa3b4adc15e662cdb80dc49e194f8e"},
1400
+ {file = "orjson-3.10.15-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9d11c0714fc85bfcf36ada1179400862da3288fc785c30e8297844c867d7505a"},
1401
+ {file = "orjson-3.10.15-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dba5a1e85d554e3897fa9fe6fbcff2ed32d55008973ec9a2b992bd9a65d2352d"},
1402
+ {file = "orjson-3.10.15-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7723ad949a0ea502df656948ddd8b392780a5beaa4c3b5f97e525191b102fff0"},
1403
+ {file = "orjson-3.10.15-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6fd9bc64421e9fe9bd88039e7ce8e58d4fead67ca88e3a4014b143cec7684fd4"},
1404
+ {file = "orjson-3.10.15-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dadba0e7b6594216c214ef7894c4bd5f08d7c0135f4dd0145600be4fbcc16767"},
1405
+ {file = "orjson-3.10.15-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b48f59114fe318f33bbaee8ebeda696d8ccc94c9e90bc27dbe72153094e26f41"},
1406
+ {file = "orjson-3.10.15-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:035fb83585e0f15e076759b6fedaf0abb460d1765b6a36f48018a52858443514"},
1407
+ {file = "orjson-3.10.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d13b7fe322d75bf84464b075eafd8e7dd9eae05649aa2a5354cfa32f43c59f17"},
1408
+ {file = "orjson-3.10.15-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:7066b74f9f259849629e0d04db6609db4cf5b973248f455ba5d3bd58a4daaa5b"},
1409
+ {file = "orjson-3.10.15-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:88dc3f65a026bd3175eb157fea994fca6ac7c4c8579fc5a86fc2114ad05705b7"},
1410
+ {file = "orjson-3.10.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b342567e5465bd99faa559507fe45e33fc76b9fb868a63f1642c6bc0735ad02a"},
1411
+ {file = "orjson-3.10.15-cp312-cp312-win32.whl", hash = "sha256:0a4f27ea5617828e6b58922fdbec67b0aa4bb844e2d363b9244c47fa2180e665"},
1412
+ {file = "orjson-3.10.15-cp312-cp312-win_amd64.whl", hash = "sha256:ef5b87e7aa9545ddadd2309efe6824bd3dd64ac101c15dae0f2f597911d46eaa"},
1413
+ {file = "orjson-3.10.15-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:bae0e6ec2b7ba6895198cd981b7cca95d1487d0147c8ed751e5632ad16f031a6"},
1414
+ {file = "orjson-3.10.15-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f93ce145b2db1252dd86af37d4165b6faa83072b46e3995ecc95d4b2301b725a"},
1415
+ {file = "orjson-3.10.15-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7c203f6f969210128af3acae0ef9ea6aab9782939f45f6fe02d05958fe761ef9"},
1416
+ {file = "orjson-3.10.15-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8918719572d662e18b8af66aef699d8c21072e54b6c82a3f8f6404c1f5ccd5e0"},
1417
+ {file = "orjson-3.10.15-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f71eae9651465dff70aa80db92586ad5b92df46a9373ee55252109bb6b703307"},
1418
+ {file = "orjson-3.10.15-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e117eb299a35f2634e25ed120c37c641398826c2f5a3d3cc39f5993b96171b9e"},
1419
+ {file = "orjson-3.10.15-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:13242f12d295e83c2955756a574ddd6741c81e5b99f2bef8ed8d53e47a01e4b7"},
1420
+ {file = "orjson-3.10.15-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7946922ada8f3e0b7b958cc3eb22cfcf6c0df83d1fe5521b4a100103e3fa84c8"},
1421
+ {file = "orjson-3.10.15-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:b7155eb1623347f0f22c38c9abdd738b287e39b9982e1da227503387b81b34ca"},
1422
+ {file = "orjson-3.10.15-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:208beedfa807c922da4e81061dafa9c8489c6328934ca2a562efa707e049e561"},
1423
+ {file = "orjson-3.10.15-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eca81f83b1b8c07449e1d6ff7074e82e3fd6777e588f1a6632127f286a968825"},
1424
+ {file = "orjson-3.10.15-cp313-cp313-win32.whl", hash = "sha256:c03cd6eea1bd3b949d0d007c8d57049aa2b39bd49f58b4b2af571a5d3833d890"},
1425
+ {file = "orjson-3.10.15-cp313-cp313-win_amd64.whl", hash = "sha256:fd56a26a04f6ba5fb2045b0acc487a63162a958ed837648c5781e1fe3316cfbf"},
1426
+ {file = "orjson-3.10.15-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:5e8afd6200e12771467a1a44e5ad780614b86abb4b11862ec54861a82d677746"},
1427
+ {file = "orjson-3.10.15-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da9a18c500f19273e9e104cca8c1f0b40a6470bcccfc33afcc088045d0bf5ea6"},
1428
+ {file = "orjson-3.10.15-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb00b7bfbdf5d34a13180e4805d76b4567025da19a197645ca746fc2fb536586"},
1429
+ {file = "orjson-3.10.15-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:33aedc3d903378e257047fee506f11e0833146ca3e57a1a1fb0ddb789876c1e1"},
1430
+ {file = "orjson-3.10.15-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd0099ae6aed5eb1fc84c9eb72b95505a3df4267e6962eb93cdd5af03be71c98"},
1431
+ {file = "orjson-3.10.15-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c864a80a2d467d7786274fce0e4f93ef2a7ca4ff31f7fc5634225aaa4e9e98c"},
1432
+ {file = "orjson-3.10.15-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c25774c9e88a3e0013d7d1a6c8056926b607a61edd423b50eb5c88fd7f2823ae"},
1433
+ {file = "orjson-3.10.15-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:e78c211d0074e783d824ce7bb85bf459f93a233eb67a5b5003498232ddfb0e8a"},
1434
+ {file = "orjson-3.10.15-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:43e17289ffdbbac8f39243916c893d2ae41a2ea1a9cbb060a56a4d75286351ae"},
1435
+ {file = "orjson-3.10.15-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:781d54657063f361e89714293c095f506c533582ee40a426cb6489c48a637b81"},
1436
+ {file = "orjson-3.10.15-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:6875210307d36c94873f553786a808af2788e362bd0cf4c8e66d976791e7b528"},
1437
+ {file = "orjson-3.10.15-cp38-cp38-win32.whl", hash = "sha256:305b38b2b8f8083cc3d618927d7f424349afce5975b316d33075ef0f73576b60"},
1438
+ {file = "orjson-3.10.15-cp38-cp38-win_amd64.whl", hash = "sha256:5dd9ef1639878cc3efffed349543cbf9372bdbd79f478615a1c633fe4e4180d1"},
1439
+ {file = "orjson-3.10.15-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:ffe19f3e8d68111e8644d4f4e267a069ca427926855582ff01fc012496d19969"},
1440
+ {file = "orjson-3.10.15-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d433bf32a363823863a96561a555227c18a522a8217a6f9400f00ddc70139ae2"},
1441
+ {file = "orjson-3.10.15-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:da03392674f59a95d03fa5fb9fe3a160b0511ad84b7a3914699ea5a1b3a38da2"},
1442
+ {file = "orjson-3.10.15-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3a63bb41559b05360ded9132032239e47983a39b151af1201f07ec9370715c82"},
1443
+ {file = "orjson-3.10.15-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3766ac4702f8f795ff3fa067968e806b4344af257011858cc3d6d8721588b53f"},
1444
+ {file = "orjson-3.10.15-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a1c73dcc8fadbd7c55802d9aa093b36878d34a3b3222c41052ce6b0fc65f8e8"},
1445
+ {file = "orjson-3.10.15-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b299383825eafe642cbab34be762ccff9fd3408d72726a6b2a4506d410a71ab3"},
1446
+ {file = "orjson-3.10.15-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:abc7abecdbf67a173ef1316036ebbf54ce400ef2300b4e26a7b843bd446c2480"},
1447
+ {file = "orjson-3.10.15-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:3614ea508d522a621384c1d6639016a5a2e4f027f3e4a1c93a51867615d28829"},
1448
+ {file = "orjson-3.10.15-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:295c70f9dc154307777ba30fe29ff15c1bcc9dfc5c48632f37d20a607e9ba85a"},
1449
+ {file = "orjson-3.10.15-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:63309e3ff924c62404923c80b9e2048c1f74ba4b615e7584584389ada50ed428"},
1450
+ {file = "orjson-3.10.15-cp39-cp39-win32.whl", hash = "sha256:a2f708c62d026fb5340788ba94a55c23df4e1869fec74be455e0b2f5363b8507"},
1451
+ {file = "orjson-3.10.15-cp39-cp39-win_amd64.whl", hash = "sha256:efcf6c735c3d22ef60c4aa27a5238f1a477df85e9b15f2142f9d669beb2d13fd"},
1452
+ {file = "orjson-3.10.15.tar.gz", hash = "sha256:05ca7fe452a2e9d8d9d706a2984c95b9c2ebc5db417ce0b7a49b91d50642a23e"},
1453
+ ]
1454
+
1455
  [[package]]
1456
  name = "packaging"
1457
  version = "24.2"
 
1952
  carto = ["pydeck-carto"]
1953
  jupyter = ["ipykernel (>=5.1.2)", "ipython (>=5.8.0)", "ipywidgets (>=7,<8)", "traitlets (>=4.3.2)"]
1954
 
1955
+ [[package]]
1956
+ name = "pydub"
1957
+ version = "0.25.1"
1958
+ description = "Manipulate audio with an simple and easy high level interface"
1959
+ optional = false
1960
+ python-versions = "*"
1961
+ files = [
1962
+ {file = "pydub-0.25.1-py2.py3-none-any.whl", hash = "sha256:65617e33033874b59d87db603aa1ed450633288aefead953b30bded59cb599a6"},
1963
+ {file = "pydub-0.25.1.tar.gz", hash = "sha256:980a33ce9949cab2a569606b65674d748ecbca4f0796887fd6f46173a7b0d30f"},
1964
+ ]
1965
+
1966
  [[package]]
1967
  name = "pygments"
1968
  version = "2.19.1"
 
2005
  [package.extras]
2006
  cli = ["click (>=5.0)"]
2007
 
2008
+ [[package]]
2009
+ name = "python-multipart"
2010
+ version = "0.0.20"
2011
+ description = "A streaming multipart parser for Python"
2012
+ optional = false
2013
+ python-versions = ">=3.8"
2014
+ files = [
2015
+ {file = "python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104"},
2016
+ {file = "python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13"},
2017
+ ]
2018
+
2019
  [[package]]
2020
  name = "pytz"
2021
  version = "2025.1"
 
2271
  [package.dependencies]
2272
  pyasn1 = ">=0.1.3"
2273
 
2274
+ [[package]]
2275
+ name = "ruff"
2276
+ version = "0.9.6"
2277
+ description = "An extremely fast Python linter and code formatter, written in Rust."
2278
+ optional = false
2279
+ python-versions = ">=3.7"
2280
+ files = [
2281
+ {file = "ruff-0.9.6-py3-none-linux_armv6l.whl", hash = "sha256:2f218f356dd2d995839f1941322ff021c72a492c470f0b26a34f844c29cdf5ba"},
2282
+ {file = "ruff-0.9.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b908ff4df65dad7b251c9968a2e4560836d8f5487c2f0cc238321ed951ea0504"},
2283
+ {file = "ruff-0.9.6-py3-none-macosx_11_0_arm64.whl", hash = "sha256:b109c0ad2ececf42e75fa99dc4043ff72a357436bb171900714a9ea581ddef83"},
2284
+ {file = "ruff-0.9.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1de4367cca3dac99bcbd15c161404e849bb0bfd543664db39232648dc00112dc"},
2285
+ {file = "ruff-0.9.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac3ee4d7c2c92ddfdaedf0bf31b2b176fa7aa8950efc454628d477394d35638b"},
2286
+ {file = "ruff-0.9.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5dc1edd1775270e6aa2386119aea692039781429f0be1e0949ea5884e011aa8e"},
2287
+ {file = "ruff-0.9.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:4a091729086dffa4bd070aa5dab7e39cc6b9d62eb2bef8f3d91172d30d599666"},
2288
+ {file = "ruff-0.9.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1bbc6808bf7b15796cef0815e1dfb796fbd383e7dbd4334709642649625e7c5"},
2289
+ {file = "ruff-0.9.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:589d1d9f25b5754ff230dce914a174a7c951a85a4e9270613a2b74231fdac2f5"},
2290
+ {file = "ruff-0.9.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc61dd5131742e21103fbbdcad683a8813be0e3c204472d520d9a5021ca8b217"},
2291
+ {file = "ruff-0.9.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:5e2d9126161d0357e5c8f30b0bd6168d2c3872372f14481136d13de9937f79b6"},
2292
+ {file = "ruff-0.9.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:68660eab1a8e65babb5229a1f97b46e3120923757a68b5413d8561f8a85d4897"},
2293
+ {file = "ruff-0.9.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:c4cae6c4cc7b9b4017c71114115db0445b00a16de3bcde0946273e8392856f08"},
2294
+ {file = "ruff-0.9.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:19f505b643228b417c1111a2a536424ddde0db4ef9023b9e04a46ed8a1cb4656"},
2295
+ {file = "ruff-0.9.6-py3-none-win32.whl", hash = "sha256:194d8402bceef1b31164909540a597e0d913c0e4952015a5b40e28c146121b5d"},
2296
+ {file = "ruff-0.9.6-py3-none-win_amd64.whl", hash = "sha256:03482d5c09d90d4ee3f40d97578423698ad895c87314c4de39ed2af945633caa"},
2297
+ {file = "ruff-0.9.6-py3-none-win_arm64.whl", hash = "sha256:0e2bb706a2be7ddfea4a4af918562fdc1bcb16df255e5fa595bbd800ce322a5a"},
2298
+ {file = "ruff-0.9.6.tar.gz", hash = "sha256:81761592f72b620ec8fa1068a6fd00e98a5ebee342a3642efd84454f3031dca9"},
2299
+ ]
2300
+
2301
+ [[package]]
2302
+ name = "safehttpx"
2303
+ version = "0.1.6"
2304
+ description = "A small Python library created to help developers protect their applications from Server Side Request Forgery (SSRF) attacks."
2305
+ optional = false
2306
+ python-versions = ">3.9"
2307
+ files = [
2308
+ {file = "safehttpx-0.1.6-py3-none-any.whl", hash = "sha256:407cff0b410b071623087c63dd2080c3b44dc076888d8c5823c00d1e58cb381c"},
2309
+ {file = "safehttpx-0.1.6.tar.gz", hash = "sha256:b356bfc82cee3a24c395b94a2dbeabbed60aff1aa5fa3b5fe97c4f2456ebce42"},
2310
+ ]
2311
+
2312
+ [package.dependencies]
2313
+ httpx = "*"
2314
+
2315
+ [package.extras]
2316
+ dev = ["pytest"]
2317
+
2318
+ [[package]]
2319
+ name = "semantic-version"
2320
+ version = "2.10.0"
2321
+ description = "A library implementing the 'SemVer' scheme."
2322
+ optional = false
2323
+ python-versions = ">=2.7"
2324
+ files = [
2325
+ {file = "semantic_version-2.10.0-py2.py3-none-any.whl", hash = "sha256:de78a3b8e0feda74cabc54aab2da702113e33ac9d9eb9d2389bcf1f58b7d9177"},
2326
+ {file = "semantic_version-2.10.0.tar.gz", hash = "sha256:bdabb6d336998cbb378d4b9db3a4b56a1e3235701dc05ea2690d9a997ed5041c"},
2327
+ ]
2328
+
2329
+ [package.extras]
2330
+ dev = ["Django (>=1.11)", "check-manifest", "colorama (<=0.4.1)", "coverage", "flake8", "nose2", "readme-renderer (<25.0)", "tox", "wheel", "zest.releaser[recommended]"]
2331
+ doc = ["Sphinx", "sphinx-rtd-theme"]
2332
+
2333
+ [[package]]
2334
+ name = "shellingham"
2335
+ version = "1.5.4"
2336
+ description = "Tool to Detect Surrounding Shell"
2337
+ optional = false
2338
+ python-versions = ">=3.7"
2339
+ files = [
2340
+ {file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"},
2341
+ {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"},
2342
+ ]
2343
+
2344
  [[package]]
2345
  name = "six"
2346
  version = "1.17.0"
 
2374
  {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"},
2375
  ]
2376
 
2377
+ [[package]]
2378
+ name = "starlette"
2379
+ version = "0.45.3"
2380
+ description = "The little ASGI library that shines."
2381
+ optional = false
2382
+ python-versions = ">=3.9"
2383
+ files = [
2384
+ {file = "starlette-0.45.3-py3-none-any.whl", hash = "sha256:dfb6d332576f136ec740296c7e8bb8c8a7125044e7c6da30744718880cdd059d"},
2385
+ {file = "starlette-0.45.3.tar.gz", hash = "sha256:2cbcba2a75806f8a41c722141486f37c28e30a0921c5f6fe4346cb0dcee1302f"},
2386
+ ]
2387
+
2388
+ [package.dependencies]
2389
+ anyio = ">=3.6.2,<5"
2390
+
2391
+ [package.extras]
2392
+ full = ["httpx (>=0.27.0,<0.29.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.18)", "pyyaml"]
2393
+
2394
  [[package]]
2395
  name = "streamlit"
2396
  version = "1.42.0"
 
2525
  {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"},
2526
  ]
2527
 
2528
+ [[package]]
2529
+ name = "tomlkit"
2530
+ version = "0.13.2"
2531
+ description = "Style preserving TOML library"
2532
+ optional = false
2533
+ python-versions = ">=3.8"
2534
+ files = [
2535
+ {file = "tomlkit-0.13.2-py3-none-any.whl", hash = "sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde"},
2536
+ {file = "tomlkit-0.13.2.tar.gz", hash = "sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79"},
2537
+ ]
2538
+
2539
  [[package]]
2540
  name = "tornado"
2541
  version = "6.4.2"
 
2577
  slack = ["slack-sdk"]
2578
  telegram = ["requests"]
2579
 
2580
+ [[package]]
2581
+ name = "typer"
2582
+ version = "0.15.1"
2583
+ description = "Typer, build great CLIs. Easy to code. Based on Python type hints."
2584
+ optional = false
2585
+ python-versions = ">=3.7"
2586
+ files = [
2587
+ {file = "typer-0.15.1-py3-none-any.whl", hash = "sha256:7994fb7b8155b64d3402518560648446072864beefd44aa2dc36972a5972e847"},
2588
+ {file = "typer-0.15.1.tar.gz", hash = "sha256:a0588c0a7fa68a1978a069818657778f86abe6ff5ea6abf472f940a08bfe4f0a"},
2589
+ ]
2590
+
2591
+ [package.dependencies]
2592
+ click = ">=8.0.0"
2593
+ rich = ">=10.11.0"
2594
+ shellingham = ">=1.3.0"
2595
+ typing-extensions = ">=3.7.4.3"
2596
+
2597
  [[package]]
2598
  name = "types-requests"
2599
  version = "2.32.0.20241016"
 
2662
  socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
2663
  zstd = ["zstandard (>=0.18.0)"]
2664
 
2665
+ [[package]]
2666
+ name = "uvicorn"
2667
+ version = "0.34.0"
2668
+ description = "The lightning-fast ASGI server."
2669
+ optional = false
2670
+ python-versions = ">=3.9"
2671
+ files = [
2672
+ {file = "uvicorn-0.34.0-py3-none-any.whl", hash = "sha256:023dc038422502fa28a09c7a30bf2b6991512da7dcdb8fd35fe57cfc154126f4"},
2673
+ {file = "uvicorn-0.34.0.tar.gz", hash = "sha256:404051050cd7e905de2c9a7e61790943440b3416f49cb409f965d9dcd0fa73e9"},
2674
+ ]
2675
+
2676
+ [package.dependencies]
2677
+ click = ">=7.0"
2678
+ h11 = ">=0.8"
2679
+ typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""}
2680
+
2681
+ [package.extras]
2682
+ standard = ["colorama (>=0.4)", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"]
2683
+
2684
  [[package]]
2685
  name = "watchdog"
2686
  version = "6.0.0"
 
2723
  [package.extras]
2724
  watchmedo = ["PyYAML (>=3.10)"]
2725
 
2726
+ [[package]]
2727
+ name = "websockets"
2728
+ version = "14.2"
2729
+ description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)"
2730
+ optional = false
2731
+ python-versions = ">=3.9"
2732
+ files = [
2733
+ {file = "websockets-14.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e8179f95323b9ab1c11723e5d91a89403903f7b001828161b480a7810b334885"},
2734
+ {file = "websockets-14.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0d8c3e2cdb38f31d8bd7d9d28908005f6fa9def3324edb9bf336d7e4266fd397"},
2735
+ {file = "websockets-14.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:714a9b682deb4339d39ffa674f7b674230227d981a37d5d174a4a83e3978a610"},
2736
+ {file = "websockets-14.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2e53c72052f2596fb792a7acd9704cbc549bf70fcde8a99e899311455974ca3"},
2737
+ {file = "websockets-14.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e3fbd68850c837e57373d95c8fe352203a512b6e49eaae4c2f4088ef8cf21980"},
2738
+ {file = "websockets-14.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b27ece32f63150c268593d5fdb82819584831a83a3f5809b7521df0685cd5d8"},
2739
+ {file = "websockets-14.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4daa0faea5424d8713142b33825fff03c736f781690d90652d2c8b053345b0e7"},
2740
+ {file = "websockets-14.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:bc63cee8596a6ec84d9753fd0fcfa0452ee12f317afe4beae6b157f0070c6c7f"},
2741
+ {file = "websockets-14.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7a570862c325af2111343cc9b0257b7119b904823c675b22d4ac547163088d0d"},
2742
+ {file = "websockets-14.2-cp310-cp310-win32.whl", hash = "sha256:75862126b3d2d505e895893e3deac0a9339ce750bd27b4ba515f008b5acf832d"},
2743
+ {file = "websockets-14.2-cp310-cp310-win_amd64.whl", hash = "sha256:cc45afb9c9b2dc0852d5c8b5321759cf825f82a31bfaf506b65bf4668c96f8b2"},
2744
+ {file = "websockets-14.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3bdc8c692c866ce5fefcaf07d2b55c91d6922ac397e031ef9b774e5b9ea42166"},
2745
+ {file = "websockets-14.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c93215fac5dadc63e51bcc6dceca72e72267c11def401d6668622b47675b097f"},
2746
+ {file = "websockets-14.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1c9b6535c0e2cf8a6bf938064fb754aaceb1e6a4a51a80d884cd5db569886910"},
2747
+ {file = "websockets-14.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a52a6d7cf6938e04e9dceb949d35fbdf58ac14deea26e685ab6368e73744e4c"},
2748
+ {file = "websockets-14.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9f05702e93203a6ff5226e21d9b40c037761b2cfb637187c9802c10f58e40473"},
2749
+ {file = "websockets-14.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22441c81a6748a53bfcb98951d58d1af0661ab47a536af08920d129b4d1c3473"},
2750
+ {file = "websockets-14.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd9b868d78b194790e6236d9cbc46d68aba4b75b22497eb4ab64fa640c3af56"},
2751
+ {file = "websockets-14.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1a5a20d5843886d34ff8c57424cc65a1deda4375729cbca4cb6b3353f3ce4142"},
2752
+ {file = "websockets-14.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:34277a29f5303d54ec6468fb525d99c99938607bc96b8d72d675dee2b9f5bf1d"},
2753
+ {file = "websockets-14.2-cp311-cp311-win32.whl", hash = "sha256:02687db35dbc7d25fd541a602b5f8e451a238ffa033030b172ff86a93cb5dc2a"},
2754
+ {file = "websockets-14.2-cp311-cp311-win_amd64.whl", hash = "sha256:862e9967b46c07d4dcd2532e9e8e3c2825e004ffbf91a5ef9dde519ee2effb0b"},
2755
+ {file = "websockets-14.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1f20522e624d7ffbdbe259c6b6a65d73c895045f76a93719aa10cd93b3de100c"},
2756
+ {file = "websockets-14.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:647b573f7d3ada919fd60e64d533409a79dcf1ea21daeb4542d1d996519ca967"},
2757
+ {file = "websockets-14.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6af99a38e49f66be5a64b1e890208ad026cda49355661549c507152113049990"},
2758
+ {file = "websockets-14.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:091ab63dfc8cea748cc22c1db2814eadb77ccbf82829bac6b2fbe3401d548eda"},
2759
+ {file = "websockets-14.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b374e8953ad477d17e4851cdc66d83fdc2db88d9e73abf755c94510ebddceb95"},
2760
+ {file = "websockets-14.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a39d7eceeea35db85b85e1169011bb4321c32e673920ae9c1b6e0978590012a3"},
2761
+ {file = "websockets-14.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0a6f3efd47ffd0d12080594f434faf1cd2549b31e54870b8470b28cc1d3817d9"},
2762
+ {file = "websockets-14.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:065ce275e7c4ffb42cb738dd6b20726ac26ac9ad0a2a48e33ca632351a737267"},
2763
+ {file = "websockets-14.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e9d0e53530ba7b8b5e389c02282f9d2aa47581514bd6049d3a7cffe1385cf5fe"},
2764
+ {file = "websockets-14.2-cp312-cp312-win32.whl", hash = "sha256:20e6dd0984d7ca3037afcb4494e48c74ffb51e8013cac71cf607fffe11df7205"},
2765
+ {file = "websockets-14.2-cp312-cp312-win_amd64.whl", hash = "sha256:44bba1a956c2c9d268bdcdf234d5e5ff4c9b6dc3e300545cbe99af59dda9dcce"},
2766
+ {file = "websockets-14.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6f1372e511c7409a542291bce92d6c83320e02c9cf392223272287ce55bc224e"},
2767
+ {file = "websockets-14.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4da98b72009836179bb596a92297b1a61bb5a830c0e483a7d0766d45070a08ad"},
2768
+ {file = "websockets-14.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8a86a269759026d2bde227652b87be79f8a734e582debf64c9d302faa1e9f03"},
2769
+ {file = "websockets-14.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:86cf1aaeca909bf6815ea714d5c5736c8d6dd3a13770e885aafe062ecbd04f1f"},
2770
+ {file = "websockets-14.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9b0f6c3ba3b1240f602ebb3971d45b02cc12bd1845466dd783496b3b05783a5"},
2771
+ {file = "websockets-14.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:669c3e101c246aa85bc8534e495952e2ca208bd87994650b90a23d745902db9a"},
2772
+ {file = "websockets-14.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:eabdb28b972f3729348e632ab08f2a7b616c7e53d5414c12108c29972e655b20"},
2773
+ {file = "websockets-14.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2066dc4cbcc19f32c12a5a0e8cc1b7ac734e5b64ac0a325ff8353451c4b15ef2"},
2774
+ {file = "websockets-14.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ab95d357cd471df61873dadf66dd05dd4709cae001dd6342edafc8dc6382f307"},
2775
+ {file = "websockets-14.2-cp313-cp313-win32.whl", hash = "sha256:a9e72fb63e5f3feacdcf5b4ff53199ec8c18d66e325c34ee4c551ca748623bbc"},
2776
+ {file = "websockets-14.2-cp313-cp313-win_amd64.whl", hash = "sha256:b439ea828c4ba99bb3176dc8d9b933392a2413c0f6b149fdcba48393f573377f"},
2777
+ {file = "websockets-14.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7cd5706caec1686c5d233bc76243ff64b1c0dc445339bd538f30547e787c11fe"},
2778
+ {file = "websockets-14.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ec607328ce95a2f12b595f7ae4c5d71bf502212bddcea528290b35c286932b12"},
2779
+ {file = "websockets-14.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da85651270c6bfb630136423037dd4975199e5d4114cae6d3066641adcc9d1c7"},
2780
+ {file = "websockets-14.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3ecadc7ce90accf39903815697917643f5b7cfb73c96702318a096c00aa71f5"},
2781
+ {file = "websockets-14.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1979bee04af6a78608024bad6dfcc0cc930ce819f9e10342a29a05b5320355d0"},
2782
+ {file = "websockets-14.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dddacad58e2614a24938a50b85969d56f88e620e3f897b7d80ac0d8a5800258"},
2783
+ {file = "websockets-14.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:89a71173caaf75fa71a09a5f614f450ba3ec84ad9fca47cb2422a860676716f0"},
2784
+ {file = "websockets-14.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:6af6a4b26eea4fc06c6818a6b962a952441e0e39548b44773502761ded8cc1d4"},
2785
+ {file = "websockets-14.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:80c8efa38957f20bba0117b48737993643204645e9ec45512579132508477cfc"},
2786
+ {file = "websockets-14.2-cp39-cp39-win32.whl", hash = "sha256:2e20c5f517e2163d76e2729104abc42639c41cf91f7b1839295be43302713661"},
2787
+ {file = "websockets-14.2-cp39-cp39-win_amd64.whl", hash = "sha256:b4c8cef610e8d7c70dea92e62b6814a8cd24fbd01d7103cc89308d2bfe1659ef"},
2788
+ {file = "websockets-14.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:d7d9cafbccba46e768be8a8ad4635fa3eae1ffac4c6e7cb4eb276ba41297ed29"},
2789
+ {file = "websockets-14.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:c76193c1c044bd1e9b3316dcc34b174bbf9664598791e6fb606d8d29000e070c"},
2790
+ {file = "websockets-14.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd475a974d5352390baf865309fe37dec6831aafc3014ffac1eea99e84e83fc2"},
2791
+ {file = "websockets-14.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2c6c0097a41968b2e2b54ed3424739aab0b762ca92af2379f152c1aef0187e1c"},
2792
+ {file = "websockets-14.2-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d7ff794c8b36bc402f2e07c0b2ceb4a2424147ed4785ff03e2a7af03711d60a"},
2793
+ {file = "websockets-14.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:dec254fcabc7bd488dab64846f588fc5b6fe0d78f641180030f8ea27b76d72c3"},
2794
+ {file = "websockets-14.2-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:bbe03eb853e17fd5b15448328b4ec7fb2407d45fb0245036d06a3af251f8e48f"},
2795
+ {file = "websockets-14.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a3c4aa3428b904d5404a0ed85f3644d37e2cb25996b7f096d77caeb0e96a3b42"},
2796
+ {file = "websockets-14.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:577a4cebf1ceaf0b65ffc42c54856214165fb8ceeba3935852fc33f6b0c55e7f"},
2797
+ {file = "websockets-14.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ad1c1d02357b7665e700eca43a31d52814ad9ad9b89b58118bdabc365454b574"},
2798
+ {file = "websockets-14.2-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f390024a47d904613577df83ba700bd189eedc09c57af0a904e5c39624621270"},
2799
+ {file = "websockets-14.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3c1426c021c38cf92b453cdf371228d3430acd775edee6bac5a4d577efc72365"},
2800
+ {file = "websockets-14.2-py3-none-any.whl", hash = "sha256:7a6ceec4ea84469f15cf15807a747e9efe57e369c384fa86e022b3bea679b79b"},
2801
+ {file = "websockets-14.2.tar.gz", hash = "sha256:5059ed9c54945efb321f097084b4c7e52c246f2c869815876a69d1efc4ad6eb5"},
2802
+ ]
2803
+
2804
  [[package]]
2805
  name = "wrapt"
2806
  version = "1.17.2"
 
2911
  [metadata]
2912
  lock-version = "2.0"
2913
  python-versions = "3.10"
2914
+ content-hash = "83c3d0c47f98107284fb95080f8f9a6ba3c17d9a89f13ccbd66b73ca99863b4d"
pyproject.toml CHANGED
@@ -13,6 +13,7 @@ watchdog = "^6.0.0"
13
  pydantic-ai = "^0.0.24"
14
  python-dotenv = "^1.0.1"
15
  logfire = "^3.5.3"
 
16
 
17
 
18
  [build-system]
 
13
  pydantic-ai = "^0.0.24"
14
  python-dotenv = "^1.0.1"
15
  logfire = "^3.5.3"
16
+ gradio = "^5.16.1"
17
 
18
 
19
  [build-system]
src/agents/image-edit-agent.py CHANGED
@@ -4,7 +4,7 @@ from pydantic_ai.models.openai import OpenAIModel
4
  from dotenv import load_dotenv
5
  import os
6
  import asyncio
7
- import base64
8
  from dataclasses import dataclass
9
 
10
  load_dotenv()
@@ -76,31 +76,29 @@ async def generate_mask(ctx: RunContext[ImageEditDeps], mask_subject: str) -> st
76
 
77
  async def main():
78
  image_file_path = "./assets/lakeview.jpg"
79
- with open(image_file_path, "rb") as image_file:
80
- image_bytes = image_file.read()
81
- image_base64 = base64.b64encode(image_bytes).decode("utf-8")
82
- image_url = f"data:image/jpeg;base64,{image_base64}"
83
 
84
- prompt = "remove the light post"
85
- messages = [
86
- {
87
- "type": "text",
88
- "text": prompt
89
- },
90
- {
91
- "type": "image_url",
92
- "image_url": {
93
- "url": image_url
94
- }
95
  }
96
- ]
 
97
 
98
- deps = ImageEditDeps(
99
- edit_instruction=prompt,
100
- image_url=image_url
101
- )
102
- r = await mask_generation_agent.run(messages, deps=deps)
103
- print(r.data)
104
 
105
 
106
  if __name__ == "__main__":
 
4
  from dotenv import load_dotenv
5
  import os
6
  import asyncio
7
+ from src.utils import image_path_to_base64
8
  from dataclasses import dataclass
9
 
10
  load_dotenv()
 
76
 
77
  async def main():
78
  image_file_path = "./assets/lakeview.jpg"
79
+ image_base64 = image_path_to_base64(image_file_path)
80
+ image_url = f"data:image/jpeg;base64,{image_base64}"
 
 
81
 
82
+ prompt = "remove the light post"
83
+ messages = [
84
+ {
85
+ "type": "text",
86
+ "text": prompt
87
+ },
88
+ {
89
+ "type": "image_url",
90
+ "image_url": {
91
+ "url": image_url
 
92
  }
93
+ }
94
+ ]
95
 
96
+ deps = ImageEditDeps(
97
+ edit_instruction=prompt,
98
+ image_url=image_url
99
+ )
100
+ r = await mask_generation_agent.run(messages, deps=deps)
101
+ print(r.data)
102
 
103
 
104
  if __name__ == "__main__":
src/agents/mask_generation_agent.py CHANGED
@@ -3,11 +3,12 @@ from pydantic_ai.models.openai import OpenAIModel
3
  from dotenv import load_dotenv
4
  import os
5
  import asyncio
6
- import base64
7
  from dataclasses import dataclass
8
  import logfire
9
  from src.services.generate_mask import GenerateMaskService
10
  from src.hopter.client import Hopter, Environment, MagicReplaceInput
 
 
11
 
12
  load_dotenv()
13
 
@@ -38,7 +39,7 @@ class MaskGenerationResult:
38
 
39
  @dataclass
40
  class EditImageResult:
41
- edited_image_base64: str
42
 
43
  mask_generation_agent = Agent(
44
  model,
@@ -74,53 +75,52 @@ async def edit_object(ctx: RunContext[ImageEditDeps]) -> EditImageResult:
74
 
75
  # Generate mask
76
  print("Generating mask")
77
- mask_instruction = await mask_service.get_mask_generation_instruction(edit_instruction, image_url)
78
- mask = await mask_service.generate_mask(mask_instruction, image_url)
79
 
80
  # Magic replace
81
  input = MagicReplaceInput(image=image_url, mask=mask, prompt=mask_instruction.target_caption)
82
- result = await hopter_client.magic_replace(input)
83
  print("Exiting edit_object tool: ", result)
84
- return EditImageResult(edited_image_base64=result.base64_image)
 
 
85
 
86
  async def main():
87
  image_file_path = "./assets/lakeview.jpg"
88
- with open(image_file_path, "rb") as image_file:
89
- image_bytes = image_file.read()
90
- image_base64 = base64.b64encode(image_bytes).decode("utf-8")
91
- image_url = f"data:image/jpeg;base64,{image_base64}"
92
-
93
- prompt = "remove the light post"
94
- messages = [
95
- {
96
- "type": "text",
97
- "text": prompt
98
- },
99
- {
100
- "type": "image_url",
101
- "image_url": {
102
- "url": image_url
103
- }
104
  }
105
- ]
106
-
107
- # Initialize services
108
- hopter = Hopter(api_key=os.environ.get("HOPTER_API_KEY"), environment=Environment.STAGING)
109
- mask_service = GenerateMaskService(hopter=hopter)
110
-
111
- # Initialize dependencies
112
- deps = ImageEditDeps(
113
- edit_instruction=prompt,
114
- image_url=image_url,
115
- hopter_client=hopter,
116
- mask_service=mask_service
117
- )
118
- async with mask_generation_agent.run_stream(
119
- messages,
120
- deps=deps
121
- ) as result:
122
- async for message in result.stream():
123
- print(message)
 
124
 
125
 
126
  if __name__ == "__main__":
 
3
  from dotenv import load_dotenv
4
  import os
5
  import asyncio
 
6
  from dataclasses import dataclass
7
  import logfire
8
  from src.services.generate_mask import GenerateMaskService
9
  from src.hopter.client import Hopter, Environment, MagicReplaceInput
10
+ from src.services.image_uploader import ImageUploader
11
+ from src.utils import image_path_to_uri
12
 
13
  load_dotenv()
14
 
 
39
 
40
  @dataclass
41
  class EditImageResult:
42
+ edited_image_url: str
43
 
44
  mask_generation_agent = Agent(
45
  model,
 
75
 
76
  # Generate mask
77
  print("Generating mask")
78
+ mask_instruction = mask_service.get_mask_generation_instruction(edit_instruction, image_url)
79
+ mask = mask_service.generate_mask(mask_instruction, image_url)
80
 
81
  # Magic replace
82
  input = MagicReplaceInput(image=image_url, mask=mask, prompt=mask_instruction.target_caption)
83
+ result = hopter_client.magic_replace(input)
84
  print("Exiting edit_object tool: ", result)
85
+ uploader = ImageUploader(os.environ.get("IMG_BB_API_KEY"))
86
+ uploaded_image = uploader.upload_url(result.base64_image)
87
+ return EditImageResult(edited_image_url=uploaded_image.data.url)
88
 
89
  async def main():
90
  image_file_path = "./assets/lakeview.jpg"
91
+ image_url = image_path_to_uri(image_file_path)
92
+
93
+ prompt = "remove the light post"
94
+ messages = [
95
+ {
96
+ "type": "text",
97
+ "text": prompt
98
+ },
99
+ {
100
+ "type": "image_url",
101
+ "image_url": {
102
+ "url": image_url
 
 
 
 
103
  }
104
+ }
105
+ ]
106
+
107
+ # Initialize services
108
+ hopter = Hopter(api_key=os.environ.get("HOPTER_API_KEY"), environment=Environment.STAGING)
109
+ mask_service = GenerateMaskService(hopter=hopter)
110
+
111
+ # Initialize dependencies
112
+ deps = ImageEditDeps(
113
+ edit_instruction=prompt,
114
+ image_url=image_url,
115
+ hopter_client=hopter,
116
+ mask_service=mask_service
117
+ )
118
+ async with mask_generation_agent.run_stream(
119
+ messages,
120
+ deps=deps
121
+ ) as result:
122
+ async for message in result.stream():
123
+ print(message)
124
 
125
 
126
  if __name__ == "__main__":
src/hopter/client.py CHANGED
@@ -1,8 +1,7 @@
1
  import asyncio
2
  import httpx
3
  from enum import Enum
4
- from src.models.generate_mask_instruction import GenerateMaskInstruction
5
- import base64
6
  from dotenv import load_dotenv
7
  import os
8
  from pydantic import BaseModel, Field
@@ -48,12 +47,12 @@ class Hopter:
48
  ):
49
  self.api_key = api_key
50
  self.base_url = environment.base_url
51
- self.client = httpx.AsyncClient()
52
 
53
- async def generate_mask(self, input: RamGroundedSamInput) -> RamGroundedSamResult:
54
  print(f"Generating mask with input: {input.text_prompt}")
55
  try:
56
- response = await self.client.post(
57
  f"{self.base_url}/api/v1/services/ram-grounded-sam-api/predictions",
58
  headers={
59
  "Authorization": f"Bearer {self.api_key}",
@@ -61,7 +60,8 @@ class Hopter:
61
  },
62
  json={
63
  "input": input.model_dump()
64
- }
 
65
  )
66
  response.raise_for_status() # Raise an error for bad responses
67
  instance = response.json().get("output").get("instances")[0]
@@ -72,10 +72,10 @@ class Hopter:
72
  except Exception as exc:
73
  print(f"An unexpected error occurred: {exc}")
74
 
75
- async def magic_replace(self, input: MagicReplaceInput) -> MagicReplaceResult:
76
  print(f"Magic replacing with input: {input.prompt}")
77
  try:
78
- response = await self.client.post(
79
  f"{self.base_url}/api/v1/services/sdxl-magic-replace/predictions",
80
  headers={
81
  "Authorization": f"Bearer {self.api_key}",
@@ -83,9 +83,9 @@ class Hopter:
83
  },
84
  json={
85
  "input": input.model_dump()
86
- }
 
87
  )
88
- print(response)
89
  response.raise_for_status() # Raise an error for bad responses
90
  instance = response.json().get("output")
91
  print("Magic replaced.")
@@ -100,7 +100,7 @@ async def test_generate_mask(hopter: Hopter, image_url: str) -> str:
100
  text_prompt="pole",
101
  image_b64=image_url
102
  )
103
- mask = await hopter.generate_mask(input)
104
  return mask.mask_b64
105
 
106
  async def test_magic_replace(hopter: Hopter, image_url: str, mask: str, prompt: str) -> str:
@@ -109,7 +109,7 @@ async def test_magic_replace(hopter: Hopter, image_url: str, mask: str, prompt:
109
  mask=mask,
110
  prompt=prompt
111
  )
112
- result = await hopter.magic_replace(input)
113
  return result.base64_image
114
 
115
  async def main():
@@ -118,13 +118,11 @@ async def main():
118
  environment=Environment.STAGING
119
  )
120
  image_file_path = "./assets/lakeview.jpg"
121
- with open(image_file_path, "rb") as image_file:
122
- image_bytes = image_file.read()
123
- image_base64 = base64.b64encode(image_bytes).decode("utf-8")
124
- image_url = f"data:image/jpeg;base64,{image_base64}"
 
125
 
126
- mask = await test_generate_mask(hopter, image_url)
127
- magic_replace_result = await test_magic_replace(hopter, image_url, mask, "remove the pole")
128
- print(magic_replace_result)
129
  if __name__ == "__main__":
130
  asyncio.run(main())
 
1
  import asyncio
2
  import httpx
3
  from enum import Enum
4
+ from src.utils import image_path_to_uri
 
5
  from dotenv import load_dotenv
6
  import os
7
  from pydantic import BaseModel, Field
 
47
  ):
48
  self.api_key = api_key
49
  self.base_url = environment.base_url
50
+ self.client = httpx.Client()
51
 
52
+ def generate_mask(self, input: RamGroundedSamInput) -> RamGroundedSamResult:
53
  print(f"Generating mask with input: {input.text_prompt}")
54
  try:
55
+ response = self.client.post(
56
  f"{self.base_url}/api/v1/services/ram-grounded-sam-api/predictions",
57
  headers={
58
  "Authorization": f"Bearer {self.api_key}",
 
60
  },
61
  json={
62
  "input": input.model_dump()
63
+ },
64
+ timeout=None
65
  )
66
  response.raise_for_status() # Raise an error for bad responses
67
  instance = response.json().get("output").get("instances")[0]
 
72
  except Exception as exc:
73
  print(f"An unexpected error occurred: {exc}")
74
 
75
+ def magic_replace(self, input: MagicReplaceInput) -> MagicReplaceResult:
76
  print(f"Magic replacing with input: {input.prompt}")
77
  try:
78
+ response = self.client.post(
79
  f"{self.base_url}/api/v1/services/sdxl-magic-replace/predictions",
80
  headers={
81
  "Authorization": f"Bearer {self.api_key}",
 
83
  },
84
  json={
85
  "input": input.model_dump()
86
+ },
87
+ timeout=None
88
  )
 
89
  response.raise_for_status() # Raise an error for bad responses
90
  instance = response.json().get("output")
91
  print("Magic replaced.")
 
100
  text_prompt="pole",
101
  image_b64=image_url
102
  )
103
+ mask = hopter.generate_mask(input)
104
  return mask.mask_b64
105
 
106
  async def test_magic_replace(hopter: Hopter, image_url: str, mask: str, prompt: str) -> str:
 
109
  mask=mask,
110
  prompt=prompt
111
  )
112
+ result = hopter.magic_replace(input)
113
  return result.base64_image
114
 
115
  async def main():
 
118
  environment=Environment.STAGING
119
  )
120
  image_file_path = "./assets/lakeview.jpg"
121
+ image_url = image_path_to_uri(image_file_path)
122
+
123
+ mask = await test_generate_mask(hopter, image_url)
124
+ magic_replace_result = await test_magic_replace(hopter, image_url, mask, "remove the pole")
125
+ print(magic_replace_result)
126
 
 
 
 
127
  if __name__ == "__main__":
128
  asyncio.run(main())
src/services/generate_mask.py CHANGED
@@ -46,7 +46,7 @@ class GenerateMaskService:
46
  self.openai_file_upload = OpenAIFileUpload()
47
  self.hopter = hopter
48
 
49
- async def get_mask_generation_instruction(self, edit_instruction: str, image_url: str) -> GenerateMaskInstruction:
50
  messages = [
51
  {
52
  "role": "system",
@@ -77,7 +77,7 @@ class GenerateMaskService:
77
  instruction = response.choices[0].message.parsed
78
  return instruction
79
 
80
- async def generate_mask(self, mask_instruction: GenerateMaskInstruction, image_url: str) -> str:
81
  """
82
  Generate a mask for the image editing instruction.
83
 
@@ -91,7 +91,7 @@ class GenerateMaskService:
91
  text_prompt=mask_instruction.subject,
92
  image_b64=image_url
93
  )
94
- generate_mask_result = await self.hopter.generate_mask(input)
95
  return generate_mask_result.mask_b64
96
 
97
  async def main():
@@ -101,9 +101,9 @@ async def main():
101
  with open(image_file_path, "rb") as image_file:
102
  image_url = service.openai_file_upload.upload_image(image_file.read(), "vision")
103
 
104
- instruction = await service.get_mask_generation_instruction(edit_instruction, image_url)
105
  print(instruction)
106
- mask = await service.generate_mask(instruction, image_url)
107
  print(mask)
108
 
109
  if __name__ == "__main__":
 
46
  self.openai_file_upload = OpenAIFileUpload()
47
  self.hopter = hopter
48
 
49
+ def get_mask_generation_instruction(self, edit_instruction: str, image_url: str) -> GenerateMaskInstruction:
50
  messages = [
51
  {
52
  "role": "system",
 
77
  instruction = response.choices[0].message.parsed
78
  return instruction
79
 
80
+ def generate_mask(self, mask_instruction: GenerateMaskInstruction, image_url: str) -> str:
81
  """
82
  Generate a mask for the image editing instruction.
83
 
 
91
  text_prompt=mask_instruction.subject,
92
  image_b64=image_url
93
  )
94
+ generate_mask_result = self.hopter.generate_mask(input)
95
  return generate_mask_result.mask_b64
96
 
97
  async def main():
 
101
  with open(image_file_path, "rb") as image_file:
102
  image_url = service.openai_file_upload.upload_image(image_file.read(), "vision")
103
 
104
+ instruction = service.get_mask_generation_instruction(edit_instruction, image_url)
105
  print(instruction)
106
+ mask = service.generate_mask(instruction, image_url)
107
  print(mask)
108
 
109
  if __name__ == "__main__":
src/utils.py ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import base64
2
+ from fastapi import UploadFile
3
+ def image_path_to_base64(image_path: str) -> str:
4
+ with open(image_path, "rb") as image_file:
5
+ return base64.b64encode(image_file.read()).decode("utf-8")
6
+
7
+ def upload_file_to_base64(file: UploadFile) -> str:
8
+ return base64.b64encode(file.file.read()).decode("utf-8")
9
+
10
+ def image_path_to_uri(image_path: str) -> str:
11
+ return f"data:image/jpeg;base64,{image_path_to_base64(image_path)}"