8000 style: :lipstick: update lint problems · codefromthecrypt/adk-python@ad2abf5 · GitHub
[go: up one dir, main page]

Skip to content

Commit ad2abf5

Browse files
committed
style: 💄 update lint problems
1 parent 5480f0d commit ad2abf5

File tree

2 files changed

+435
-433
lines changed

2 files changed

+435
-433
lines changed

src/google/adk/models/gemini_llm_connection.py

Lines changed: 183 additions & 185 deletions
Original file line numberDiff line numberDiff line change
@@ -25,191 +25,189 @@
2525

2626

2727
class GeminiLlmConnection(BaseLlmConnection):
28-
"""The Gemini model connection."""
29-
30-
def __init__(self, gemini_session: live.AsyncSession):
31-
self._gemini_session = gemini_session
32-
33-
async def send_history(self, history: list[types.Content]):
34-
"""Sends the conversation history to the gemini model.
35-
36-
You call this method right after setting up the model connection.
37-
The model will respond if the last content is from user, otherwise it will
38-
wait for new user input before responding.
39-
40-
Args:
41-
history: The conversation history to send to the model.
42-
"""
43-
44-
# TODO: Remove this filter and translate unary contents to streaming
45-
# contents properly.
46-
47-
# We ignore any audio from user during the agent transfer phase
48-
contents = [
49-
content for content in history if content.parts and content.parts[0].text
50-
]
51-
52-
if contents:
53-
await self._gemini_session.send(
54-
input=types.LiveClientContent(
55-
turns=contents,
56-
turn_complete=contents[-1].role == "user",
57-
),
58-
)
59-
else:
60-
logger.info("no content is sent")
61-
62-
async def send_content(self, content: types.Content):
63-
"""Sends a user content to the gemini model.
64-
65-
The model will respond immediately upon receiving the content.
66-
If you send function responses, all parts in the content should be function
67-
responses.
68-
69-
Args:
70-
content: The content to send to the model.
71-
"""
72-
73-
assert content.parts
74-
if content.parts[0].function_response:
75-
# All parts have to be function responses.
76-
function_responses = [part.function_response for part in content.parts]
77-
logger.debug("Sending LLM function response: %s", function_responses)
78-
await self._gemini_session.send(
79-
input=types.LiveClientToolResponse(
80-
function_responses=function_responses
81-
),
82-
)
83-
else:
84-
logger.debug("Sending LLM new content %s", content)
85-
await self._gemini_session.send(
86-
input=types.LiveClientContent(
87-
turns=[content],
88-
turn_complete=True,
28+
"""The Gemini model connection."""
29+
30+
def __init__(self, gemini_session: live.AsyncSession):
31+
self._gemini_session = gemini_session
32+
33+
async def send_history(self, history: list[types.Content]):
34+
"""Sends the conversation history to the gemini model.
35+
36+
You call this method right after setting up the model connection.
37+
The model will respond if the last content is from user, otherwise it will
38+
wait for new user input before responding.
39+
40+
Args:
41+
history: The conversation history to send to the model.
42+
"""
43+
44+
# TODO: Remove this filter and translate unary contents to streaming
45+
# contents properly.
46+
47+
# We ignore any audio from user during the agent transfer phase
48+
contents = [
49+
content
50+
for content in history
51+
if content.parts and content.parts[0].text
52+
]
53+
54+
if contents:
55+
await self._gemini_session.send(
56+
input=types.LiveClientContent(
57+
turns=contents,
58+
turn_complete=contents[-1].role == 'user',
59+
),
60+
)
61+
else:
62+
logger.info('no content is sent')
63+
64+
async def send_content(self, content: types.Content):
65+
"""Sends a user content to the gemini model.
66+
67+
The model will respond immediately upon receiving the content.
68+
If you send function responses, all parts in the content should be function
69+
responses.
70+
71+
Args:
72+
content: The content to send to the model.
73+
"""
74+
75+
assert content.parts
76+
if content.parts[0].function_response:
77+
# All parts have to be function responses.
78+
function_responses = [part.function_response for part in content.parts]
79+
logger.debug('Sending LLM function response: %s', function_responses)
80+
await self._gemini_session.send(
81+
input=types.LiveClientToolResponse(
82+
function_responses=function_responses
83+
),
84+
)
85+
else:
86+
logger.debug('Sending LLM new content %s', content)
87+
await self._gemini_session.send(
88+
input=types.LiveClientContent(
89+
turns=[content],
90+
turn_complete=True,
91+
)
92+
)
93+
94+
async def send_realtime(self, blob: types.Blob):
95+
"""Sends a chunk of audio or a frame of video to the model in realtime.
96+
97+
Args:
98+
blob: The blob to send to the model.
99+
"""
100+
101+
input_blob = blob.model_dump()
102+
logger.debug('Sending LLM Blob: %s', input_blob)
103+
await self._gemini_session.send(input=input_blob)
104+
105+
def __build_full_text_response(self, text: str):
106+
"""Builds a full text response.
107+
108+
The text should not partial and the returned LlmResponse is not be
109+
partial.
110+
111+
Args:
112+
text: The text to be included in the response.
113+
114+
Returns:
115+
An LlmResponse containing the full text.
116+
"""
117+
return LlmResponse(
118+
content=types.Content(
119+
role='model',
120+
parts=[types.Part.from_text(text=text)],
121+
),
122+
)
123+
124+
async def receive(self) -> AsyncGenerator[LlmResponse, None]:
125+
"""Receives the model response using the llm server connection.
126+
127+
Yields:
128+
LlmResponse: The model response.
129+
"""
130+
131+
text = ''
132+
async for message in self._gemini_session.receive():
133+
logger.debug('Got LLM Live message: %s', message)
134+
if message.server_content:
135+
content = message.server_content.model_turn
136+
if content and content.parts:
137+
llm_response = LlmResponse(
138+
content=content, interrupted=message.server_content.interrupted
139+
)
140+
if content.parts[0].text:
141+
text += content.parts[0].text
142+
llm_response.partial = True
143+
# don't yield the merged text event when receiving audio data
144+
elif text and not content.parts[0].inline_data:
145+
yield self.__build_full_text_response(text)
146+
text = ''
147+
yield llm_response
148+
if (
149+
message.server_content.input_transcription
150+
and message.server_content.input_transcription.text
151+
):
152+
user_text = message.server_content.input_transcription.text
153+
parts = [
154+
types.Part.from_text(
155+
text=user_text,
89156
)
157+
]
158+
llm_response = LlmResponse(
159+
content=types.Content(role='user', parts=parts)
90160
)
161+
yield llm_response
162+
if (
163+
message.server_content.output_transcription
164+
and message.server_content.output_transcription.text
165+
):
166+
# TODO: Right now, we just support output_transcription without
167+
# changing interface and data protocol. Later, we can consider to
168+
# support output_transcription as a separate field in LlmResponse.
169+
170+
# Transcription is always considered as partial event
171+
# We rely on other control signals to determine when to yield the
172+
# full text response(turn_complete, interrupted, or tool_call).
173+
text += message.server_content.output_transcription.text
174+
parts = [
175+
types.Part.from_text(
176+
text=message.server_content.output_transcription.text
177+
)
178+
]
179+
llm_response = LlmResponse(
180+
content=types.Content(role='model', parts=parts), partial=True
181+
)
182+
yield llm_response
183+
184+
if message.server_content.turn_complete:
185+
if text:
186+
yield self.__build_full_text_response(text)
187+
text = ''
188+
yield LlmResponse(
189+
turn_complete=True, interrupted=message.server_content.interrupted
190+
)
191+
break
192+
# in case of empty content or parts, we sill surface it
193+
# in case it's an interrupted message, we merge the previous partial
194+
# text. Other we don't merge. because content can be none when model
195+
# safety threshold is triggered
196+
if message.server_content.interrupted and text:
197+
yield self.__build_full_text_response(text)
198+
text = ''
199+
yield LlmResponse(interrupted=message.server_content.interrupted)
200+
if message.tool_call:
201+
if text:
202+
yield self.__build_full_text_response(text)
203+
text = ''
204+
parts = [
205+
types.Part(function_call=function_call)
206+
for function_call in message.tool_call.function_calls
207+
]
208+
yield LlmResponse(content=types.Content(role='model', parts=parts))
209+
210+
async def close(self):
211+
"""Closes the llm server connection."""
91212

92-
async def send_realtime(self, blob: types.Blob):
93-
"""Sends a chunk of audio or a frame of video to the model in realtime.
94-
95-
Args:
96-
blob: The blob to send to the model.
97-
"""
98-
99-
input_blob = blob.model_dump()
100-
logger.debug("Sending LLM Blob: %s", input_blob)
101-
await self._gemini_session.send(input=input_blob)
102-
103-
def __build_full_text_response(self, text: str):
104-
"""Builds a full text response.
105-
106-
The text should not partial and the returned LlmResponse is not be
107-
partial.
108-
109-
Args:
110-
text: The text to be included in the response.
111-
112-
Returns:
113-
An LlmResponse containing the full text.
114-
"""
115-
return LlmResponse(
116-
content=types.Content(
117-
role="model",
118-
parts=[types.Part.from_text(text=text)],
119-
),
120-
)
121-
122-
async def receive(self) -> AsyncGenerator[LlmResponse, None]:
123-
"""Receives the model response using the llm server connection.
124-
125-
Yields:
126-
LlmResponse: The model response.
127-
"""
128-
129-
text = ""
130-
async for message in self._gemini_session.receive():
131-
logger.debug("Got LLM Live message: %s", message)
132-
133-
if message.server_content:
134-
content = message.server_content.model_turn
135-
if content and content.parts:
136-
llm_response = LlmResponse(
137-
content=content, interrupted=message.server_content.interrupted
138-
)
139-
if content.parts[0].text:
140-
text += content.parts[0].text
141-
llm_response.partial = True
142-
# don't yield the merged text event when receiving audio data
143-
elif text and not content.parts[0].inline_data:
144-
yield self.__build_full_text_response(text)
145-
text = ""
146-
yield llm_response
147-
if (
148-
message.server_content.input_transcription
149-
and message.server_content.input_transcription.text
150-
):
151-
user_text = message.server_content.input_transcription.text
152-
parts = [
153-
types.Part.from_text(
154-
text=user_text,
155-
)
156-
]
157-
llm_response = LlmResponse(
158-
content=types.Content(role="user", parts=parts)
159-
)
160-
yield llm_response
161-
if (
162-
10000 message.server_content.output_transcription
163-
and message.server_content.output_transcription.text
164-
):
165-
# TODO: Right now, we just support output_transcription without
166-
# changing interface and data protocol. Later, we can consider to
167-
# support output_transcription as a separate field in LlmResponse.
168-
169-
# Transcription is always considered as partial event
170-
# We rely on other control signals to determine when to yield the
171-
# full text response(turn_complete, interrupted, or tool_call).
172-
text += message.server_content.output_transcription.text
173-
parts = [
174-
types.Part.from_text(
175-
text=message.server_content.output_transcription.text
176-
)
177-
]
178-
llm_response = LlmResponse(
179-
content=types.Content(role="model", parts=parts), partial=True
180-
)
181-
yield llm_response
182-
183-
if message.server_content.turn_complete:
184-
if text:
185-
yield self.__build_full_text_response(text)
186-
text = ""
187-
yield LlmResponse(
188-
turn_complete=True,
189-
interrupted=message.server_content.interrupted,
190-
)
191-
break
192-
# in case of empty content or parts, we sill surface it
193-
# in case it's an interrupted message, we merge the previous partial
194-
# text. Other we don't merge. because content can be none when model
195-
# safety threshold is triggered
196-
if message.server_content.interrupted and text:
197-
yield self.__build_full_text_response(text)
198-
text = ""
199-
yield LlmResponse(interrupted=message.server_content.interrupted)
200-
if message.tool_call:
201-
if text:
202-
yield self.__build_full_text_response(text)
203-
text = ""
204-
parts = [
205-
types.Part(function_call=function_call)
206-
for function_call in message.tool_call.function_calls
207-
]
208-
yield LlmResponse(content=types.Content(role="model", parts=parts))
209-
else:
210-
pass
211-
212-
async def close(self):
213-
"""Closes the llm server connection."""
214-
215-
await self._gemini_session.close()
213+
await self._gemini_session.close()

0 commit comments

Comments
 (0)
0