Skip to content

Commit 45a180b

Browse files
committed
addressing review comments
1 parent 7e3f46f commit 45a180b

File tree

17 files changed

+735
-690
lines changed

17 files changed

+735
-690
lines changed

.github/labeler.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,11 @@ integration:unstructured-fileconverter:
169169
- any-glob-to-any-file: "integrations/unstructured/**/*"
170170
- any-glob-to-any-file: ".github/workflows/unstructured.yml"
171171

172+
integration:watsonx:
173+
- changed-files:
174+
- any-glob-to-any-file: "integrations/watsonx/**/*"
175+
- any-glob-to-any-file: ".github/workflows/watsonx.yml"
176+
172177
integration:weaviate:
173178
- changed-files:
174179
- any-glob-to-any-file: "integrations/weaviate/**/*"

.github/workflows/watsonx.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ jobs:
3030
strategy:
3131
fail-fast: false
3232
matrix:
33-
os: [ubuntu-latest] # Start with Linux only, add others later
34-
python-version: ["3.9", "3.10", "3.11", "3.12"] # Watsonx supported versions
33+
os: [ubuntu-latest, windows-latest, macos-latest]
34+
python-version: ["3.10", "3.12"]
3535

3636
steps:
3737
- uses: actions/checkout@v4
@@ -49,10 +49,10 @@ jobs:
4949

5050
- name: Lint
5151
if: matrix.python-version == '3.9' && runner.os == 'Linux'
52-
run: hatch run lint
52+
run: hatch run fmt-check && hatch run test:types
5353

5454
- name: Run tests
55-
run: hatch run test
55+
run: hatch run test:cov-retry
5656

5757
- name: Run unit tests with lowest direct dependencies
5858
run: |

integrations/watsonx/examples/chat_generator_example.py

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,33 @@
22
import asyncio
33
import os
44

5+
import nest_asyncio
56
from haystack.dataclasses import ChatMessage
67
from haystack.utils.auth import Secret
78

89
from haystack_integrations.components.generators.watsonx.chat.chat_generator import WatsonxChatGenerator
910

1011
# Initialize the generator
1112
generator = WatsonxChatGenerator(
12-
api_key=Secret.from_env_var('WATSONX_API_KEY'), # Or use from_token("<apikey>")
13-
model='meta-llama/llama-3-2-1b-instruct',
14-
project_id=os.getenv('WATSONX_PROJECT_ID'),
13+
api_key=Secret.from_env_var("WATSONX_API_KEY"), # Or use from_token("<apikey>")
14+
model="meta-llama/llama-3-2-1b-instruct",
15+
project_id=os.getenv("WATSONX_PROJECT_ID"),
1516
generation_kwargs={
16-
'max_tokens': 500,
17-
'temperature': 0.7,
18-
'top_p': 0.9,
17+
"max_tokens": 500,
18+
"temperature": 0.7,
19+
"top_p": 0.9,
1920
},
2021
tools=[
2122
{
22-
'name': 'get_weather',
23-
'description': 'Get the current weather in a given location',
24-
'parameters': {
25-
'type': 'object',
26-
'properties': {
27-
'location': {'type': 'string', 'description': 'The city and state, e.g. San Francisco, CA'},
28-
'unit': {'type': 'string', 'enum': ['celsius', 'fahrenheit'], 'default': 'celsius'},
23+
"name": "get_weather",
24+
"description": "Get the current weather in a given location",
25+
"parameters": {
26+
"type": "object",
27+
"properties": {
28+
"location": {"type": "string", "description": "The city and state, e.g. San Francisco, CA"},
29+
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"], "default": "celsius"},
2930
},
30-
'required': ['location'],
31+
"required": ["location"],
3132
},
3233
}
3334
],
@@ -39,8 +40,8 @@
3940
# Example 1: Basic synchronous chat
4041
def basic_chat():
4142
messages = [
42-
ChatMessage.from_system('You are a helpful assistant.'),
43-
ChatMessage.from_user('Explain quantum computing in simple terms'),
43+
ChatMessage.from_system("You are a helpful assistant."),
44+
ChatMessage.from_user("Explain quantum computing in simple terms"),
4445
]
4546
generator.run(messages)
4647

@@ -49,7 +50,7 @@ def basic_chat():
4950
def tool_calling_chat():
5051
messages = [ChatMessage.from_user("What's the weather in Berlin today?")]
5152
response = generator.run(messages)
52-
reply = response['replies'][0]
53+
reply = response["replies"][0]
5354
if reply.tool_calls:
5455
for _tool_call in reply.tool_calls:
5556
pass
@@ -59,14 +60,14 @@ def tool_calling_chat():
5960

6061
# Example 3: Streaming chat (sync)
6162
def streaming_chat():
62-
messages = [ChatMessage.from_user('Write a short poem about artificial intelligence')]
63+
messages = [ChatMessage.from_user("Write a short poem about artificial intelligence")]
6364
generator.run(messages, stream=True)
6465

6566

6667
# Example 4: Asynchronous chat
6768
def run_async_chat():
6869
async def _async_chat():
69-
messages = [ChatMessage.from_user('Tell me about the history of the internet')]
70+
messages = [ChatMessage.from_user("Tell me about the history of the internet")]
7071
await generator.run_async(messages)
7172

7273
_run_async(_async_chat)
@@ -75,7 +76,7 @@ async def _async_chat():
7576
# Example 5: Asynchronous streaming chat
7677
def run_async_streaming_chat():
7778
async def _async_streaming_chat():
78-
messages = [ChatMessage.from_user('Explain blockchain technology')]
79+
messages = [ChatMessage.from_user("Explain blockchain technology")]
7980
await generator.run_async(messages, stream=True)
8081

8182
_run_async(_async_streaming_chat)
@@ -90,16 +91,14 @@ def _run_async(coro_func):
9091
else:
9192
return loop.run_until_complete(coro_func())
9293
except RuntimeError:
93-
import nest_asyncio
94-
9594
nest_asyncio.apply()
9695
loop = asyncio.new_event_loop()
9796
asyncio.set_event_loop(loop)
9897
return loop.run_until_complete(coro_func())
9998

10099

101100
# Main
102-
if __name__ == '__main__':
101+
if __name__ == "__main__":
103102
basic_chat()
104103
tool_calling_chat()
105104
streaming_chat()

integrations/watsonx/examples/embedders_example.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,47 +8,47 @@
88
from haystack_integrations.components.embedders.watsonx.text_embedder import WatsonXTextEmbedder
99

1010
# Step 1: Set your credentials
11-
api_key = '<api-key>'
12-
project_id = '<project-id>'
11+
api_key = "<api-key>"
12+
project_id = "<project-id>"
1313

1414
# Step 2: Create document store
15-
document_store = InMemoryDocumentStore(embedding_similarity_function='cosine')
15+
document_store = InMemoryDocumentStore(embedding_similarity_function="cosine")
1616

1717
# Step 3: Prepare documents
1818
documents = [
19-
Document(content='I saw a black horse running'),
20-
Document(content='Germany has many big cities'),
21-
Document(content='My name is Wolfgang and I live in Berlin'),
19+
Document(content="I saw a black horse running"),
20+
Document(content="Germany has many big cities"),
21+
Document(content="My name is Wolfgang and I live in Berlin"),
2222
]
2323

2424
# Step 4: Embed documents
2525
document_embedder = WatsonXDocumentEmbedder(
26-
model='ibm/slate-125m-english-rtrvr',
26+
model="ibm/slate-125m-english-rtrvr",
2727
api_key=Secret.from_token(api_key),
2828
project_id=project_id,
29-
url='https://us-south.ml.cloud.ibm.com',
29+
url="https://us-south.ml.cloud.ibm.com",
3030
)
31-
documents_with_embeddings = document_embedder.run(documents)['documents']
31+
documents_with_embeddings = document_embedder.run(documents)["documents"]
3232

3333
document_store.write_documents(documents_with_embeddings)
3434

3535
# Step 5: Build pipeline
3636
query_pipeline = Pipeline()
3737
query_pipeline.add_component(
38-
'text_embedder',
38+
"text_embedder",
3939
WatsonXTextEmbedder(
40-
model='ibm/slate-125m-english-rtrvr',
40+
model="ibm/slate-125m-english-rtrvr",
4141
api_key=Secret.from_token(api_key),
4242
project_id=project_id,
43-
url='https://us-south.ml.cloud.ibm.com',
43+
url="https://us-south.ml.cloud.ibm.com",
4444
),
4545
)
46-
query_pipeline.add_component('retriever', InMemoryEmbeddingRetriever(document_store=document_store))
47-
query_pipeline.connect('text_embedder.embedding', 'retriever.query_embedding')
46+
query_pipeline.add_component("retriever", InMemoryEmbeddingRetriever(document_store=document_store))
47+
query_pipeline.connect("text_embedder.embedding", "retriever.query_embedding")
4848

4949
# Step 6: Run query
50-
query = 'Who lives in Berlin?'
51-
result = query_pipeline.run({'text_embedder': {'text': query}})
50+
query = "Who lives in Berlin?"
51+
result = query_pipeline.run({"text_embedder": {"text": query}})
5252

5353
# Step 7: Print result
5454

integrations/watsonx/examples/generator_example.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,18 @@
88

99
# Basic Usage of WatsonxGenerator
1010
generator = WatsonxGenerator(
11-
model='ibm/granite-13b-instruct-v2',
12-
api_key=Secret.from_env_var('WATSONX_API_KEY'),
13-
project_id=os.getenv('WATSONX_PROJECT_ID'),
11+
model="ibm/granite-13b-instruct-v2",
12+
api_key=Secret.from_env_var("WATSONX_API_KEY"),
13+
project_id=os.getenv("WATSONX_PROJECT_ID"),
1414
generation_kwargs={
15-
'max_new_tokens': 100,
16-
'temperature': 0.7,
17-
'top_p': 0.9,
18-
'decoding_method': 'sample',
19-
'concurrency_limit': 5,
15+
"max_new_tokens": 100,
16+
"temperature": 0.7,
17+
"top_p": 0.9,
18+
"decoding_method": "sample",
19+
"concurrency_limit": 5,
2020
},
2121
)
22-
prompts = ['Who is the president of the USA?', 'What is the tallest mountain?']
22+
prompts = ["Who is the president of the USA?", "What is the tallest mountain?"]
2323

2424
for prompt in prompts:
2525
result = generator.run(prompt)
@@ -32,19 +32,19 @@
3232

3333
# Initialize with streaming enabled
3434
streaming_generator = WatsonxGenerator(
35-
api_key=Secret.from_token(os.environ['WATSONX_API_KEY']),
36-
model='ibm/granite-13b-instruct-v2',
37-
project_id=os.environ['WATSONX_PROJECT_ID'],
38-
generation_kwargs={'max_new_tokens': 450, 'temperature': 0.9, 'top_p': 0.9, 'repetition_penalty': 1.2},
35+
api_key=Secret.from_token(os.environ["WATSONX_API_KEY"]),
36+
model="ibm/granite-13b-instruct-v2",
37+
project_id=os.environ["WATSONX_PROJECT_ID"],
38+
generation_kwargs={"max_new_tokens": 450, "temperature": 0.9, "top_p": 0.9, "repetition_penalty": 1.2},
3939
)
4040

4141
# Create pipeline
4242
streaming_pipeline = Pipeline()
43-
streaming_pipeline.add_component('generator', streaming_generator)
43+
streaming_pipeline.add_component("generator", streaming_generator)
4444

4545
# Run with streaming
46-
prompt = 'Write a short story about an AI assistant.'
47-
result = streaming_pipeline.run({'generator': {'prompt': prompt, 'stream': True}})
46+
prompt = "Write a short story about an AI assistant."
47+
result = streaming_pipeline.run({"generator": {"prompt": prompt, "stream": True}})
4848

4949
# Process streaming results
5050

integrations/watsonx/pyproject.toml

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,16 @@ name = "watsonx-haystack"
77
version = "0.1.0"
88
description = "Watsonx integration for Haystack"
99
readme = "README.md"
10-
requires-python = ">=3.9"
10+
requires-python = ">=3.10"
1111
license = "Apache-2.0"
12-
authors = [{ name = "Divya", email = "[email protected]" }]
12+
authors = [
13+
{ name = "Divya", email = "[email protected]" },
14+
{ name = "deepset GmbH", email = "[email protected]" },
15+
]
1316
classifiers = [
1417
"License :: OSI Approved :: Apache Software License",
1518
"Development Status :: 4 - Beta",
1619
"Programming Language :: Python",
17-
"Programming Language :: Python :: 3.9",
1820
"Programming Language :: Python :: 3.10",
1921
"Programming Language :: Python :: 3.11",
2022
"Programming Language :: Python :: 3.12",
@@ -47,7 +49,6 @@ dependencies = [
4749
docs = ["pydoc-markdown pydoc/config.yml"]
4850
fmt = "ruff check --fix {args:.} && ruff format {args:.}"
4951
fmt-check = "ruff check {args:.} && ruff format --check {args:.}"
50-
test = "pytest"
5152

5253
[tool.hatch.envs.test]
5354
dependencies = [
@@ -69,6 +70,12 @@ all = 'pytest {args:tests}'
6970
cov-retry = 'all --cov=haystack_integrations --reruns 3 --reruns-delay 30 -x'
7071
types = "mypy -p haystack_integrations.components.generators.watsonx {args}"
7172

73+
[tool.mypy]
74+
install_types = true
75+
non_interactive = true
76+
check_untyped_defs = true
77+
disallow_incomplete_defs = true
78+
7279
[tool.hatch.envs.docs]
7380
dependencies = ["haystack-pydoc-tools"]
7481

@@ -88,6 +95,7 @@ markers = [
8895
"integration: mark tests as integration tests"
8996
]
9097
asyncio_mode = "auto"
98+
asyncio_default_fixture_loop_scope = "class"
9199
addopts = "--tb=short -v"
92100

93101
[tool.black]
@@ -138,13 +146,8 @@ ignore = [
138146
known-first-party = ["haystack_integrations"]
139147

140148
[tool.ruff.lint.per-file-ignores]
141-
"examples/**" = ["T201", "RET505", "INP001"]
142-
"watsonx/tests/**" = ["ALL"]
143-
"tests/**" = ["ALL"]
144-
"**/test_*.py" = ["ALL"]
149+
# Tests can use magic values, assertions, and relative imports
150+
"tests/**/*" = ["PLR2004", "S101", "TID252"]
145151

146152
[tool.ruff.lint.flake8-tidy-imports]
147-
ban-relative-imports = "parents"
148-
149-
[tool.ruff.format]
150-
quote-style = "single"
153+
ban-relative-imports = "parents"
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
# SPDX-FileCopyrightText: 2025-present deepset GmbH <[email protected]>
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
14
from haystack_integrations.components.embedders.watsonx.document_embedder import WatsonXDocumentEmbedder
25
from haystack_integrations.components.embedders.watsonx.text_embedder import WatsonXTextEmbedder
36

4-
__all__ = ['WatsonXDocumentEmbedder', 'WatsonXTextEmbedder']
7+
__all__ = ["WatsonXDocumentEmbedder", "WatsonXTextEmbedder"]

0 commit comments

Comments
 (0)