From 69010f3f6f14e14d33dc95a9692ed64f297d2694 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20K=C3=B6hnecke?= Date: Mon, 5 Aug 2024 12:29:06 +0200 Subject: [PATCH 01/16] feat: initial version of studio client --- docker-compose.yaml | 22 +++ env.sample | 1 + src/intelligence_layer/connectors/__init__.py | 1 + .../connectors/studio/studio.py | 134 ++++++++++++++++++ tests/connectors/studio/test_studio.py | 126 ++++++++++++++++ 5 files changed, 284 insertions(+) create mode 100644 src/intelligence_layer/connectors/studio/studio.py create mode 100644 tests/connectors/studio/test_studio.py diff --git a/docker-compose.yaml b/docker-compose.yaml index 263b62008..ffc8d92f2 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -38,6 +38,28 @@ services: image: ghcr.io/aleph-alpha/trace-viewer-trace-viewer:main ports: - 3000:3000 + + # export GITLAB_TOKEN=... + # (optional) export GITLAB_TOKEN=$(op item get YOUR_GITLAB_TOKEN_ENTRY --format json --fields password | jq .value) + # echo $GITLAB_TOKEN | docker login ghcr.io -u your_email@for_gitlab --password-stdin + # echo $GITLAB_TOKEN | docker login registry.gitlab.aleph-alpha.de -u your_email@for_gitlab --password-stdin + # docker compose pull to update containers + studio-backend: + image: registry.gitlab.aleph-alpha.de/product/studio/backend:latest + ports: + - 8000:8000 + depends_on: + postgres: + condition: service_started + restart: true + environment: + DATABASE_URL: postgres:5432 # This overrides the env file + POSTGRES_DB: il_sdk + POSTGRES_USER: il_sdk + POSTGRES_PASSWORD: test + + AUTHORIZATION_SERVICE_URL: "none" # This overrides the env file + postgres: image: postgres:15 ports: diff --git a/env.sample b/env.sample index c687dc0f8..2eb1a3a3a 100644 --- a/env.sample +++ b/env.sample @@ -5,3 +5,4 @@ ARGILLA_API_KEY="argilla.apikey" HUGGING_FACE_TOKEN=token # local dev builds run on 5173 TRACE_VIEWER_URL="http://localhost:3000" +STUDIO_URL=localhost:8000 diff --git a/src/intelligence_layer/connectors/__init__.py b/src/intelligence_layer/connectors/__init__.py index f5a246df9..026cbb3f5 100644 --- a/src/intelligence_layer/connectors/__init__.py +++ b/src/intelligence_layer/connectors/__init__.py @@ -44,5 +44,6 @@ QdrantInMemoryRetriever as QdrantInMemoryRetriever, ) from .retrievers.qdrant_in_memory_retriever import RetrieverType as RetrieverType +from .studio.studio import StudioClient as StudioClient __all__ = [symbol for symbol in dir() if symbol and symbol[0].isupper()] diff --git a/src/intelligence_layer/connectors/studio/studio.py b/src/intelligence_layer/connectors/studio/studio.py new file mode 100644 index 000000000..dc1532b0a --- /dev/null +++ b/src/intelligence_layer/connectors/studio/studio.py @@ -0,0 +1,134 @@ +import os +from collections.abc import Sequence +from typing import Optional +from urllib.parse import urljoin + +import requests +from pydantic import BaseModel +from requests.exceptions import ConnectionError, MissingSchema + +from intelligence_layer.core.tracer.tracer import ExportedSpan, ExportedSpanList + + +class StudioProject(BaseModel): + name: str + description: Optional[str] + + +class StudioClient: + def __init__( + self, + project: str, + studio_url: Optional[str] = None, + auth_token: Optional[str] = None, + ) -> None: + self._token = auth_token if auth_token is not None else os.getenv("AA_TOKEN") + if self._token is None: + raise ValueError( + "'AA_TOKEN' is not set and auth_token is not given as a parameter. Please provide one or the other." + ) + self._headers = { + "Content-Type": "application/json", + "Accept": "application/json", + "Authorization": f"Bearer {self._token}", + } + + temp_url = studio_url if studio_url is not None else os.getenv("STUDIO_URL") + if temp_url is None: + raise ValueError( + "'STUDIO_URL' is not set and url is not given as a parameter. Please provide one or the other." + ) + self.url = temp_url + + self._check_connection() + + self._project_name = project + self._project_id: int | None = None + + def _check_connection(self) -> None: + try: + url = urljoin(self.url, "/health") + response = requests.get( + url, + headers=self._headers, + ) + response.raise_for_status() + except MissingSchema: + raise ValueError( + "The given url of the studio client is invalid. Make sure to include http:// in your url." + ) from None + except ConnectionError: + raise ValueError( + "The given url of the studio client does not point to a server." + ) from None + except requests.HTTPError: + raise ValueError( + f"The given url of the studio client does not point to a healthy studio: {response.status_code}: {response.json()}" + ) from None + + @property + def project_id(self) -> int: + if self._project_id is None: + project_id = self._get_project(self._project_name) + if project_id is None: + raise ValueError( + f"Project {self._project_name} was not available. Consider creating it with `StudioClient.create_project`." + ) + self._project_id = project_id + return self._project_id + + def _get_project(self, project: str) -> int | None: + url = urljoin(self.url, "/api/projects") + response = requests.get( + url, + headers=self._headers, + ) + response.raise_for_status() + all_projects = response.json() + try: + project_of_interest = next( + proj for proj in all_projects if proj["name"] == project + ) + return int(project_of_interest["id"]) + except StopIteration: + return None + + def create_project(self, project: str, description: Optional[str] = None) -> int: + url = urljoin(self.url, "/api/projects") + data = StudioProject(name=project, description=description) + response = requests.post( + url, + data=data.model_dump_json(), + headers=self._headers, + ) + match response.status_code: + case 409: + raise ValueError("Project already exists") + case _: + response.raise_for_status() + return int(response.text) + + def submit_trace(self, data: Sequence[ExportedSpan]) -> str: + if len(data) == 0: + raise ValueError("Tried to upload an empty trace") + return self._upload_trace(ExportedSpanList(data)) + + def _upload_trace(self, trace: ExportedSpanList) -> str: + url = urljoin(self.url, f"/api/projects/{self.project_id}/traces") + response = requests.post( + url, + data=trace.model_dump_json(), + headers=self._headers, + ) + match response.status_code: + case 409: + raise ValueError( + f"Trace with id {trace.root[0].context.trace_id} already exists." + ) + case 422: + raise ValueError( + f"Uploading the trace failed with 422. Response: {response.json()}" + ) + case _: + response.raise_for_status() + return response.text diff --git a/tests/connectors/studio/test_studio.py b/tests/connectors/studio/test_studio.py new file mode 100644 index 000000000..1fa392c80 --- /dev/null +++ b/tests/connectors/studio/test_studio.py @@ -0,0 +1,126 @@ +import os +import time +from collections.abc import Sequence +from typing import Any +from unittest.mock import patch +from uuid import uuid4 + +import pytest +from dotenv import load_dotenv +from pytest import fixture + +from intelligence_layer.connectors import StudioClient +from intelligence_layer.core import ExportedSpan, InMemoryTracer, Task, TaskSpan + + +class TracerTestSubTask(Task[None, None]): + def do_run(self, input: None, task_span: TaskSpan) -> None: + task_span.log("subtask", "value") + + +class TracerTestTask(Task[str, str]): + sub_task = TracerTestSubTask() + + def do_run(self, input: str, task_span: TaskSpan) -> str: + time.sleep(0.001) + with task_span.span("span") as sub_span: + time.sleep(0.001) + sub_span.log("message", "a value") + time.sleep(0.001) + self.sub_task.run(None, sub_span) + time.sleep(0.001) + self.sub_task.run(None, task_span) + try: + with task_span.task_span("Error task", "myInput"): + raise ValueError("oops") + except Exception as _: + pass + time.sleep(0.001) + return "output" + + +@fixture +def test_trace() -> Sequence[ExportedSpan]: + tracer = InMemoryTracer() + task = TracerTestTask() + task.run("my input", tracer) + return tracer.export_for_viewing() + + +@fixture +def studio_client() -> StudioClient: + load_dotenv() + project_name = str(uuid4()) + client = StudioClient(project_name) + client.create_project(project_name) + return client + + +def test_cannot_connect_to_non_existing_project() -> None: + project_name = "non-existing-project" + with pytest.raises(ValueError, match=project_name): + StudioClient(project="non-existing-project").project_id # noqa: B018 + + +def test_cannot_create_the_same_project_twice() -> None: + project_name = str(uuid4()) + client = StudioClient(project="IL-default-project") + client.create_project(project_name) + with pytest.raises(ValueError, match="already exists"): + client.create_project(project_name) + + +def test_can_upload_trace( + test_trace: Sequence[ExportedSpan], studio_client: StudioClient +) -> None: + id = studio_client.submit_trace(test_trace) + + assert id == str(test_trace[0].context.trace_id) + + +def test_cannot_upload_empty_trace(studio_client: StudioClient) -> None: + with pytest.raises(ValueError, match="empty"): + studio_client.submit_trace([]) + + +def test_cannot_upload_same_trace_twice( + test_trace: Sequence[ExportedSpan], studio_client: StudioClient +) -> None: + studio_client.submit_trace(test_trace) + with pytest.raises(ValueError): + studio_client.submit_trace(test_trace) + + +def test_cannot_upload_lists_with_multiple_traces(studio_client: StudioClient) -> None: + tracer = InMemoryTracer() + with tracer.span("test"): + pass + with tracer.span("test2"): + pass + data = tracer.export_for_viewing() + + with pytest.raises(ValueError): + studio_client.submit_trace(data) + # TODO + + +def test_handles_invalid_url() -> None: + with pytest.raises(ValueError, match="invalid"): + StudioClient(str(uuid4), studio_url="unknown-url") + + +def test_handles_valid_but_incorrect_url() -> None: + with pytest.raises(ValueError, match="does not point to a server"): + StudioClient(str(uuid4), studio_url="http://invalid-test-url-123456543") + + +def test_handles_no_auth_configured() -> None: + def mock_return(var: Any) -> Any: + if var == "AA_TOKEN": + return None + else: + return os.environ[var] + + with patch("os.getenv", side_effect=mock_return) as _: # noqa: SIM117 + with pytest.raises(ValueError, match="auth_token"): + StudioClient(str(uuid4)) From d2b44fb32412d78471efd24294f1de8e325ad83c Mon Sep 17 00:00:00 2001 From: Merlin Kallenborn Date: Mon, 5 Aug 2024 14:32:27 +0200 Subject: [PATCH 02/16] fix:Add STUDIO_URL prefix, fix string in test --- env.sample | 2 +- src/intelligence_layer/connectors/studio/studio.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/env.sample b/env.sample index 2eb1a3a3a..a7e94aab4 100644 --- a/env.sample +++ b/env.sample @@ -5,4 +5,4 @@ ARGILLA_API_KEY="argilla.apikey" HUGGING_FACE_TOKEN=token # local dev builds run on 5173 TRACE_VIEWER_URL="http://localhost:3000" -STUDIO_URL=localhost:8000 +STUDIO_URL=http://localhost:8000 diff --git a/src/intelligence_layer/connectors/studio/studio.py b/src/intelligence_layer/connectors/studio/studio.py index dc1532b0a..d74bdd8f5 100644 --- a/src/intelligence_layer/connectors/studio/studio.py +++ b/src/intelligence_layer/connectors/studio/studio.py @@ -131,4 +131,4 @@ def _upload_trace(self, trace: ExportedSpanList) -> str: ) case _: response.raise_for_status() - return response.text + return str(response.json()) From a2e614a968639b2a0ee6181bfede08482146beba Mon Sep 17 00:00:00 2001 From: Merlin Kallenborn Date: Mon, 5 Aug 2024 16:43:04 +0200 Subject: [PATCH 03/16] feat: Add trace submission from tracer TASK: PHS-616 --- .../document_index/document_index.py | 2 +- .../connectors/studio/studio.py | 27 ++++++++++++++++- src/intelligence_layer/core/tracer/tracer.py | 5 ++++ tests/connectors/studio/test_studio.py | 29 ++++++++++++++++++- 4 files changed, 60 insertions(+), 3 deletions(-) diff --git a/src/intelligence_layer/connectors/document_index/document_index.py b/src/intelligence_layer/connectors/document_index/document_index.py index 6ce714eff..e09bf69b8 100644 --- a/src/intelligence_layer/connectors/document_index/document_index.py +++ b/src/intelligence_layer/connectors/document_index/document_index.py @@ -295,7 +295,7 @@ class DocumentIndexClient: Document Index is a tool for managing collections of documents, enabling operations such as creation, deletion, listing, and searching. Documents can be stored either in the cloud or in a local deployment. - Args: + Attributes: token: A valid token for the document index API. base_document_index_url: The url of the document index' API. diff --git a/src/intelligence_layer/connectors/studio/studio.py b/src/intelligence_layer/connectors/studio/studio.py index d74bdd8f5..79802bed8 100644 --- a/src/intelligence_layer/connectors/studio/studio.py +++ b/src/intelligence_layer/connectors/studio/studio.py @@ -1,4 +1,5 @@ import os +from collections import defaultdict from collections.abc import Sequence from typing import Optional from urllib.parse import urljoin @@ -7,7 +8,7 @@ from pydantic import BaseModel from requests.exceptions import ConnectionError, MissingSchema -from intelligence_layer.core.tracer.tracer import ExportedSpan, ExportedSpanList +from intelligence_layer.core.tracer.tracer import ExportedSpan, ExportedSpanList, Tracer class StudioProject(BaseModel): @@ -16,12 +17,29 @@ class StudioProject(BaseModel): class StudioClient: + """Client for communicating with PhariaStudio. + + Attributes: + project_id: The unique identifier of the project currently in use. + url: The url of your current PhariaStudio instance. + """ + def __init__( self, project: str, studio_url: Optional[str] = None, auth_token: Optional[str] = None, ) -> None: + """Initializes the client. + + Runs a health check to check for a valid url of the Studio connection. + It does not check for a valid authentication token, which happens later. + + Args: + project: The human readable identifier provided by the user. + studio_url: The url of your current PhariaStudio instance. + auth_token: The authorization bearer token of the user. This corresponds to the user's Aleph Alpha token. + """ self._token = auth_token if auth_token is not None else os.getenv("AA_TOKEN") if self._token is None: raise ValueError( @@ -113,6 +131,13 @@ def submit_trace(self, data: Sequence[ExportedSpan]) -> str: raise ValueError("Tried to upload an empty trace") return self._upload_trace(ExportedSpanList(data)) + def submit_from_tracer(self, tracer: Tracer) -> list[str]: + traces = defaultdict(list) + for span in tracer.export_for_viewing(): + traces[span.context.trace_id].append(span) + + return [self.submit_trace(value) for value in traces.values()] + def _upload_trace(self, trace: ExportedSpanList) -> str: url = urljoin(self.url, f"/api/projects/{self.project_id}/traces") response = requests.post( diff --git a/src/intelligence_layer/core/tracer/tracer.py b/src/intelligence_layer/core/tracer/tracer.py index b2e78dec1..1983a7105 100644 --- a/src/intelligence_layer/core/tracer/tracer.py +++ b/src/intelligence_layer/core/tracer/tracer.py @@ -1,5 +1,6 @@ import os import traceback +import warnings from abc import ABC, abstractmethod from collections.abc import Mapping, Sequence from contextlib import AbstractContextManager @@ -208,6 +209,10 @@ def export_for_viewing(self) -> Sequence[ExportedSpan]: ... def submit_to_trace_viewer(self) -> bool: + warnings.warn( + "TraceViewer will be removed soon. Use the Studio Trace functionality instead.", + DeprecationWarning, + ) return submit_to_trace_viewer(self.export_for_viewing()) diff --git a/tests/connectors/studio/test_studio.py b/tests/connectors/studio/test_studio.py index 1fa392c80..7bfff9682 100644 --- a/tests/connectors/studio/test_studio.py +++ b/tests/connectors/studio/test_studio.py @@ -91,7 +91,9 @@ def test_cannot_upload_same_trace_twice( studio_client.submit_trace(test_trace) -def test_cannot_upload_lists_with_multiple_traces(studio_client: StudioClient) -> None: +def test_submit_trace_cannot_upload_lists_with_multiple_traces( + studio_client: StudioClient, +) -> None: tracer = InMemoryTracer() with tracer.span("test"): pass @@ -124,3 +126,28 @@ def mock_return(var: Any) -> Any: with patch("os.getenv", side_effect=mock_return) as _: # noqa: SIM117 with pytest.raises(ValueError, match="auth_token"): StudioClient(str(uuid4)) + + +def test_submit_from_tracer_can_upload_lists_with_multiple_traces( + studio_client: StudioClient, +) -> None: + tracer = InMemoryTracer() + task = TracerTestTask() + task.run("my input", tracer) + task.run("my second input", tracer) + + id_list = set(str(span.context.trace_id) for span in tracer.export_for_viewing()) + + trace_id_list = set(studio_client.submit_from_tracer(tracer)) + + assert trace_id_list == id_list + + +def test_submit_from_tracer_works_with_empty_tracer( + studio_client: StudioClient, +) -> None: + tracer = InMemoryTracer() + + empty_trace_id_list = studio_client.submit_from_tracer(tracer) + + assert len(empty_trace_id_list) == 0 From c3ae1413ba4007cd3e2c8965af491c784f22668e Mon Sep 17 00:00:00 2001 From: Merlin Kallenborn Date: Mon, 5 Aug 2024 17:31:23 +0200 Subject: [PATCH 04/16] docs: Add docstrings for StudioClient functions PHS-616 --- .../how_tos/how_to_run_the_trace_viewer.ipynb | 49 +++++++++++++------ .../connectors/studio/studio.py | 30 ++++++++++++ 2 files changed, 65 insertions(+), 14 deletions(-) diff --git a/src/documentation/how_tos/how_to_run_the_trace_viewer.ipynb b/src/documentation/how_tos/how_to_run_the_trace_viewer.ipynb index 4daf1fed6..48d3f7dd7 100644 --- a/src/documentation/how_tos/how_to_run_the_trace_viewer.ipynb +++ b/src/documentation/how_tos/how_to_run_the_trace_viewer.ipynb @@ -4,25 +4,46 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Running the Trace Viewer\n", + "# How to use PhariaStudio for Debugging in a SaaS Configuration\n", + "
\n", "\n", - "Make sure you have your access to the Jfrog instance at https://alephalpha.jfrog.io. \n", - "Then login to the container registry with docker with your JFrog user name and a JFrog token as the password with the following command:\n", + "Make sure your account has permissions to use the PhariaStudio application.\n", "\n", - "```bash\n", - "docker login alephalpha.jfrog.io\n", - "```\n", - "\n", - "Note: If you do not already have a JFrog token, you can find it on the website under the \"Set me up\" option, either in the resource of interest or under your profile name.\n", - "\n", - "Afterwards, run the container locally to start the trace viewer:\n", + "For an on-prem or local installation, please contact the PhariaStudio team.\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "\n", - "```bash\n", - "docker run -p 3000:3000 alephalpha.jfrog.io/container-images/trace-viewer:latest\n", - "```\n", + "0. Generate a trace of your `Task` of interest.\n", + "1. Initialize a `StudioClient` with a project.\n", + " - Use an existing project or create a new one with the `StudioClient.create_project` function.\n", + "2. Submit your traces with the client\n", + " - submit a single trace via `Tracer.export_for_viewing` and `StudioClient.submit_trace`\n", + " - [Recommended] submit multiple traces via `StudioClient.submit_from_tracer`. \n", + "3. Click the link \n", "\n", - "Finally, visit `http://localhost:3000`, where you can upload a trace to interact with the data." + "### Example" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "vscode": { + "languageId": "plaintext" + } + }, + "outputs": [], + "source": [] } ], "metadata": { diff --git a/src/intelligence_layer/connectors/studio/studio.py b/src/intelligence_layer/connectors/studio/studio.py index 79802bed8..1b2a51309 100644 --- a/src/intelligence_layer/connectors/studio/studio.py +++ b/src/intelligence_layer/connectors/studio/studio.py @@ -112,6 +112,17 @@ def _get_project(self, project: str) -> int | None: return None def create_project(self, project: str, description: Optional[str] = None) -> int: + """Creates a project in PhariaStudio. + + Projects are uniquely identified by the user provided name. + + Args: + project: User provided name of the project. + description: Description explaining the usage of the project. Defaults to None. + + Returns: + The ID of the newly created project. + """ url = urljoin(self.url, "/api/projects") data = StudioProject(name=project, description=description) response = requests.post( @@ -127,11 +138,30 @@ def create_project(self, project: str, description: Optional[str] = None) -> int return int(response.text) def submit_trace(self, data: Sequence[ExportedSpan]) -> str: + """Sends the provided spans to Studio as a singular trace. + + The method fails if the span list is empty, has already been created or if + spans belong to multiple traces. + + Args: + data: Spans to create the trace from. Created by exporting from a `Tracer`. + + Returns: + The ID of the created trace. + """ if len(data) == 0: raise ValueError("Tried to upload an empty trace") return self._upload_trace(ExportedSpanList(data)) def submit_from_tracer(self, tracer: Tracer) -> list[str]: + """Sends all trace data from the Tracer to Studio. + + Args: + tracer: Tracer to extract data from. + + Returns: + List of created trace IDs. + """ traces = defaultdict(list) for span in tracer.export_for_viewing(): traces[span.context.trace_id].append(span) From a71719fa1a889c6710de43e8da37372289399581 Mon Sep 17 00:00:00 2001 From: Merlin Kallenborn Date: Tue, 6 Aug 2024 09:47:11 +0200 Subject: [PATCH 05/16] docs: Add example code snippet to how-to --- .../how_tos/how_to_run_the_trace_viewer.ipynb | 45 +++++++++++++------ 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/src/documentation/how_tos/how_to_run_the_trace_viewer.ipynb b/src/documentation/how_tos/how_to_run_the_trace_viewer.ipynb index 48d3f7dd7..13bfdd647 100644 --- a/src/documentation/how_tos/how_to_run_the_trace_viewer.ipynb +++ b/src/documentation/how_tos/how_to_run_the_trace_viewer.ipynb @@ -22,28 +22,45 @@ "1. Initialize a `StudioClient` with a project.\n", " - Use an existing project or create a new one with the `StudioClient.create_project` function.\n", "2. Submit your traces with the client\n", - " - submit a single trace via `Tracer.export_for_viewing` and `StudioClient.submit_trace`\n", - " - [Recommended] submit multiple traces via `StudioClient.submit_from_tracer`. \n", - "3. Click the link \n", + " 1. Submit a single trace via `Tracer.export_for_viewing` and `StudioClient.submit_trace`\n", + " 2. [Recommended] submit multiple traces via `StudioClient.submit_from_tracer`. \n", "\n", "### Example" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [] - }, { "cell_type": "code", "execution_count": null, - "metadata": { - "vscode": { - "languageId": "plaintext" - } - }, + "metadata": {}, "outputs": [], - "source": [] + "source": [ + "from intelligence_layer.connectors.studio.studio import StudioClient\n", + "from intelligence_layer.core.task import Task\n", + "from intelligence_layer.core.tracer.in_memory_tracer import InMemoryTracer\n", + "from intelligence_layer.core.tracer.tracer import TaskSpan\n", + "\n", + "# Step 0\n", + "class DummyTask(Task[str, str]):\n", + " def do_run(self, input: str, task_span: TaskSpan) -> str:\n", + " return f\"{input} -> output\"\n", + "\n", + "tracer = InMemoryTracer()\n", + "DummyTask().run('My Dummy Run', tracer=tracer)\n", + "\n", + "# Step 1\n", + "studio_client = StudioClient(project='my_project')\n", + "my_project = studio_client.create_project(project='my_project')\n", + "\n", + "# Step 2.1\n", + "trace_to_submit = tracer.export_for_viewing()\n", + "studio_client.submit_trace(trace_to_submit) # only works for single traces\n", + "\n", + "# Step 2.2\n", + "DummyTask().run('My Dummy Run2', tracer=tracer)\n", + "multiple_traces_to_submit = studio_client.submit_from_tracer(tracer)\n", + "\n", + "\n" + ] } ], "metadata": { From ead31109c08cbb1e35904eb2d832b9723de1ea2f Mon Sep 17 00:00:00 2001 From: Merlin Kallenborn Date: Tue, 6 Aug 2024 10:13:42 +0200 Subject: [PATCH 06/16] ci: Remove daily OS support tests --- .github/workflows/daily.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/daily.yml b/.github/workflows/daily.yml index b2d6a1729..463fcbe9a 100644 --- a/.github/workflows/daily.yml +++ b/.github/workflows/daily.yml @@ -3,9 +3,7 @@ name: "os-support-tests" on: workflow_dispatch: # Scheduled workflows will only run on the default branch. - schedule: - - cron: '0 0 * * *' # runs once a day at midnight in the timezone of your GitHub repository - + defaults: run: shell: bash From 1f3be23afc73000bbf2b055b6321e9ce6d4a1ca0 Mon Sep 17 00:00:00 2001 From: Merlin Kallenborn Date: Tue, 6 Aug 2024 10:28:49 +0200 Subject: [PATCH 07/16] ci: Add studio-backend container to sdk-test.yml --- .github/workflows/sdk-tests.yml | 42 +++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/.github/workflows/sdk-tests.yml b/.github/workflows/sdk-tests.yml index 107ac8705..ab620782e 100644 --- a/.github/workflows/sdk-tests.yml +++ b/.github/workflows/sdk-tests.yml @@ -129,6 +129,27 @@ jobs: password: ${{ secrets.GH_PAT }} ports: - "3000:3000" + postgres: + image: postgres:15 + ports: + - "5433:5432" + env: + POSTGRES_DB: "il_sdk" + POSTGRES_USER: "il_sdk" + POSTGRES_PASSWORD: "test" + studio-backend: + image: registry.gitlab.aleph-alpha.de/product/studio/backend:latest + ports: + - "8000:8000" + env: + DATABASE_URL: "postgres:5432" + POSTGRES_DB: "il_sdk" + POSTGRES_USER: "il_sdk" + POSTGRES_PASSWORD: "test" + AUTHORIZATION_SERVICE_URL: "none" + credentials: + username: "unused" + password: ${{ secrets.GL_Studio_Container_Token }} steps: - name: Checkout repository uses: actions/checkout@v4 @@ -186,6 +207,27 @@ jobs: env: ARGILLA_ELASTICSEARCH: "http://argilla-elastic-search:9200" ARGILLA_ENABLE_TELEMETRY: 0 + postgres: + image: postgres:15 + ports: + - "5433:5432" + env: + POSTGRES_DB: "il_sdk" + POSTGRES_USER: "il_sdk" + POSTGRES_PASSWORD: "test" + studio-backend: + image: registry.gitlab.aleph-alpha.de/product/studio/backend:latest + ports: + - "8000:8000" + env: + DATABASE_URL: "postgres:5432" + POSTGRES_DB: "il_sdk" + POSTGRES_USER: "il_sdk" + POSTGRES_PASSWORD: "test" + AUTHORIZATION_SERVICE_URL: "none" + credentials: + username: "unused" + password: ${{ secrets.GL_Studio_Container_Token }} steps: - name: Checkout repository uses: actions/checkout@v4 From 528a703875f791ebf570ef92768e5f5e944addfc Mon Sep 17 00:00:00 2001 From: Merlin Kallenborn Date: Tue, 6 Aug 2024 10:57:14 +0200 Subject: [PATCH 08/16] fix: Linting and minor rewording in trace viewer how-to --- .../how_tos/how_to_run_the_trace_viewer.ipynb | 37 ++++++++++++++----- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/src/documentation/how_tos/how_to_run_the_trace_viewer.ipynb b/src/documentation/how_tos/how_to_run_the_trace_viewer.ipynb index 13bfdd647..3c9a08f19 100644 --- a/src/documentation/how_tos/how_to_run_the_trace_viewer.ipynb +++ b/src/documentation/how_tos/how_to_run_the_trace_viewer.ipynb @@ -34,38 +34,57 @@ "metadata": {}, "outputs": [], "source": [ + "from uuid import uuid4\n", + "\n", "from intelligence_layer.connectors.studio.studio import StudioClient\n", "from intelligence_layer.core.task import Task\n", "from intelligence_layer.core.tracer.in_memory_tracer import InMemoryTracer\n", "from intelligence_layer.core.tracer.tracer import TaskSpan\n", "\n", + "\n", "# Step 0\n", "class DummyTask(Task[str, str]):\n", " def do_run(self, input: str, task_span: TaskSpan) -> str:\n", " return f\"{input} -> output\"\n", "\n", + "\n", "tracer = InMemoryTracer()\n", - "DummyTask().run('My Dummy Run', tracer=tracer)\n", + "DummyTask().run(\"My Dummy Run\", tracer=tracer)\n", "\n", "# Step 1\n", - "studio_client = StudioClient(project='my_project')\n", - "my_project = studio_client.create_project(project='my_project')\n", + "project_name = str(uuid4())\n", + "studio_client = StudioClient(project=project_name)\n", + "my_project = studio_client.create_project(project=project_name)\n", "\n", "# Step 2.1\n", "trace_to_submit = tracer.export_for_viewing()\n", - "studio_client.submit_trace(trace_to_submit) # only works for single traces\n", + "trace_id = studio_client.submit_trace(trace_to_submit) # only works for single traces\n", "\n", "# Step 2.2\n", - "DummyTask().run('My Dummy Run2', tracer=tracer)\n", - "multiple_traces_to_submit = studio_client.submit_from_tracer(tracer)\n", - "\n", - "\n" + "tracer2 = InMemoryTracer()\n", + "DummyTask().run(\"My Dummy Run2\", tracer=tracer2)\n", + "DummyTask().run(\"My Dummy Run3\", tracer=tracer2)\n", + "ids_of_submitted_traces = studio_client.submit_from_tracer(tracer2)" ] } ], "metadata": { + "kernelspec": { + "display_name": "intelligence-layer-aL2cXmJM-py3.11", + "language": "python", + "name": "python3" + }, "language_info": { - "name": "python" + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" } }, "nbformat": 4, From a20c6ce8e3e17e5412228baa5fa5ff04b29bff63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20K=C3=B6hnecke?= Date: Tue, 6 Aug 2024 11:00:04 +0200 Subject: [PATCH 09/16] ci: update auth token name --- .github/workflows/sdk-tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/sdk-tests.yml b/.github/workflows/sdk-tests.yml index ab620782e..8865a1b01 100644 --- a/.github/workflows/sdk-tests.yml +++ b/.github/workflows/sdk-tests.yml @@ -149,7 +149,7 @@ jobs: AUTHORIZATION_SERVICE_URL: "none" credentials: username: "unused" - password: ${{ secrets.GL_Studio_Container_Token }} + password: ${{ secrets.GL_STUDIO_CONTAINER_TOKEN }} steps: - name: Checkout repository uses: actions/checkout@v4 @@ -227,7 +227,7 @@ jobs: AUTHORIZATION_SERVICE_URL: "none" credentials: username: "unused" - password: ${{ secrets.GL_Studio_Container_Token }} + password: ${{ secrets.GL_STUDIO_CONTAINER_TOKEN }} steps: - name: Checkout repository uses: actions/checkout@v4 From ac1b46de2a800e900f4b129fe7b0f07fdc9bd71f Mon Sep 17 00:00:00 2001 From: Merlin Kallenborn Date: Tue, 6 Aug 2024 11:34:37 +0200 Subject: [PATCH 10/16] ci: Specify missing env variable --- .github/workflows/sdk-tests.yml | 6 ++++-- docker-compose.yaml | 5 ++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/sdk-tests.yml b/.github/workflows/sdk-tests.yml index 8865a1b01..f68156e0c 100644 --- a/.github/workflows/sdk-tests.yml +++ b/.github/workflows/sdk-tests.yml @@ -142,7 +142,7 @@ jobs: ports: - "8000:8000" env: - DATABASE_URL: "postgres:5432" + DATABASE_URL: "localhost:5432" POSTGRES_DB: "il_sdk" POSTGRES_USER: "il_sdk" POSTGRES_PASSWORD: "test" @@ -185,6 +185,7 @@ jobs: ARGILLA_API_URL: "http://localhost:6900/" ARGILLA_API_KEY: "argilla.apikey" CLIENT_URL: "https://api.aleph-alpha.com" + STUDIO_URL: "http://localhost:8000" run: | ./scripts/test.sh run-notebooks: @@ -220,7 +221,7 @@ jobs: ports: - "8000:8000" env: - DATABASE_URL: "postgres:5432" + DATABASE_URL: "localhost:5432" POSTGRES_DB: "il_sdk" POSTGRES_USER: "il_sdk" POSTGRES_PASSWORD: "test" @@ -259,5 +260,6 @@ jobs: ARGILLA_API_URL: "http://localhost:6900/" ARGILLA_API_KEY: "argilla.apikey" CLIENT_URL: "https://api.aleph-alpha.com" + STUDIO_URL: "http://localhost:8000" run: | ./scripts/notebook_runner.sh diff --git a/docker-compose.yaml b/docker-compose.yaml index ffc8d92f2..55613dd0b 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -40,8 +40,7 @@ services: - 3000:3000 # export GITLAB_TOKEN=... - # (optional) export GITLAB_TOKEN=$(op item get YOUR_GITLAB_TOKEN_ENTRY --format json --fields password | jq .value) - # echo $GITLAB_TOKEN | docker login ghcr.io -u your_email@for_gitlab --password-stdin + # (optional) export GITLAB_TOKEN=$(op item get YOUR_TOKEN --format json --fields password | jq .value | tr -d '"') # echo $GITLAB_TOKEN | docker login registry.gitlab.aleph-alpha.de -u your_email@for_gitlab --password-stdin # docker compose pull to update containers studio-backend: @@ -59,7 +58,7 @@ services: POSTGRES_PASSWORD: test AUTHORIZATION_SERVICE_URL: "none" # This overrides the env file - + postgres: image: postgres:15 ports: From 6cfbe51d8713ae542b265243500af03fbc60d31e Mon Sep 17 00:00:00 2001 From: Merlin Kallenborn Date: Tue, 6 Aug 2024 11:36:21 +0200 Subject: [PATCH 11/16] fix: Lint --- README.md | 2 +- .../how_tos/how_to_log_and_debug_a_task.ipynb | 9 +-------- ....ipynb => how_to_use_pharia_studio_with_traces.ipynb} | 6 ++---- src/intelligence_layer/connectors/studio/studio.py | 2 +- 4 files changed, 5 insertions(+), 14 deletions(-) rename src/documentation/how_tos/{how_to_run_the_trace_viewer.ipynb => how_to_use_pharia_studio_with_traces.ipynb} (89%) diff --git a/README.md b/README.md index b260363a6..2e21a3432 100644 --- a/README.md +++ b/README.md @@ -149,7 +149,7 @@ The how-tos are quick lookups about how to do things. Compared to the tutorials, | [...define a task](./src/documentation/how_tos/how_to_define_a_task.ipynb) | How to come up with a new task and formulate it | | [...implement a task](./src/documentation/how_tos/how_to_implement_a_task.ipynb) | Implement a formulated task and make it run with the Intelligence Layer | | [...debug and log a task](./src/documentation/how_tos/how_to_log_and_debug_a_task.ipynb) | Tools for logging and debugging in tasks | -| [...run the trace viewer](./src/documentation/how_tos/how_to_run_the_trace_viewer.ipynb) | Downloading and running the trace viewer for debugging traces | +| [...use PhariaStudio with traces](./src/documentation/how_tos/how_to_use_pharia_studio_with_traces.ipynb) | Submitting Traces to PhariaStudio for debugging | | **Analysis Pipeline** | | | [...implement a simple evaluation and aggregation logic](./src/documentation/how_tos/how_to_implement_a_simple_evaluation_and_aggregation_logic.ipynb) | Basic examples of evaluation and aggregation logic | | [...create a dataset](./src/documentation/how_tos/how_to_create_a_dataset.ipynb) | Create a dataset used for running a task | diff --git a/src/documentation/how_tos/how_to_log_and_debug_a_task.ipynb b/src/documentation/how_tos/how_to_log_and_debug_a_task.ipynb index 9b62fccc3..f335fd726 100644 --- a/src/documentation/how_tos/how_to_log_and_debug_a_task.ipynb +++ b/src/documentation/how_tos/how_to_log_and_debug_a_task.ipynb @@ -37,10 +37,7 @@ " - To create custom logging messages in a trace use `task_span.log()`.\n", " - To map a complex execution flow of a task into a single trace, pass the `task_span` of the `do_run` to other execution methods (e.g. `Task.run()` or `model.complete()`). \n", " - If the execution method is not provided by the intelligence layer, the tracing of input and output has to happen manually. See the implementation of `Task.run()` for an example.\n", - " - Use the [trace viewer](./how_to_run_the_trace_viewer.ipynb) to view and inspect a trace\n", - " - Use and display an `InMemoryTracer` in a notebook to automatically send the trace data to the trace viewer.\n", - " - Note: This also works for traces of the `Runner` and the `Evaluator`.\n", - " - To create persistent traces, use the `FileTracer` instead. This creates files which can manually be uploaded in the trace viewer UI." + " - Use the [submit trace functionality of the `StudioClient`](./how_to_use_pharia_studio_with_traces.ipynb) to view and inspect a trace in PhariaStudio" ] }, { @@ -77,10 +74,6 @@ "\n", "tracer = InMemoryTracer()\n", "DummyTask().run(\"\", tracer)\n", - "# ! make sure to run the trace viewer docker container to get the improved display !\n", - "# display an InMemoryTracer in a notebook and send the data to the trace viewer\n", - "display(tracer)\n", - "\n", "pass" ] } diff --git a/src/documentation/how_tos/how_to_run_the_trace_viewer.ipynb b/src/documentation/how_tos/how_to_use_pharia_studio_with_traces.ipynb similarity index 89% rename from src/documentation/how_tos/how_to_run_the_trace_viewer.ipynb rename to src/documentation/how_tos/how_to_use_pharia_studio_with_traces.ipynb index 3c9a08f19..6516cde7b 100644 --- a/src/documentation/how_tos/how_to_run_the_trace_viewer.ipynb +++ b/src/documentation/how_tos/how_to_use_pharia_studio_with_traces.ipynb @@ -36,10 +36,8 @@ "source": [ "from uuid import uuid4\n", "\n", - "from intelligence_layer.connectors.studio.studio import StudioClient\n", - "from intelligence_layer.core.task import Task\n", - "from intelligence_layer.core.tracer.in_memory_tracer import InMemoryTracer\n", - "from intelligence_layer.core.tracer.tracer import TaskSpan\n", + "from intelligence_layer.connectors import StudioClient\n", + "from intelligence_layer.core import InMemoryTracer, Task, TaskSpan\n", "\n", "\n", "# Step 0\n", diff --git a/src/intelligence_layer/connectors/studio/studio.py b/src/intelligence_layer/connectors/studio/studio.py index 1b2a51309..9a256aa35 100644 --- a/src/intelligence_layer/connectors/studio/studio.py +++ b/src/intelligence_layer/connectors/studio/studio.py @@ -8,7 +8,7 @@ from pydantic import BaseModel from requests.exceptions import ConnectionError, MissingSchema -from intelligence_layer.core.tracer.tracer import ExportedSpan, ExportedSpanList, Tracer +from intelligence_layer.core import ExportedSpan, ExportedSpanList, Tracer class StudioProject(BaseModel): From e141306af7de5a2d395a2519a2c522e22f34a4aa Mon Sep 17 00:00:00 2001 From: Merlin Kallenborn Date: Tue, 6 Aug 2024 11:48:20 +0200 Subject: [PATCH 12/16] ci: Add docker logs to ci test step --- .github/workflows/sdk-tests.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/sdk-tests.yml b/.github/workflows/sdk-tests.yml index f68156e0c..eb000c14a 100644 --- a/.github/workflows/sdk-tests.yml +++ b/.github/workflows/sdk-tests.yml @@ -185,8 +185,9 @@ jobs: ARGILLA_API_URL: "http://localhost:6900/" ARGILLA_API_KEY: "argilla.apikey" CLIENT_URL: "https://api.aleph-alpha.com" - STUDIO_URL: "http://localhost:8000" + STUDIO_URL: "http://localhost:8000/" run: | + docker logs "${{ job.services.studio-backend.id }}" ./scripts/test.sh run-notebooks: defaults: From 2e896fc45a49c9b4d6cf37f2b545da553172baf8 Mon Sep 17 00:00:00 2001 From: Merlin Kallenborn Date: Tue, 6 Aug 2024 11:57:39 +0200 Subject: [PATCH 13/16] ci: Use host name for db in studio-backend service --- .github/workflows/sdk-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sdk-tests.yml b/.github/workflows/sdk-tests.yml index eb000c14a..493fd4071 100644 --- a/.github/workflows/sdk-tests.yml +++ b/.github/workflows/sdk-tests.yml @@ -142,7 +142,7 @@ jobs: ports: - "8000:8000" env: - DATABASE_URL: "localhost:5432" + DATABASE_URL: "postgres:5432" POSTGRES_DB: "il_sdk" POSTGRES_USER: "il_sdk" POSTGRES_PASSWORD: "test" From 09ea35d3da2e3c088b4773e31da87305e8810138 Mon Sep 17 00:00:00 2001 From: Merlin Kallenborn Date: Tue, 6 Aug 2024 12:02:18 +0200 Subject: [PATCH 14/16] ci: Use host name for DB in notebook-run step --- .github/workflows/sdk-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sdk-tests.yml b/.github/workflows/sdk-tests.yml index 493fd4071..3b101775b 100644 --- a/.github/workflows/sdk-tests.yml +++ b/.github/workflows/sdk-tests.yml @@ -222,7 +222,7 @@ jobs: ports: - "8000:8000" env: - DATABASE_URL: "localhost:5432" + DATABASE_URL: "postgres:5432" POSTGRES_DB: "il_sdk" POSTGRES_USER: "il_sdk" POSTGRES_PASSWORD: "test" From 39524bfae575f04a12485b5d8c2cd1968cea3b31 Mon Sep 17 00:00:00 2001 From: Merlin Kallenborn Date: Tue, 6 Aug 2024 12:26:58 +0200 Subject: [PATCH 15/16] fix: Circular imports --- src/intelligence_layer/connectors/studio/studio.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/intelligence_layer/connectors/studio/studio.py b/src/intelligence_layer/connectors/studio/studio.py index 9a256aa35..1b2a51309 100644 --- a/src/intelligence_layer/connectors/studio/studio.py +++ b/src/intelligence_layer/connectors/studio/studio.py @@ -8,7 +8,7 @@ from pydantic import BaseModel from requests.exceptions import ConnectionError, MissingSchema -from intelligence_layer.core import ExportedSpan, ExportedSpanList, Tracer +from intelligence_layer.core.tracer.tracer import ExportedSpan, ExportedSpanList, Tracer class StudioProject(BaseModel): From d283946e0a793d779a669c6284907755e7ca1ca9 Mon Sep 17 00:00:00 2001 From: Merlin Kallenborn Date: Tue, 6 Aug 2024 12:50:55 +0200 Subject: [PATCH 16/16] docs: Add changelog entry fix: Lint --- .github/workflows/sdk-tests.yml | 1 - CHANGELOG.md | 4 ++-- README.md | 2 +- docker-compose.yaml | 5 ++--- .../how_tos/how_to_log_and_debug_a_task.ipynb | 10 ++++++++++ .../how_to_use_pharia_studio_with_traces.ipynb | 18 ++++++++++++------ .../connectors/studio/studio.py | 6 +++++- 7 files changed, 32 insertions(+), 14 deletions(-) diff --git a/.github/workflows/sdk-tests.yml b/.github/workflows/sdk-tests.yml index 3b101775b..012bfa3f4 100644 --- a/.github/workflows/sdk-tests.yml +++ b/.github/workflows/sdk-tests.yml @@ -187,7 +187,6 @@ jobs: CLIENT_URL: "https://api.aleph-alpha.com" STUDIO_URL: "http://localhost:8000/" run: | - docker logs "${{ job.services.studio-backend.id }}" ./scripts/test.sh run-notebooks: defaults: diff --git a/CHANGELOG.md b/CHANGELOG.md index 77de72112..c6e5d5ebc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,13 +6,13 @@ ... ### Features -... +- Add `StudioClient` as connector to PhariaStudio for submitting traces. ### Fixes ... ### Deprecations -... + - Deprecate old Trace Viewer as the new `StudioClient` replaces it. This affects `Tracer.submit_to_trace_viewer`. ## 5.0.3 diff --git a/README.md b/README.md index 2e21a3432..a4268d738 100644 --- a/README.md +++ b/README.md @@ -149,7 +149,7 @@ The how-tos are quick lookups about how to do things. Compared to the tutorials, | [...define a task](./src/documentation/how_tos/how_to_define_a_task.ipynb) | How to come up with a new task and formulate it | | [...implement a task](./src/documentation/how_tos/how_to_implement_a_task.ipynb) | Implement a formulated task and make it run with the Intelligence Layer | | [...debug and log a task](./src/documentation/how_tos/how_to_log_and_debug_a_task.ipynb) | Tools for logging and debugging in tasks | -| [...use PhariaStudio with traces](./src/documentation/how_tos/how_to_use_pharia_studio_with_traces.ipynb) | Submitting Traces to PhariaStudio for debugging | +| [...use PhariaStudio with traces](./src/documentation/how_tos/how_to_use_pharia_studio_with_traces.ipynb) | Submitting Traces to PhariaStudio for debugging | | **Analysis Pipeline** | | | [...implement a simple evaluation and aggregation logic](./src/documentation/how_tos/how_to_implement_a_simple_evaluation_and_aggregation_logic.ipynb) | Basic examples of evaluation and aggregation logic | | [...create a dataset](./src/documentation/how_tos/how_to_create_a_dataset.ipynb) | Create a dataset used for running a task | diff --git a/docker-compose.yaml b/docker-compose.yaml index 55613dd0b..190f65855 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -52,13 +52,12 @@ services: condition: service_started restart: true environment: - DATABASE_URL: postgres:5432 # This overrides the env file + DATABASE_URL: postgres:5432 POSTGRES_DB: il_sdk POSTGRES_USER: il_sdk POSTGRES_PASSWORD: test - AUTHORIZATION_SERVICE_URL: "none" # This overrides the env file - + AUTHORIZATION_SERVICE_URL: "none" postgres: image: postgres:15 ports: diff --git a/src/documentation/how_tos/how_to_log_and_debug_a_task.ipynb b/src/documentation/how_tos/how_to_log_and_debug_a_task.ipynb index f335fd726..d30aa7c7c 100644 --- a/src/documentation/how_tos/how_to_log_and_debug_a_task.ipynb +++ b/src/documentation/how_tos/how_to_log_and_debug_a_task.ipynb @@ -7,10 +7,12 @@ "outputs": [], "source": [ "import random\n", + "from uuid import uuid4\n", "\n", "from aleph_alpha_client import Prompt\n", "from dotenv import load_dotenv\n", "\n", + "from intelligence_layer.connectors import StudioClient\n", "from intelligence_layer.core import (\n", " CompleteInput,\n", " InMemoryTracer,\n", @@ -74,6 +76,14 @@ "\n", "tracer = InMemoryTracer()\n", "DummyTask().run(\"\", tracer)\n", + "\n", + "project_name = str(uuid4())\n", + "studio_client = StudioClient(project=project_name)\n", + "my_project = studio_client.create_project(project=project_name)\n", + "\n", + "submitted_trace_id = studio_client.submit_from_tracer(tracer)\n", + "\n", + "\n", "pass" ] } diff --git a/src/documentation/how_tos/how_to_use_pharia_studio_with_traces.ipynb b/src/documentation/how_tos/how_to_use_pharia_studio_with_traces.ipynb index 6516cde7b..5161f0295 100644 --- a/src/documentation/how_tos/how_to_use_pharia_studio_with_traces.ipynb +++ b/src/documentation/how_tos/how_to_use_pharia_studio_with_traces.ipynb @@ -1,5 +1,17 @@ { "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from uuid import uuid4\n", + "\n", + "from intelligence_layer.connectors import StudioClient\n", + "from intelligence_layer.core import InMemoryTracer, Task, TaskSpan" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -34,12 +46,6 @@ "metadata": {}, "outputs": [], "source": [ - "from uuid import uuid4\n", - "\n", - "from intelligence_layer.connectors import StudioClient\n", - "from intelligence_layer.core import InMemoryTracer, Task, TaskSpan\n", - "\n", - "\n", "# Step 0\n", "class DummyTask(Task[str, str]):\n", " def do_run(self, input: str, task_span: TaskSpan) -> str:\n", diff --git a/src/intelligence_layer/connectors/studio/studio.py b/src/intelligence_layer/connectors/studio/studio.py index 1b2a51309..a6888649a 100644 --- a/src/intelligence_layer/connectors/studio/studio.py +++ b/src/intelligence_layer/connectors/studio/studio.py @@ -8,7 +8,11 @@ from pydantic import BaseModel from requests.exceptions import ConnectionError, MissingSchema -from intelligence_layer.core.tracer.tracer import ExportedSpan, ExportedSpanList, Tracer +from intelligence_layer.core.tracer.tracer import ( # Import to be fixed with PHS-731 + ExportedSpan, + ExportedSpanList, + Tracer, +) class StudioProject(BaseModel):