Skip to content

Conversation

@soumik12345
Copy link
Contributor

@soumik12345 soumik12345 commented Sep 17, 2024

Continuing from #2078

This PR adds the autopatch integration with Google GenerativeAI SDK.

Tasks:

  • Non async, non streaming
  • Non async, streaming
  • Async, non streaming
  • Async, streaming
  • Add tests
  • Add docs

Examples

Non async, non streaming

import os
import google.generativeai as genai
import weave

genai.configure(api_key=os.environ["GOOGLE_API_KEY"])
weave.init(project_name="google_ai_studio-test")
model = genai.GenerativeModel("gemini-1.5-flash")
response = model.generate_content("Write a story about an AI and magic")

Non async, streaming

import os
import google.generativeai as genai
import weave

genai.configure(api_key=os.environ["GOOGLE_API_KEY"])
weave.init(project_name="google_ai_studio-test")
model = genai.GenerativeModel("gemini-1.5-flash")
response = model.generate_content("Write a story about an AI and magic", stream=True)
chunks = [chunk.text for chunk in response]

Async, non streaming

import os
import asyncio
import google.generativeai as genai
import weave

genai.configure(api_key=os.environ["GOOGLE_API_KEY"])
weave.init(project_name="google_ai_studio-test")
model = genai.GenerativeModel("gemini-1.5-flash")

async def async_generate():
    response = await model.generate_content_async(
        "Write a story about an AI and magic"
    )
    return response

response = asyncio.run(async_generate())

Async Streaming

import os
import asyncio
import google.generativeai as genai
import weave

genai.configure(api_key=os.environ["GOOGLE_API_KEY"])
weave.init(project_name="google_ai_studio-test")
model = genai.GenerativeModel("gemini-1.5-flash")

async def get_response():
    async for chunk in await model.generate_content_async(
        "Write a story about an AI and magic", stream=True
    ):
        if chunk.text:
            print(chunk.text)
        print("_" * 80)


response = asyncio.run(get_response())

@soumik12345 soumik12345 self-assigned this Sep 17, 2024
@soumik12345 soumik12345 requested a review from a team as a code owner September 17, 2024 08:26
@circle-job-mirror
Copy link

circle-job-mirror bot commented Sep 17, 2024

acc = value
if not acc._done:
return value
if acc != value:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this if correct? What if the acc is done and it's the same as the value (e.g. you return just 1 token)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If i don't add this if, the first token is being accumulated twice, both in the weave trace as well as in the output of the function. I agree that this is not the best way to tackle this issue and I'm open to suggestions to improve the logic here.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you saying that adding the accumulator modifies the output of the function? It shouldn't do that -- we should never modify the user's output

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I placed the check to prevent modification of output.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry, I don't understand.

Here's what I think I'm reading:

  1. If the acc is fresh, use the first value of the iterator
  2. While the acc is not finished, use the next values
  3. If acc != value, then aggregate the candidate completions

So open questions are:

  1. How does the above modify the user's output? It shouldn't. We should only be "listening" to the stream
  2. Why do we need the acc != value check? I guess there's an interaction with _done, but I'm not sure how

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

raise TypeError(
f"Cannot call next on an iterator of type {type(self._iterator_or_ctx_manager)}"
)
self._iterator_or_ctx_manager = iter(self._iterator_or_ctx_manager) # type: ignore
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you putting a type ignore here?

Is this safe? I think it assumes that whatever is yielded by the contextmanager is iter-able

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I don't put type ignore here, its failing the mypy checks.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The point of mypy is to check if it's type-safe, and the ignore here suggests that it's not. Can you please remove the ignore and fix?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We added this back then when the class was extended to support context manager for Anthropic, I pushed a hacky fix

@andrewtruong andrewtruong merged commit c37f9d2 into master Oct 15, 2024
@andrewtruong andrewtruong deleted the feat/google-genai-sdk branch October 15, 2024 19:10
@github-actions github-actions bot locked and limited conversation to collaborators Oct 15, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants