Skip to content

Commit

Permalink
feat: add search example (#10)
Browse files Browse the repository at this point in the history
- Include a search example designed with UI and dynamiq code
integration.
  • Loading branch information
olbychos authored Oct 16, 2024
1 parent 530c152 commit b02820e
Show file tree
Hide file tree
Showing 6 changed files with 408 additions and 5 deletions.
10 changes: 5 additions & 5 deletions dynamiq/nodes/tools/scale_serp.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,11 +141,11 @@ def execute(

if self.is_optimized_for_agents:
result = (
"<Sources with URLs>\n",
"\n".join(sources_with_url),
"</Sources with URLs>\n\n<Search results>",
formatted_results,
"</Search results>",
"<Sources with URLs>\n"
+ "\n".join(sources_with_url)
+ "</Sources with URLs>\n\n<Search results>"
+ formatted_results
+ "</Search results>"
)
else:
urls = [result.get("link") for result in content_results]
Expand Down
94 changes: 94 additions & 0 deletions examples/use_case_search/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
## Search use - case

This project demonstrates two different approaches to building a web-based search application powered by **Dynamiq**. The main goal is to showcase how Dynamiq's workflows, agents, and tools can be used in a flexible manner to process user queries and provide synthesized, accurate search results in real-time.

The project has two stages:
1. **Stage 1**: Building the logic server programmatically using Dynamiq code, where we define nodes, agents, and tools, and then craft a workflow. The workflow is then integrated into a frontend app using Streamlit to create an interactive web search tool.
2. **Stage 2**: Using the **Dynamiq UI** to craft nodes, agents, and tools visually and deploy the logic via an API endpoint. This endpoint is then used as the backend for a Streamlit-based web application.

---

## Project Structure

```
README.md
app.py
run.sh
server.py
server_via_dynamiq.py
```

### Files Overview

- **README.md**: This file.
- **app.py**: The main entry point for the Streamlit app. It handles query input, processes queries using the server logic, and displays results in real-time.
- **run.sh**: A script to launch the application (optional, depending on setup).
- **server.py**: Contains the server logic for **Stage 1**, where Dynamiq workflows are defined programmatically. This server rephrases user queries, searches for results using a search tool, and synthesizes answers.
- **server_via_dynamiq.py**: A simplified server for **Stage 2**, which uses the Dynamiq UI to set up nodes, agents, and tools, and leverages an API endpoint to process queries.

---

## Stage 1: Programmatically Building the Search Application

In this stage, we manually define the logic server using Dynamiq's Python library.

### Key Components:

1. **Agents and Tools**:
- **Rephrasing Agent**: This agent rewrites the user's input query to make it more concise and optimized for search engines.
- **Search Tool**: This tool uses an external search engine (e.g., SERP Scale) to retrieve relevant information based on the rephrased query.
- **Answer Synthesizer Agent**: This agent synthesizes an answer from the search results and formats it according to the query.

2. **Workflow**:
- A workflow is defined using the agents and tools mentioned above. The query first goes through the rephrasing agent, then to the search tool, and finally to the answer synthesizer agent.

3. **Frontend**:
- A Streamlit-based frontend (`app.py`) allows users to input search queries, and it processes these queries through the defined workflow. The result is streamed back to the user in real time, showing both the sources of information and the final answer.

### How to Run:

Run the Streamlit app:
```
streamlit run app.py
```

---

## Stage 2: Building the Application Using Dynamiq UI

In this stage, we utilize the **Dynamiq UI** to visually create the workflow, agents, and tools. Once the workflow is set up, it is deployed as an API, which acts as a backend for the Streamlit app.

### Key Components:

1. **Dynamiq UI**:
- The agents and tools are created using Dynamiq's graphical interface.
- The workflow is deployed, and an API endpoint is provided to interact with the workflow.

2. **Backend**:
- The `server_via_dynamiq.py` file contains a simplified implementation that connects to the Dynamiq API. The queries are sent to this API, and the results are streamed back and displayed to the user in real time.

### How to Run:

1. Set up environment variables for the Dynamiq API:
```
export DYNAMIQ_ENDPOINT=<Your Dynamiq endpoint>
export DYNAMIQ_API_KEY=<Your Dynamiq API key>
```

2. Run the Streamlit app:
```
streamlit run app.py
```

---

## Conclusion

This project showcases two flexible approaches to building a search-based application using Dynamiq:

- In **Stage 1**, we manually define the workflow and integrate it into a Python-based backend.
- In **Stage 2**, we leverage the Dynamiq UI to deploy the backend as an API.

Both approaches allow for real-time query processing and answer synthesis, demonstrating the power and versatility of Dynamiq in creating intelligent search tools.

Feel free to experiment with both approaches depending on your needs and preferences!
71 changes: 71 additions & 0 deletions examples/use_case_search/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import time
import streamlit as st
from examples.use_case_search.server import process_query


def reset_conversation():
"""
Resets the conversation state, clearing query history and input fields.
"""
st.session_state.query_history = []
st.session_state.current_query = ""
st.session_state.clear_input = False


def initialize_session_state():
"""
Initializes session state variables if not already set.
"""
if "query_history" not in st.session_state:
st.session_state.query_history = []
if "current_query" not in st.session_state:
st.session_state.current_query = ""
if "clear_input" not in st.session_state:
st.session_state.clear_input = False


def handle_query_submission(query: str):
"""
Handles query submission and displays the result chunk by chunk.
Args:
query (str): The user input query.
"""
if query.strip():
st.session_state.query_history.append(query)
st.session_state.current_query = query

result_placeholder = st.empty()

with st.spinner("Processing your query..."):
result_text = ""
for chunk in process_query(query):
result_text += chunk + " "
result_placeholder.write(result_text.strip())
time.sleep(0.05)

st.session_state.clear_input = True
else:
st.warning("Please enter a query before submitting.")


def main():
st.title("Search Application")

initialize_session_state()

query = st.text_input("Enter your query:", value="", key="initial_input")

if st.button("Submit"):
handle_query_submission(query)

if st.button("Start New Query"):
reset_conversation()
st.experimental_rerun()

if st.session_state.clear_input:
st.session_state.clear_input = False


if __name__ == "__main__":
main()
3 changes: 3 additions & 0 deletions examples/use_case_search/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash

python -m streamlit run examples/use_case_search/app.py
156 changes: 156 additions & 0 deletions examples/use_case_search/server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import re

from dynamiq import Workflow
from dynamiq.callbacks import TracingCallbackHandler
from dynamiq.connections import ScaleSerp
from dynamiq.flows import Flow
from dynamiq.nodes import InputTransformer
from dynamiq.nodes.agents.simple import SimpleAgent
from dynamiq.nodes.tools.scale_serp import ScaleSerpTool
from dynamiq.runnables import RunnableConfig
from dynamiq.utils.logger import logger
from examples.llm_setup import setup_llm


def extract_tag_content(text, tag):
"""
Extract content wrapped within specific XML-like tags from the text.
Args:
text (str): The input text containing the tag.
tag (str): The tag name to extract content from.
Returns:
str: The content inside the tag if found, otherwise None.
"""
pattern = rf"<{tag}>(.*?)</{tag}>"
match = re.search(pattern, text, re.DOTALL)
return match.group(1).strip() if match else None


AGENT_QUERY_ROLE = """
You are an AI assistant tasked with processing and refactoring search queries.
Your goal is to rewrite queries to be more concise, clear, and useful for search engines. Follow these guidelines:
1. Remove unnecessary words like "what is," "who is," "where is," etc.
2. Convert questions into declarative statements
3. Focus on the core subject of the query
4. Maintain essential keywords
5. Ensure the refactored query is grammatically correct
Here are some examples of original queries and their refactored versions:
Original: "Who was the first person to walk on the moon?"
Refactored: "First person to walk on the moon"
Original: "What are the ingredients in a chocolate chip cookie?"
Refactored: "Chocolate chip cookie ingredients"
Original: "How tall is the Eiffel Tower?"
Refactored: "Eiffel Tower height"
Rewrite the query according to the guidelines provided. Output your refactored version, without any additional wording.
""" # noqa E501
AGENT_ANSWER_ROLE = """
You are an AI assistant tasked with synthesizing answers from search results.
Your goal is to provide a concise and informative answer based on the following search results and user query.
Here are the search results:
<search_results>
{search_results}
</search_results>
And here is the user's query:
<user_query>
{user_query}
</user_query>
To complete this task, follow these steps:
1. Carefully read through the search results and identify the most relevant information that addresses the user's query.
2. Synthesize the information from multiple sources to create a comprehensive and accurate answer.
3. As you craft your answer, cite your sources using numbered markdown links formatted as [1], [2], etc. Each citation should correspond to a source in your source list.
4. Write your answer in a clear, concise, and journalistic tone. Avoid unnecessary jargon and explain any complex concepts in simple terms.
5. Ensure that your answer is well-structured and easy to read. Use paragraphs to separate different ideas or aspects of the answer.
6. After your main answer, provide a numbered list of sources. Format each source as follows:
[number]. Source name (source URL)
Provide your synthesized answer within <answer> tags, followed by the source list within <sources> tags using link formatting like in markdown.
Your response should look like this:
<answer>
Your synthesized answer here, with citations like this [1] and this [2].
</answer>
<sources>
1. [Source Name 1](http://www.example1.com)
2. [Source Name 2](http://www.example2.com)
</sources>
Remember to focus on accuracy, clarity, and proper citation in your response.
If there are errors with the query or you are unable to craft a response, provide polite feedback within the <answer> tags.
Explain that you are not able to find the answer and provide some suggestions for the user to improve the query.
""" # noqa E501

# Setup models
llm_mini = setup_llm(model_provider="gpt", model_name="gpt-4o-mini", max_tokens=500, temperature=0.5)
llm = setup_llm(model_provider="gpt", model_name="gpt-4o", max_tokens=3000, temperature=0.1)
# Define agents and search tool
agent_query_rephraser = SimpleAgent(
id="agent_query_rephraser",
name="agent_query_rephraser",
role=AGENT_QUERY_ROLE,
llm=llm_mini,
)

search_tool = ScaleSerpTool(
name="search_tool",
id="search_tool",
connection=ScaleSerp(params={"location": "USA, United Kingdom, Europe"}),
limit=5,
is_optimized_for_agents=True,
).depends_on(agent_query_rephraser)
search_tool.input_transformer = InputTransformer(selector={"input": "$[agent_query_rephraser].output.content"})

agent_answer_synthesizer = SimpleAgent(
id="agent_answer_synthesizer",
name="agent_answer_synthesizer",
role=AGENT_ANSWER_ROLE,
llm=llm,
).depends_on([search_tool, agent_query_rephraser])
agent_answer_synthesizer._prompt_variables.update({"search_results": "{search_results}", "user_query": "{user_query}"})
agent_answer_synthesizer.input_transformer = InputTransformer(
selector={
"input": "",
"search_results": "$[search_tool].output.content",
"user_query": "$[agent_query_rephraser].output.content",
}
)

tracing = TracingCallbackHandler()
wf = Workflow(flow=Flow(nodes=[agent_query_rephraser, search_tool, agent_answer_synthesizer]), callbacks=[tracing])


def process_query(query: str):
"""
Process the user's query through a workflow that rephrases, searches, and synthesizes an answer.
Yields results chunk by chunk to simulate real-time streaming of data.
Args:
query (str): The original user query.
Yields:
str: Chunks of the final result (sources and answer).
"""
try:
# Run the workflow with the provided query
result = wf.run(input_data={"input": query}, config=RunnableConfig(callbacks=[tracing]))

output_content = result.output[agent_answer_synthesizer.id]["output"].get("content")
logger.info(f"Workflow result: {output_content}")

answer = extract_tag_content(output_content, "answer")
sources = extract_tag_content(output_content, "sources")

if answer and sources:
# Stream the sources first
yield "Sources:\n\n"
for source_chunk in sources.split("\n"):
yield source_chunk + "\n\n"

# Stream the answer next
yield "\n\nAnswer:\n\n"
for answer_chunk in answer.split(" "):
yield answer_chunk + " "
else:
yield "Error: Unable to extract answer or sources from the workflow output."

except Exception as e:
logger.error(f"An error occurred while processing the query: {e}")
yield f"Error: {str(e)}"
Loading

1 comment on commit b02820e

@github-actions
Copy link

Choose a reason for hiding this comment

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

Coverage

Coverage Report
FileStmtsMissCoverMissing
dynamiq
   __init__.py30100% 
dynamiq/cache
   __init__.py10100% 
   codecs.py11281%16, 27
   config.py14192%34
   utils.py260100% 
dynamiq/cache/backends
   __init__.py20100% 
   base.py23578%34, 47, 59, 72, 84
   redis.py16475%20, 22, 48, 59
dynamiq/cache/managers
   __init__.py20100% 
   base.py39489%117–118, 120, 146
   workflow.py28292%73–74
dynamiq/callbacks
   __init__.py30100% 
   base.py491275%19, 31, 43, 79, 115, 132, 168, 187, 205, 209–210, 212
   streaming.py551572%96, 126–127, 135, 160–161, 169–174, 182, 190–191
   tracing.py169497%64, 120, 485, 507
dynamiq/clients
   __init__.py10100% 
   base.py8275%5, 21
dynamiq/components
   __init__.py00100% 
   serializers.py27966%25, 40, 58, 70, 101, 120, 122, 134, 136
dynamiq/components/converters
   __init__.py00100% 
   base.py491569%43, 48–50, 53–54, 61–62, 64–65, 98, 102, 107, 118, 122
   pptx.py34973%59–61, 66, 96–97, 101–102, 104
   pypdf.py602066%71–72, 77, 100–102, 125–135, 137–138, 140
   unstructured.py1165156%63, 69–70, 82–83, 90, 105–107, 109, 143, 194–195, 200, 220–221, 228–229, 232, 281–283, 285, 292–302, 304–305, 307, 312–325
   utils.py11463%23–25, 27
dynamiq/components/embedders
   __init__.py00100% 
   base.py71691%76, 80, 137–138, 159, 163
   bedrock.py18477%19, 26–28
   cohere.py18288%21, 29
   huggingface.py10190%19
   mistral.py10190%19
   openai.py16287%44, 51
   watsonx.py10190%19
dynamiq/components/retrievers
   __init__.py00100% 
   chroma.py19289%33–34
   pinecone.py17288%34–35
   qdrant.py17288%31–32
   weaviate.py19289%31–32
dynamiq/components/splitters
   __init__.py00100% 
   document.py551081%60, 63, 83, 88, 97, 118, 123–124, 126, 149
dynamiq/connections
   __init__.py20100% 
   connections.py3524686%13–17, 99, 107, 118, 141, 478, 480, 582–583, 585–586, 590–591, 593–594, 607–608, 610, 638, 640, 652, 654–656, 697–698, 720–721, 727–729, 731–734, 736, 753–754, 791–792, 800, 908
   managers.py60591%70–71, 107, 167, 179
   storages.py14192%51
dynamiq/executors
   __init__.py00100% 
   base.py12283%35, 58
   pool.py601181%90, 111–112, 115, 163–164, 179, 192, 203–204, 215
dynamiq/flows
   __init__.py20100% 
   base.py25196%35
   flow.py1273175%68, 75, 82, 116, 159–161, 246–247, 249, 268–269, 271, 274, 293–294, 297–298, 301–302, 304–305, 308–310, 312–316, 318
dynamiq/loaders
   __init__.py00100% 
   yaml.py2999069%55, 58, 62–63, 66–69, 72, 97, 101, 112–113, 138, 145–146, 177, 204, 228, 231, 234, 237, 257–261, 264, 284–288, 291–292, 318–319, 324–325, 330–331, 373, 376–377, 388–391, 404–405, 443, 446, 449, 481, 485, 503–504, 588–589, 591–592, 596–599, 601, 606, 645, 648, 655, 663, 676–677, 709, 711, 714, 719, 746, 750, 754, 758–759, 812–813, 842, 891–895
dynamiq/memory
   __init__.py10100% 
   memory.py592852%17, 33–35, 50, 53, 56, 60–61, 67–77, 79, 83, 87–92
dynamiq/memory/backend
   __init__.py50100% 
   base.py18572%12, 17, 22, 27, 32
   in_memory.py704634%19–22, 26–27, 31, 35–39, 41–49, 51, 67–68, 76–81, 83–84, 88–89, 91–100, 104, 108
   pinecone.py826323%30–32, 34–38, 40–43, 47–48, 54, 58–61, 65–70, 74–75, 80, 88–90, 94–100, 106–108, 115–119, 123–128, 130, 132, 136–140, 144–147
   qdrant.py806025%26–28, 30–33, 36–37, 41–42, 48–49, 53–57, 67–68, 72–73, 79–82, 87–92, 99–102, 108, 110–112, 116–121, 123–125, 129–135, 139–142
   sqlite.py1199421%50–51, 53–56, 60–61, 63–67, 69–71, 73, 75–76, 80–87, 91–96, 106, 108–109, 113–119, 124–125, 129–135, 137–138, 142–149, 153–156, 158–160, 162–164, 166–168, 171–173, 175–176, 178–182, 184–187, 189, 191–192, 194–195
dynamiq/nodes
   __init__.py20100% 
   exceptions.py13192%4
   managers.py12741%28–34
   node.py2794384%212, 223, 240, 243, 246, 264, 474–476, 545–551, 553–558, 562, 564, 566, 736, 753–754, 757–758, 761–762, 764–765, 768–769, 771, 783–785, 804, 829, 834
   types.py230100% 
dynamiq/nodes/agents
   __init__.py40100% 
   base.py2318662%80, 84–87, 93, 96–98, 123, 127, 164, 179–180, 186–190, 210, 212–213, 216, 223–225, 229–230, 235–239, 241–242, 244–247, 259–260, 264–266, 271, 275, 277, 283–287, 289–290, 306, 311, 344–345, 349–350, 354, 358, 362, 368–371, 375–377, 381, 383–384, 386–387, 389, 394–395, 402, 405, 409–410, 414–415, 419–420
   exceptions.py15380%7–8, 61
   react.py16412623%192, 241, 282–283, 287–289, 291–294, 302, 306–307, 309–310, 312, 315–317, 324, 344–345, 347–348, 354, 356, 358–364, 367, 379, 381–382, 386–387, 389–394, 398–402, 404, 406–408, 411–412, 414–417, 419, 422, 426–428, 431–432, 434–437, 439–446, 448–450, 452–455, 457, 461–462, 464, 466, 475–476, 481, 483–489, 493, 495, 503–506, 508, 512–514, 518, 520, 528–538, 540
   reflection.py362433%43–44, 47–48, 51, 64–66, 68–71, 73, 76–77, 80–81, 83–85, 87–90
   simple.py30100% 
dynamiq/nodes/audio
   __init__.py20100% 
   elevenlabs.py76692%39, 41, 89, 127, 172, 214
   whisper.py47882%46, 72, 79–80, 82, 108, 124, 126
dynamiq/nodes/converters
   __init__.py40100% 
   llm_text_extractor.py17312130%14, 49–53, 107–108, 114, 124, 132–134, 145–147, 175–177, 179, 187, 210–211, 213, 215–218, 225–226, 233–234, 236–239, 241–243, 245–246, 248–253, 255, 267, 269, 290, 292, 294–296, 298, 302, 326–327, 332, 334–335, 344, 348, 363, 370, 372–375, 389–390, 392–397, 410, 433–439, 442–443, 496, 498–500, 527–529, 531, 539, 562–563, 565, 567–570, 577–578, 585–586, 588–591, 593–594, 596–601, 603
   pptx.py31196%33
   pypdf.py32196%34
   unstructured.py39197%58
dynamiq/nodes/embedders
   __init__.py60100% 
   bedrock.py53296%48, 135
   cohere.py53296%48, 136
   huggingface.py53296%48, 137
   mistral.py53296%49, 137
   openai.py55296%53, 151
   watsonx.py53296%46, 130
dynamiq/nodes/llms
   __init__.py190100% 
   ai21.py9188%24
   anthropic.py8187%22
   anyscale.py9188%24
   azureai.py9188%24
   base.py91495%13, 164, 239, 241
   bedrock.py9188%24
   cerebras.py9188%24
   cohere.py8362%21–23
   custom_llm.py40100% 
   deepinfra.py9188%24
   gemini.py22195%45
   groq.py9188%24
   huggingface.py9188%24
   mistral.py9188%24
   openai.py8187%22
   replicate.py9188%24
   sambanova.py9366%23–25
   togetherai.py9188%24
   watsonx.py9188%24
dynamiq/nodes/operators
   __init__.py10100% 
   operators.py1444072%158, 174, 176, 178, 180, 184–191, 193, 219–220, 222–224, 226–229, 231, 233–236, 238, 242, 266, 284–288, 290, 292–293, 295
dynamiq/nodes/retrievers
   __init__.py40100% 
   chroma.py370100% 
   pinecone.py410100% 
   qdrant.py370100% 
   weaviate.py370100% 
dynamiq/nodes/splitters
   __init__.py10100% 
   document.py300100% 
dynamiq/nodes/tools
   __init__.py80100% 
   e2b_sandbox.py13510224%81–83, 85, 89–94, 98–100, 104–106, 110–112, 116–122, 126–127, 129–134, 137–139, 141, 143–144, 148–155, 159–161, 165–166, 168–172, 176, 178–179, 181–182, 184–189, 191, 193–204, 212–214, 216–226, 228–229, 233–236
   firecrawl.py683647%59–60, 64–65, 73–74, 76, 82, 86–87, 89–92, 94, 105–106, 110–111, 117–120, 123, 125, 127–134, 138, 150, 152
   http_api_call.py47589%69, 81, 90, 99–100
   llm_summarizer.py552947%92–94, 100, 110, 122–124, 141–142, 148–151, 171–173, 175–176, 180–181, 186–188, 192–193, 195, 197, 201
   python.py512943%39–41, 70–71, 84, 86–88, 90–91, 93, 95–96, 98, 154–156, 158–159, 161–165, 179, 193–195
   scale_serp.py614427%56–57, 59–64, 66–67, 76, 91, 95–96, 98–100, 102–103, 107, 109, 111–112, 117–120, 123, 125, 127, 129–135, 137, 142–143, 151, 153, 160, 162
   tavily.py583343%78–86, 88, 104, 108–109, 111–112, 125, 127–128, 133–136, 139, 141, 143, 145, 149–150, 157–158, 161, 171, 173
   zenrows.py351945%50, 55–56, 58–60, 62, 67, 69, 74–77, 80, 82–83, 85–86, 88
dynamiq/nodes/utils
   __init__.py10100% 
   utils.py110100% 
dynamiq/nodes/validators
   __init__.py50100% 
   base.py22577%37–40, 45
   regex_match.py14192%37
   valid_choices.py9188%31
   valid_json.py10280%27–28
   valid_python.py8275%23–24
dynamiq/nodes/writers
   __init__.py40100% 
   chroma.py271062%37–39, 43, 47, 66–67, 69, 71–72
   pinecone.py29196%39
   qdrant.py28196%38
   weaviate.py291162%38–40, 44, 48, 66–67, 69, 71–72, 74
dynamiq/prompts
   __init__.py10100% 
   prompts.py841582%98, 141, 154, 197–201, 206–207, 216–217, 221, 223, 230
dynamiq/runnables
   __init__.py10100% 
   base.py45197%145
dynamiq/storages
   __init__.py00100% 
dynamiq/storages/vector
   __init__.py40100% 
   base.py50100% 
   exceptions.py60100% 
   policies.py60100% 
   utils.py20100% 
dynamiq/storages/vector/chroma
   __init__.py10100% 
   chroma.py18614919%10–11, 56–57, 62, 71, 89–91, 94, 96, 98–99, 101–102, 104, 106, 117–119, 123–124, 128, 140–141, 143–144, 154–155, 176–177, 183–184, 192, 237–239, 241–244, 246, 248, 252, 261–262, 284–285, 288–289, 292, 294–295, 298–300, 302–304, 306, 308–315, 317–319, 321–323, 325–327, 329, 338–341, 343–358, 360–361, 363–364, 366, 382–384, 387, 389, 402–403, 407, 423–425, 427, 429–430, 432, 446–449, 451–454, 459–460, 462–463, 465–466, 468–469, 471, 485–488, 490–491, 496–497, 499–500, 502–503, 505–506
dynamiq/storages/vector/pinecone
   __init__.py10100% 
   filters.py958015%22–24, 26–28, 45–50, 52–53, 55–56, 58–59, 75, 78, 80–88, 93, 95, 97, 114–116, 120, 122, 139–141, 145, 147, 164–166, 170, 172, 189–191, 195, 197, 214–216, 220, 222, 239–241, 245, 247, 264–265, 268, 270–273, 277, 279, 296–298, 300–303, 307, 309
   pinecone.py1275655%12, 63, 86–88, 96, 113–115, 120, 124–125, 135–137, 139–140, 144, 156, 160, 166–167, 169–170, 180–181, 194–196, 198–200, 202–204, 206, 213, 215–216, 225–226, 229–231, 247–248, 275–277, 280–281, 287–288, 290, 319–320
dynamiq/storages/vector/qdrant
   __init__.py10100% 
   converters.py411368%26, 28–30, 32–35, 67–68, 70–71, 75
   filters.py1333375%61–62, 65–66, 80–81, 91–92, 99, 111, 177–178, 186–187, 217–218, 227, 233–234, 261–262, 277, 282–283, 288, 293–294, 299, 304–305, 310, 315–316
   qdrant.py2667571%29, 239, 255, 279, 283, 301–302, 305, 334–335, 349–350, 390–391, 455, 495, 528–529, 533, 535–538, 550, 554–559, 601–604, 606–607, 643–644, 648, 650, 652–653, 676–678, 680, 682, 698–699, 704, 757–758, 770, 772, 777–778, 786, 788–789, 794, 796–798, 800–801, 803–804, 810, 812–813, 819, 852, 854, 906–907
dynamiq/storages/vector/weaviate
   __init__.py10100% 
   filters.py12610516%22–24, 26–28, 56–63, 65, 87–92, 94–99, 101–105, 107–108, 121–126, 140–142, 156–157, 159, 178–184, 188–189, 206–212, 216–217, 234–240, 244–245, 262–268, 272–273, 290–292, 294, 311–315, 343, 345, 351, 353–360, 362, 377–378
   weaviate.py16512723%17–18, 57–59, 67–68, 70, 80–81, 90–91, 103–105, 107–108, 110–111, 113, 125–126, 128, 130–133, 135, 137–139, 141–145, 147–148, 150, 158, 160, 172–174, 177–180, 195, 197–200, 203–204, 211–216, 228–229, 231–232, 244–245, 249–251, 267–271, 273, 279–284, 286, 292, 294, 311–316, 318, 321, 323–324, 330–337, 352–353, 355, 368–371, 373–375, 386–387, 389, 398–399, 418–419, 429, 457–459, 461–462, 473
dynamiq/types
   __init__.py10100% 
   document.py160100% 
   streaming.py31390%48, 56, 84
dynamiq/utils
   __init__.py20100% 
   duration.py11372%42–43, 45
   env.py70100% 
   jsonpath.py461469%18–19, 41, 43, 50–51, 55, 59–61, 84, 94–96
   logger.py100100% 
   utils.py621182%32, 34, 94–100, 150–151
dynamiq/workflow
   __init__.py10100% 
   workflow.py671774%15, 31, 34, 55, 57–58, 61–63, 65, 82–83, 86, 91–94
examples
   __init__.py00100% 
examples/rag
   __init__.py00100% 
   dag_yaml.py37878%65–67, 74–75, 81, 86, 88
   utils.py190100% 
tests
   __init__.py00100% 
   conftest.py78198%83
tests/integration
   __init__.py00100% 
tests/integration/flows
   __init__.py00100% 
tests/integration/nodes
   __init__.py00100% 
tests/integration/nodes/audio
   __init__.py00100% 
tests/integration/nodes/llms
   __init__.py00100% 
tests/integration/nodes/operators
   __init__.py00100% 
tests/integration/nodes/tools
   __init__.py00100% 
tests/integration/nodes/validators
   __init__.py00100% 
tests/integration_with_creds
   __init__.py00100% 
TOTAL6935222467% 

Tests Skipped Failures Errors Time
186 0 💤 0 ❌ 0 🔥 31.756s ⏱️

Please sign in to comment.