Signed-off-by: Yuichiro Utsumi <utsumi.yuichiro@fujitsu.com> Signed-off-by: -LAN- <laipz8200@outlook.com> Signed-off-by: yihong0618 <zouzou0208@gmail.com> Signed-off-by: kenwoodjw <blackxin55+@gmail.com> Signed-off-by: ChengZi <chen.zhang@zilliz.com> Signed-off-by: cl <cailue@apache.org> Co-authored-by: Yu Chun Chang <changyuchun159630@gmail.com> Co-authored-by: Kyle Chang <kylechang@91app.com> Co-authored-by: Lick-liu <51771897+Lick-liu@users.noreply.github.com> Co-authored-by: crazywoola <427733928@qq.com> Co-authored-by: Yuichiro Utsumi <81412151+utsumi-fj@users.noreply.github.com> Co-authored-by: NFish <douxc512@gmail.com> Co-authored-by: Yeuoly <45712896+Yeuoly@users.noreply.github.com> Co-authored-by: Wu Tianwei <30284043+WTW0313@users.noreply.github.com> Co-authored-by: DDDDD12138 <43703884+DDDDD12138@users.noreply.github.com> Co-authored-by: Jyong <76649700+JohnJyong@users.noreply.github.com> Co-authored-by: -LAN- <laipz8200@outlook.com> Co-authored-by: Novice <857526207@qq.com> Co-authored-by: yihong <zouzou0208@gmail.com> Co-authored-by: Kalo Chin <91766386+fdb02983rhy@users.noreply.github.com> Co-authored-by: zxhlyh <jasonapring2015@outlook.com> Co-authored-by: jiangbo721 <365065261@qq.com> Co-authored-by: 刘江波 <jiangbo721@163.com> Co-authored-by: Lam <scau_ljw@126.com> Co-authored-by: crazywoola <100913391+crazywoola@users.noreply.github.com> Co-authored-by: Mars <524574386@qq.com> Co-authored-by: mars <linjx2@by-health.com> Co-authored-by: Joe <79627742+ZhouhaoJiang@users.noreply.github.com> Co-authored-by: Rafael Carvalho <r.carvalho@me.com> Co-authored-by: Joel <iamjoel007@gmail.com> Co-authored-by: 非法操作 <hjlarry@163.com> Co-authored-by: kenwoodjw <blackxin55+@gmail.com> Co-authored-by: codingjaguar <codingjaguar@gmail.com> Co-authored-by: ChengZi <chen.zhang@zilliz.com> Co-authored-by: Fei He <droxer.he@gmail.com> Co-authored-by: Arcaner <52057416+lrhan321@users.noreply.github.com> Co-authored-by: Xiyuan Chen <52963600+GareArc@users.noreply.github.com> Co-authored-by: KVOJJJin <jzongcode@gmail.com> Co-authored-by: XiaoBa <94062266+XiaoBa-Yu@users.noreply.github.com> Co-authored-by: Xiaoba Yu <xb1823725853@gmail.com> Co-authored-by: zhangyuhang <2827528315@qq.com> Co-authored-by: yuhang2.zhang <yuhang2.zhang@ly.com> Co-authored-by: 诗浓 <nyaashino@gmail.com> Co-authored-by: RookieAgent <42060616+Sakura4036@users.noreply.github.com> Co-authored-by: sho-takano-dev <shota.takano.dev@gmail.com> Co-authored-by: 過世秋風 <1040926235@qq.com> Co-authored-by: Yi Feng <66539215+bigyifeng@users.noreply.github.com> Co-authored-by: QuantumGhost <obelisk.reg+git@gmail.com> Co-authored-by: Yongtao Huang <99629139+hyongtao-db@users.noreply.github.com> Co-authored-by: ShadowJobs <794878115@qq.com> Co-authored-by: LinYing <linying@momenta.ai> Co-authored-by: Benjamin <benjaminx@gmail.com> Co-authored-by: LiuBodong <liubodong2010@126.com> Co-authored-by: huangzhuo1949 <167434202+huangzhuo1949@users.noreply.github.com> Co-authored-by: huangzhuo <huangzhuo1@xiaomi.com> Co-authored-by: csurong <csurong1@gmail.com> Co-authored-by: 傻笑zz <43721571+shaxiaozz@users.noreply.github.com> Co-authored-by: L8ng <straydragonl@foxmail.com> Co-authored-by: Bowen Liang <liangbowen@gf.com.cn> Co-authored-by: Novice Lee <novicelee@NoviPro.local> Co-authored-by: GuanMu <ballmanjq@gmail.com> Co-authored-by: LittleFish-15 <58618983+LittleFish-15@users.noreply.github.com> Co-authored-by: 诗浓 <844670992@qq.com> Co-authored-by: luckylhb90 <luckylhb90@gmail.com> Co-authored-by: hobo.l <hobo.l@binance.com> Co-authored-by: Gen Sato <52241300+halogen22@users.noreply.github.com> Co-authored-by: twwu <twwu@dify.ai> Co-authored-by: StoneFancyX <53338920+StoneFancyX@users.noreply.github.com> Co-authored-by: StoneFancyX <kindbin@qq.com> Co-authored-by: Naoki KOBAYASHI <naotama@gmail.com> Co-authored-by: kurokobo <kuro664@gmail.com> Co-authored-by: cyflhn <cyflhn@163.com> Co-authored-by: Yingchun Lai <laiyingchun@apache.org> Co-authored-by: jimmyfen <757343258@qq.com> Co-authored-by: Xuetao Song <xuetaomagicsong@gmail.com> Co-authored-by: Panpan <wurui.dev@gmail.com> Co-authored-by: wyy-holding <59436937+wyy-holding@users.noreply.github.com> Co-authored-by: リイノ Lin <sorphwer@gmail.com> Co-authored-by: Ning <accelerator314@gmail.com> Co-authored-by: Linh Nguyen <55907715+batman0911@users.noreply.github.com> Co-authored-by: Junjie.M <118170653@qq.com> Co-authored-by: Ron <svcvit@gmail.com> Co-authored-by: Novice <novice12185727@gmail.com> Co-authored-by: NanoNova <kid1412621@gmail.com> Co-authored-by: JaydenZhou <380774082@qq.com> Co-authored-by: dotdotdot <823150982@qq.com> Co-authored-by: Good Wood <slm_1990@126.com> Co-authored-by: Ryosei Karaki <38310693+karamaru-alpha@users.noreply.github.com> Co-authored-by: chenhuan0728 <54611342+chenhuan0728@users.noreply.github.com> Co-authored-by: chenhuan <huan.chen0728@foxmail> Co-authored-by: lenbo <islenbo@qq.com> Co-authored-by: Jiang <65766008+AlwaysBluer@users.noreply.github.com> Co-authored-by: jiangzhijie <jiangzhijie.jzj@alibaba-inc.com> Co-authored-by: Yongtao Huang <yongtaoh2022@gmail.com> Co-authored-by: zhangkun-21 <sephiroth0932@gmail.com> Co-authored-by: hsiong <37357447+hsiong@users.noreply.github.com> Co-authored-by: 李远军 <4842@9ji.com> Co-authored-by: yourchanges <yourchanges@gmail.com> Co-authored-by: David <guyuezhuying@126.com> Co-authored-by: liuzhenghua <1090179900@qq.com> Co-authored-by: taokuizu <taokuizu@qq.com> Co-authored-by: Hanqing Zhao <sherry9277@gmail.com> Co-authored-by: JimintheBox <gjwlals111@gmail.com> Co-authored-by: wlleiiwang <1025164922@qq.com> Co-authored-by: wlleiiwang <wlleiiwang@tencent.com> Co-authored-by: Alex <32982705+AlexYuan997@users.noreply.github.com> Co-authored-by: yuanlong <yuanlong@boco.com.cn> Co-authored-by: wanttobeamaster <45583625+wanttobeamaster@users.noreply.github.com> Co-authored-by: xiaozhiqing.xzq <xiaozhiqing.xzq@alibaba-inc.com> Co-authored-by: Chenhe Gu <guchenhe@gmail.com> Co-authored-by: tyounami <vkbo@qq.com> Co-authored-by: bo.zhao <bo.zhao@iglooinsure.com> Co-authored-by: ClSlaid <cailue@apache.org> Co-authored-by: adru <106513264+adpanru@users.noreply.github.com> Co-authored-by: horochx <32632779+horochx@users.noreply.github.com>tags/1.3.1
| @@ -7,6 +7,7 @@ class TracingProviderEnum(Enum): | |||
| LANGFUSE = "langfuse" | |||
| LANGSMITH = "langsmith" | |||
| OPIK = "opik" | |||
| WEAVE = "weave" | |||
| class BaseTracingConfig(BaseModel): | |||
| @@ -88,5 +89,26 @@ class OpikConfig(BaseTracingConfig): | |||
| return v | |||
| class WeaveConfig(BaseTracingConfig): | |||
| """ | |||
| Model class for Weave tracing config. | |||
| """ | |||
| api_key: str | |||
| entity: str | None = None | |||
| project: str | |||
| endpoint: str = "https://trace.wandb.ai" | |||
| @field_validator("endpoint") | |||
| @classmethod | |||
| def set_value(cls, v, info: ValidationInfo): | |||
| if v is None or v == "": | |||
| v = "https://trace.wandb.ai" | |||
| if not v.startswith("https://"): | |||
| raise ValueError("endpoint must start with https://") | |||
| return v | |||
| OPS_FILE_PATH = "ops_trace/" | |||
| OPS_TRACE_FAILED_KEY = "FAILED_OPS_TRACE" | |||
| @@ -20,6 +20,7 @@ from core.ops.entities.config_entity import ( | |||
| LangSmithConfig, | |||
| OpikConfig, | |||
| TracingProviderEnum, | |||
| WeaveConfig, | |||
| ) | |||
| from core.ops.entities.trace_entity import ( | |||
| DatasetRetrievalTraceInfo, | |||
| @@ -34,7 +35,9 @@ from core.ops.entities.trace_entity import ( | |||
| ) | |||
| from core.ops.langfuse_trace.langfuse_trace import LangFuseDataTrace | |||
| from core.ops.langsmith_trace.langsmith_trace import LangSmithDataTrace | |||
| from core.ops.opik_trace.opik_trace import OpikDataTrace | |||
| from core.ops.utils import get_message_data | |||
| from core.ops.weave_trace.weave_trace import WeaveDataTrace | |||
| from extensions.ext_database import db | |||
| from extensions.ext_storage import storage | |||
| from models.model import App, AppModelConfig, Conversation, Message, MessageFile, TraceAppConfig | |||
| @@ -43,8 +46,6 @@ from tasks.ops_trace_task import process_trace_tasks | |||
| def build_opik_trace_instance(config: OpikConfig): | |||
| from core.ops.opik_trace.opik_trace import OpikDataTrace | |||
| return OpikDataTrace(config) | |||
| @@ -67,6 +68,12 @@ provider_config_map: dict[str, dict[str, Any]] = { | |||
| "other_keys": ["project", "url", "workspace"], | |||
| "trace_instance": lambda config: build_opik_trace_instance(config), | |||
| }, | |||
| TracingProviderEnum.WEAVE.value: { | |||
| "config_class": WeaveConfig, | |||
| "secret_keys": ["api_key"], | |||
| "other_keys": ["project", "entity", "endpoint"], | |||
| "trace_instance": WeaveDataTrace, | |||
| }, | |||
| } | |||
| @@ -0,0 +1,97 @@ | |||
| from typing import Any, Optional, Union | |||
| from pydantic import BaseModel, Field, field_validator | |||
| from pydantic_core.core_schema import ValidationInfo | |||
| from core.ops.utils import replace_text_with_content | |||
| class WeaveTokenUsage(BaseModel): | |||
| input_tokens: Optional[int] = None | |||
| output_tokens: Optional[int] = None | |||
| total_tokens: Optional[int] = None | |||
| class WeaveMultiModel(BaseModel): | |||
| file_list: Optional[list[str]] = Field(None, description="List of files") | |||
| class WeaveTraceModel(WeaveTokenUsage, WeaveMultiModel): | |||
| id: str = Field(..., description="ID of the trace") | |||
| op: str = Field(..., description="Name of the operation") | |||
| inputs: Optional[Union[str, dict[str, Any], list, None]] = Field(None, description="Inputs of the trace") | |||
| outputs: Optional[Union[str, dict[str, Any], list, None]] = Field(None, description="Outputs of the trace") | |||
| attributes: Optional[Union[str, dict[str, Any], list, None]] = Field( | |||
| None, description="Metadata and attributes associated with trace" | |||
| ) | |||
| exception: Optional[str] = Field(None, description="Exception message of the trace") | |||
| @field_validator("inputs", "outputs") | |||
| @classmethod | |||
| def ensure_dict(cls, v, info: ValidationInfo): | |||
| field_name = info.field_name | |||
| values = info.data | |||
| if v == {} or v is None: | |||
| return v | |||
| usage_metadata = { | |||
| "input_tokens": values.get("input_tokens", 0), | |||
| "output_tokens": values.get("output_tokens", 0), | |||
| "total_tokens": values.get("total_tokens", 0), | |||
| } | |||
| file_list = values.get("file_list", []) | |||
| if isinstance(v, str): | |||
| if field_name == "inputs": | |||
| return { | |||
| "messages": { | |||
| "role": "user", | |||
| "content": v, | |||
| "usage_metadata": usage_metadata, | |||
| "file_list": file_list, | |||
| }, | |||
| } | |||
| elif field_name == "outputs": | |||
| return { | |||
| "choices": { | |||
| "role": "ai", | |||
| "content": v, | |||
| "usage_metadata": usage_metadata, | |||
| "file_list": file_list, | |||
| }, | |||
| } | |||
| elif isinstance(v, list): | |||
| data = {} | |||
| if len(v) > 0 and isinstance(v[0], dict): | |||
| # rename text to content | |||
| v = replace_text_with_content(data=v) | |||
| if field_name == "inputs": | |||
| data = { | |||
| "messages": [ | |||
| dict(msg, **{"usage_metadata": usage_metadata, "file_list": file_list}) for msg in v | |||
| ] | |||
| if isinstance(v, list) | |||
| else v, | |||
| } | |||
| elif field_name == "outputs": | |||
| data = { | |||
| "choices": { | |||
| "role": "ai", | |||
| "content": v, | |||
| "usage_metadata": usage_metadata, | |||
| "file_list": file_list, | |||
| }, | |||
| } | |||
| return data | |||
| else: | |||
| return { | |||
| "choices": { | |||
| "role": "ai" if field_name == "outputs" else "user", | |||
| "content": str(v), | |||
| "usage_metadata": usage_metadata, | |||
| "file_list": file_list, | |||
| }, | |||
| } | |||
| if isinstance(v, dict): | |||
| v["usage_metadata"] = usage_metadata | |||
| v["file_list"] = file_list | |||
| return v | |||
| return v | |||
| @@ -0,0 +1,420 @@ | |||
| import json | |||
| import logging | |||
| import os | |||
| import uuid | |||
| from datetime import datetime, timedelta | |||
| from typing import Any, Optional, cast | |||
| import wandb | |||
| import weave | |||
| from core.ops.base_trace_instance import BaseTraceInstance | |||
| from core.ops.entities.config_entity import WeaveConfig | |||
| from core.ops.entities.trace_entity import ( | |||
| BaseTraceInfo, | |||
| DatasetRetrievalTraceInfo, | |||
| GenerateNameTraceInfo, | |||
| MessageTraceInfo, | |||
| ModerationTraceInfo, | |||
| SuggestedQuestionTraceInfo, | |||
| ToolTraceInfo, | |||
| TraceTaskName, | |||
| WorkflowTraceInfo, | |||
| ) | |||
| from core.ops.weave_trace.entities.weave_trace_entity import WeaveTraceModel | |||
| from extensions.ext_database import db | |||
| from models.model import EndUser, MessageFile | |||
| from models.workflow import WorkflowNodeExecution | |||
| logger = logging.getLogger(__name__) | |||
| class WeaveDataTrace(BaseTraceInstance): | |||
| def __init__( | |||
| self, | |||
| weave_config: WeaveConfig, | |||
| ): | |||
| super().__init__(weave_config) | |||
| self.weave_api_key = weave_config.api_key | |||
| self.project_name = weave_config.project | |||
| self.entity = weave_config.entity | |||
| # Login with API key first | |||
| login_status = wandb.login(key=self.weave_api_key, verify=True, relogin=True) | |||
| if not login_status: | |||
| logger.error("Failed to login to Weights & Biases with the provided API key") | |||
| raise ValueError("Weave login failed") | |||
| # Then initialize weave client | |||
| self.weave_client = weave.init( | |||
| project_name=(f"{self.entity}/{self.project_name}" if self.entity else self.project_name) | |||
| ) | |||
| self.file_base_url = os.getenv("FILES_URL", "http://127.0.0.1:5001") | |||
| self.calls: dict[str, Any] = {} | |||
| def get_project_url( | |||
| self, | |||
| ): | |||
| try: | |||
| project_url = f"https://wandb.ai/{self.weave_client._project_id()}" | |||
| return project_url | |||
| except Exception as e: | |||
| logger.debug(f"Weave get run url failed: {str(e)}") | |||
| raise ValueError(f"Weave get run url failed: {str(e)}") | |||
| def trace(self, trace_info: BaseTraceInfo): | |||
| logger.debug(f"Trace info: {trace_info}") | |||
| if isinstance(trace_info, WorkflowTraceInfo): | |||
| self.workflow_trace(trace_info) | |||
| if isinstance(trace_info, MessageTraceInfo): | |||
| self.message_trace(trace_info) | |||
| if isinstance(trace_info, ModerationTraceInfo): | |||
| self.moderation_trace(trace_info) | |||
| if isinstance(trace_info, SuggestedQuestionTraceInfo): | |||
| self.suggested_question_trace(trace_info) | |||
| if isinstance(trace_info, DatasetRetrievalTraceInfo): | |||
| self.dataset_retrieval_trace(trace_info) | |||
| if isinstance(trace_info, ToolTraceInfo): | |||
| self.tool_trace(trace_info) | |||
| if isinstance(trace_info, GenerateNameTraceInfo): | |||
| self.generate_name_trace(trace_info) | |||
| def workflow_trace(self, trace_info: WorkflowTraceInfo): | |||
| trace_id = trace_info.message_id or trace_info.workflow_run_id | |||
| if trace_info.start_time is None: | |||
| trace_info.start_time = datetime.now() | |||
| if trace_info.message_id: | |||
| message_attributes = trace_info.metadata | |||
| message_attributes["workflow_app_log_id"] = trace_info.workflow_app_log_id | |||
| message_attributes["message_id"] = trace_info.message_id | |||
| message_attributes["workflow_run_id"] = trace_info.workflow_run_id | |||
| message_attributes["trace_id"] = trace_id | |||
| message_attributes["start_time"] = trace_info.start_time | |||
| message_attributes["end_time"] = trace_info.end_time | |||
| message_attributes["tags"] = ["message", "workflow"] | |||
| message_run = WeaveTraceModel( | |||
| id=trace_info.message_id, | |||
| op=str(TraceTaskName.MESSAGE_TRACE.value), | |||
| inputs=dict(trace_info.workflow_run_inputs), | |||
| outputs=dict(trace_info.workflow_run_outputs), | |||
| total_tokens=trace_info.total_tokens, | |||
| attributes=message_attributes, | |||
| exception=trace_info.error, | |||
| file_list=[], | |||
| ) | |||
| self.start_call(message_run, parent_run_id=trace_info.workflow_run_id) | |||
| self.finish_call(message_run) | |||
| workflow_attributes = trace_info.metadata | |||
| workflow_attributes["workflow_run_id"] = trace_info.workflow_run_id | |||
| workflow_attributes["trace_id"] = trace_id | |||
| workflow_attributes["start_time"] = trace_info.start_time | |||
| workflow_attributes["end_time"] = trace_info.end_time | |||
| workflow_attributes["tags"] = ["workflow"] | |||
| workflow_run = WeaveTraceModel( | |||
| file_list=trace_info.file_list, | |||
| total_tokens=trace_info.total_tokens, | |||
| id=trace_info.workflow_run_id, | |||
| op=str(TraceTaskName.WORKFLOW_TRACE.value), | |||
| inputs=dict(trace_info.workflow_run_inputs), | |||
| outputs=dict(trace_info.workflow_run_outputs), | |||
| attributes=workflow_attributes, | |||
| exception=trace_info.error, | |||
| ) | |||
| self.start_call(workflow_run, parent_run_id=trace_info.message_id) | |||
| # through workflow_run_id get all_nodes_execution | |||
| workflow_nodes_execution_id_records = ( | |||
| db.session.query(WorkflowNodeExecution.id) | |||
| .filter(WorkflowNodeExecution.workflow_run_id == trace_info.workflow_run_id) | |||
| .all() | |||
| ) | |||
| for node_execution_id_record in workflow_nodes_execution_id_records: | |||
| node_execution = ( | |||
| db.session.query( | |||
| WorkflowNodeExecution.id, | |||
| WorkflowNodeExecution.tenant_id, | |||
| WorkflowNodeExecution.app_id, | |||
| WorkflowNodeExecution.title, | |||
| WorkflowNodeExecution.node_type, | |||
| WorkflowNodeExecution.status, | |||
| WorkflowNodeExecution.inputs, | |||
| WorkflowNodeExecution.outputs, | |||
| WorkflowNodeExecution.created_at, | |||
| WorkflowNodeExecution.elapsed_time, | |||
| WorkflowNodeExecution.process_data, | |||
| WorkflowNodeExecution.execution_metadata, | |||
| ) | |||
| .filter(WorkflowNodeExecution.id == node_execution_id_record.id) | |||
| .first() | |||
| ) | |||
| if not node_execution: | |||
| continue | |||
| node_execution_id = node_execution.id | |||
| tenant_id = node_execution.tenant_id | |||
| app_id = node_execution.app_id | |||
| node_name = node_execution.title | |||
| node_type = node_execution.node_type | |||
| status = node_execution.status | |||
| if node_type == "llm": | |||
| inputs = ( | |||
| json.loads(node_execution.process_data).get("prompts", {}) if node_execution.process_data else {} | |||
| ) | |||
| else: | |||
| inputs = json.loads(node_execution.inputs) if node_execution.inputs else {} | |||
| outputs = json.loads(node_execution.outputs) if node_execution.outputs else {} | |||
| created_at = node_execution.created_at or datetime.now() | |||
| elapsed_time = node_execution.elapsed_time | |||
| finished_at = created_at + timedelta(seconds=elapsed_time) | |||
| execution_metadata = ( | |||
| json.loads(node_execution.execution_metadata) if node_execution.execution_metadata else {} | |||
| ) | |||
| node_total_tokens = execution_metadata.get("total_tokens", 0) | |||
| attributes = execution_metadata.copy() | |||
| attributes.update( | |||
| { | |||
| "workflow_run_id": trace_info.workflow_run_id, | |||
| "node_execution_id": node_execution_id, | |||
| "tenant_id": tenant_id, | |||
| "app_id": app_id, | |||
| "app_name": node_name, | |||
| "node_type": node_type, | |||
| "status": status, | |||
| } | |||
| ) | |||
| process_data = json.loads(node_execution.process_data) if node_execution.process_data else {} | |||
| if process_data and process_data.get("model_mode") == "chat": | |||
| attributes.update( | |||
| { | |||
| "ls_provider": process_data.get("model_provider", ""), | |||
| "ls_model_name": process_data.get("model_name", ""), | |||
| } | |||
| ) | |||
| attributes["tags"] = ["node_execution"] | |||
| attributes["start_time"] = created_at | |||
| attributes["end_time"] = finished_at | |||
| attributes["elapsed_time"] = elapsed_time | |||
| attributes["workflow_run_id"] = trace_info.workflow_run_id | |||
| attributes["trace_id"] = trace_id | |||
| node_run = WeaveTraceModel( | |||
| total_tokens=node_total_tokens, | |||
| op=node_type, | |||
| inputs=inputs, | |||
| outputs=outputs, | |||
| file_list=trace_info.file_list, | |||
| attributes=attributes, | |||
| id=node_execution_id, | |||
| exception=None, | |||
| ) | |||
| self.start_call(node_run, parent_run_id=trace_info.workflow_run_id) | |||
| self.finish_call(node_run) | |||
| self.finish_call(workflow_run) | |||
| def message_trace(self, trace_info: MessageTraceInfo): | |||
| # get message file data | |||
| file_list = cast(list[str], trace_info.file_list) or [] | |||
| message_file_data: Optional[MessageFile] = trace_info.message_file_data | |||
| file_url = f"{self.file_base_url}/{message_file_data.url}" if message_file_data else "" | |||
| file_list.append(file_url) | |||
| attributes = trace_info.metadata | |||
| message_data = trace_info.message_data | |||
| if message_data is None: | |||
| return | |||
| message_id = message_data.id | |||
| user_id = message_data.from_account_id | |||
| attributes["user_id"] = user_id | |||
| if message_data.from_end_user_id: | |||
| end_user_data: Optional[EndUser] = ( | |||
| db.session.query(EndUser).filter(EndUser.id == message_data.from_end_user_id).first() | |||
| ) | |||
| if end_user_data is not None: | |||
| end_user_id = end_user_data.session_id | |||
| attributes["end_user_id"] = end_user_id | |||
| attributes["message_id"] = message_id | |||
| attributes["start_time"] = trace_info.start_time | |||
| attributes["end_time"] = trace_info.end_time | |||
| attributes["tags"] = ["message", str(trace_info.conversation_mode)] | |||
| message_run = WeaveTraceModel( | |||
| id=message_id, | |||
| op=str(TraceTaskName.MESSAGE_TRACE.value), | |||
| input_tokens=trace_info.message_tokens, | |||
| output_tokens=trace_info.answer_tokens, | |||
| total_tokens=trace_info.total_tokens, | |||
| inputs=trace_info.inputs, | |||
| outputs=trace_info.outputs, | |||
| exception=trace_info.error, | |||
| file_list=file_list, | |||
| attributes=attributes, | |||
| ) | |||
| self.start_call(message_run) | |||
| # create llm run parented to message run | |||
| llm_run = WeaveTraceModel( | |||
| id=str(uuid.uuid4()), | |||
| input_tokens=trace_info.message_tokens, | |||
| output_tokens=trace_info.answer_tokens, | |||
| total_tokens=trace_info.total_tokens, | |||
| op="llm", | |||
| inputs=trace_info.inputs, | |||
| outputs=trace_info.outputs, | |||
| attributes=attributes, | |||
| file_list=[], | |||
| exception=None, | |||
| ) | |||
| self.start_call( | |||
| llm_run, | |||
| parent_run_id=message_id, | |||
| ) | |||
| self.finish_call(llm_run) | |||
| self.finish_call(message_run) | |||
| def moderation_trace(self, trace_info: ModerationTraceInfo): | |||
| if trace_info.message_data is None: | |||
| return | |||
| attributes = trace_info.metadata | |||
| attributes["tags"] = ["moderation"] | |||
| attributes["message_id"] = trace_info.message_id | |||
| attributes["start_time"] = trace_info.start_time or trace_info.message_data.created_at | |||
| attributes["end_time"] = trace_info.end_time or trace_info.message_data.updated_at | |||
| moderation_run = WeaveTraceModel( | |||
| id=str(uuid.uuid4()), | |||
| op=str(TraceTaskName.MODERATION_TRACE.value), | |||
| inputs=trace_info.inputs, | |||
| outputs={ | |||
| "action": trace_info.action, | |||
| "flagged": trace_info.flagged, | |||
| "preset_response": trace_info.preset_response, | |||
| "inputs": trace_info.inputs, | |||
| }, | |||
| attributes=attributes, | |||
| exception=getattr(trace_info, "error", None), | |||
| file_list=[], | |||
| ) | |||
| self.start_call(moderation_run, parent_run_id=trace_info.message_id) | |||
| self.finish_call(moderation_run) | |||
| def suggested_question_trace(self, trace_info: SuggestedQuestionTraceInfo): | |||
| message_data = trace_info.message_data | |||
| if message_data is None: | |||
| return | |||
| attributes = trace_info.metadata | |||
| attributes["message_id"] = trace_info.message_id | |||
| attributes["tags"] = ["suggested_question"] | |||
| attributes["start_time"] = (trace_info.start_time or message_data.created_at,) | |||
| attributes["end_time"] = (trace_info.end_time or message_data.updated_at,) | |||
| suggested_question_run = WeaveTraceModel( | |||
| id=str(uuid.uuid4()), | |||
| op=str(TraceTaskName.SUGGESTED_QUESTION_TRACE.value), | |||
| inputs=trace_info.inputs, | |||
| outputs=trace_info.suggested_question, | |||
| attributes=attributes, | |||
| exception=trace_info.error, | |||
| file_list=[], | |||
| ) | |||
| self.start_call(suggested_question_run, parent_run_id=trace_info.message_id) | |||
| self.finish_call(suggested_question_run) | |||
| def dataset_retrieval_trace(self, trace_info: DatasetRetrievalTraceInfo): | |||
| if trace_info.message_data is None: | |||
| return | |||
| attributes = trace_info.metadata | |||
| attributes["message_id"] = trace_info.message_id | |||
| attributes["tags"] = ["dataset_retrieval"] | |||
| attributes["start_time"] = (trace_info.start_time or trace_info.message_data.created_at,) | |||
| attributes["end_time"] = (trace_info.end_time or trace_info.message_data.updated_at,) | |||
| dataset_retrieval_run = WeaveTraceModel( | |||
| id=str(uuid.uuid4()), | |||
| op=str(TraceTaskName.DATASET_RETRIEVAL_TRACE.value), | |||
| inputs=trace_info.inputs, | |||
| outputs={"documents": trace_info.documents}, | |||
| attributes=attributes, | |||
| exception=getattr(trace_info, "error", None), | |||
| file_list=[], | |||
| ) | |||
| self.start_call(dataset_retrieval_run, parent_run_id=trace_info.message_id) | |||
| self.finish_call(dataset_retrieval_run) | |||
| def tool_trace(self, trace_info: ToolTraceInfo): | |||
| attributes = trace_info.metadata | |||
| attributes["tags"] = ["tool", trace_info.tool_name] | |||
| attributes["start_time"] = trace_info.start_time | |||
| attributes["end_time"] = trace_info.end_time | |||
| tool_run = WeaveTraceModel( | |||
| id=str(uuid.uuid4()), | |||
| op=trace_info.tool_name, | |||
| inputs=trace_info.tool_inputs, | |||
| outputs=trace_info.tool_outputs, | |||
| file_list=[cast(str, trace_info.file_url)] if trace_info.file_url else [], | |||
| attributes=attributes, | |||
| exception=trace_info.error, | |||
| ) | |||
| message_id = trace_info.message_id or getattr(trace_info, "conversation_id", None) | |||
| message_id = message_id or None | |||
| self.start_call(tool_run, parent_run_id=message_id) | |||
| self.finish_call(tool_run) | |||
| def generate_name_trace(self, trace_info: GenerateNameTraceInfo): | |||
| attributes = trace_info.metadata | |||
| attributes["tags"] = ["generate_name"] | |||
| attributes["start_time"] = trace_info.start_time | |||
| attributes["end_time"] = trace_info.end_time | |||
| name_run = WeaveTraceModel( | |||
| id=str(uuid.uuid4()), | |||
| op=str(TraceTaskName.GENERATE_NAME_TRACE.value), | |||
| inputs=trace_info.inputs, | |||
| outputs=trace_info.outputs, | |||
| attributes=attributes, | |||
| exception=getattr(trace_info, "error", None), | |||
| file_list=[], | |||
| ) | |||
| self.start_call(name_run) | |||
| self.finish_call(name_run) | |||
| def api_check(self): | |||
| try: | |||
| login_status = wandb.login(key=self.weave_api_key, verify=True, relogin=True) | |||
| if not login_status: | |||
| raise ValueError("Weave login failed") | |||
| else: | |||
| print("Weave login successful") | |||
| return True | |||
| except Exception as e: | |||
| logger.debug(f"Weave API check failed: {str(e)}") | |||
| raise ValueError(f"Weave API check failed: {str(e)}") | |||
| def start_call(self, run_data: WeaveTraceModel, parent_run_id: Optional[str] = None): | |||
| call = self.weave_client.create_call(op=run_data.op, inputs=run_data.inputs, attributes=run_data.attributes) | |||
| self.calls[run_data.id] = call | |||
| if parent_run_id: | |||
| self.calls[run_data.id].parent_id = parent_run_id | |||
| def finish_call(self, run_data: WeaveTraceModel): | |||
| call = self.calls.get(run_data.id) | |||
| if call: | |||
| self.weave_client.finish_call(call=call, output=run_data.outputs, exception=run_data.exception) | |||
| else: | |||
| raise ValueError(f"Call with id {run_data.id} not found") | |||
| @@ -82,6 +82,7 @@ dependencies = [ | |||
| "transformers~=4.35.0", | |||
| "unstructured[docx,epub,md,ppt,pptx]~=0.16.1", | |||
| "validators==0.21.0", | |||
| "weave~=0.51.34", | |||
| "yarl~=1.18.3", | |||
| ] | |||
| # Before adding new dependency, consider place it in | |||
| @@ -67,7 +67,14 @@ class OpsService: | |||
| new_decrypt_tracing_config.update({"project_url": project_url}) | |||
| except Exception: | |||
| new_decrypt_tracing_config.update({"project_url": "https://www.comet.com/opik/"}) | |||
| if tracing_provider == "weave" and ( | |||
| "project_url" not in decrypt_tracing_config or not decrypt_tracing_config.get("project_url") | |||
| ): | |||
| try: | |||
| project_url = OpsTraceManager.get_trace_config_project_url(decrypt_tracing_config, tracing_provider) | |||
| new_decrypt_tracing_config.update({"project_url": project_url}) | |||
| except Exception: | |||
| new_decrypt_tracing_config.update({"project_url": "https://wandb.ai/"}) | |||
| trace_config_data.tracing_config = new_decrypt_tracing_config | |||
| return trace_config_data.to_dict() | |||
| @@ -44,7 +44,10 @@ def process_trace_tasks(file_info): | |||
| trace_info = trace_type(**trace_info) | |||
| trace_instance.trace(trace_info) | |||
| logging.info(f"Processing trace tasks success, app_id: {app_id}") | |||
| except Exception: | |||
| except Exception as e: | |||
| logging.info( | |||
| f"error:\n\n\n{e}\n\n\n\n", | |||
| ) | |||
| failed_key = f"{OPS_TRACE_FAILED_KEY}_{app_id}" | |||
| redis_client.incr(failed_key) | |||
| logging.info(f"Processing trace tasks failed, app_id: {app_id}") | |||
| @@ -1,12 +1,19 @@ | |||
| version = 1 | |||
| revision = 1 | |||
| requires-python = ">=3.11, <3.13" | |||
| resolution-markers = [ | |||
| "python_full_version >= '3.12.4' and platform_python_implementation != 'PyPy'", | |||
| "python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_python_implementation != 'PyPy'", | |||
| "python_full_version >= '3.12.4' and platform_python_implementation == 'PyPy'", | |||
| "python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_python_implementation == 'PyPy'", | |||
| "python_full_version < '3.12' and platform_python_implementation != 'PyPy'", | |||
| "python_full_version < '3.12' and platform_python_implementation == 'PyPy'", | |||
| "python_full_version >= '3.12.4' and platform_python_implementation != 'PyPy' and sys_platform == 'linux'", | |||
| "python_full_version >= '3.12.4' and platform_python_implementation != 'PyPy' and sys_platform != 'linux'", | |||
| "python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_python_implementation != 'PyPy' and sys_platform == 'linux'", | |||
| "python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_python_implementation != 'PyPy' and sys_platform != 'linux'", | |||
| "python_full_version >= '3.12.4' and platform_python_implementation == 'PyPy' and sys_platform == 'linux'", | |||
| "python_full_version >= '3.12.4' and platform_python_implementation == 'PyPy' and sys_platform != 'linux'", | |||
| "python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_python_implementation == 'PyPy' and sys_platform == 'linux'", | |||
| "python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_python_implementation == 'PyPy' and sys_platform != 'linux'", | |||
| "python_full_version < '3.12' and platform_python_implementation != 'PyPy' and sys_platform == 'linux'", | |||
| "python_full_version < '3.12' and platform_python_implementation != 'PyPy' and sys_platform != 'linux'", | |||
| "python_full_version < '3.12' and platform_python_implementation == 'PyPy' and sys_platform == 'linux'", | |||
| "python_full_version < '3.12' and platform_python_implementation == 'PyPy' and sys_platform != 'linux'", | |||
| ] | |||
| [[package]] | |||
| @@ -627,7 +634,7 @@ name = "build" | |||
| version = "1.2.2.post1" | |||
| source = { registry = "https://pypi.org/simple" } | |||
| dependencies = [ | |||
| { name = "colorama", marker = "os_name == 'nt'" }, | |||
| { name = "colorama", marker = "os_name == 'nt' and sys_platform != 'linux'" }, | |||
| { name = "packaging" }, | |||
| { name = "pyproject-hooks" }, | |||
| ] | |||
| @@ -1227,6 +1234,7 @@ dependencies = [ | |||
| { name = "transformers" }, | |||
| { name = "unstructured", extra = ["docx", "epub", "md", "ppt", "pptx"] }, | |||
| { name = "validators" }, | |||
| { name = "weave" }, | |||
| { name = "yarl" }, | |||
| ] | |||
| @@ -1396,6 +1404,7 @@ requires-dist = [ | |||
| { name = "transformers", specifier = "~=4.35.0" }, | |||
| { name = "unstructured", extras = ["docx", "epub", "md", "ppt", "pptx"], specifier = "~=0.16.1" }, | |||
| { name = "validators", specifier = "==0.21.0" }, | |||
| { name = "weave", specifier = "~=0.51.34" }, | |||
| { name = "yarl", specifier = "~=1.18.3" }, | |||
| ] | |||
| @@ -1487,6 +1496,15 @@ vdb = [ | |||
| { name = "xinference-client", specifier = "~=1.2.2" }, | |||
| ] | |||
| [[package]] | |||
| name = "diskcache" | |||
| version = "5.6.3" | |||
| source = { registry = "https://pypi.org/simple" } | |||
| sdist = { url = "https://files.pythonhosted.org/packages/3f/21/1c1ffc1a039ddcc459db43cc108658f32c57d271d7289a2794e401d0fdb6/diskcache-5.6.3.tar.gz", hash = "sha256:2c3a3fa2743d8535d832ec61c2054a1641f41775aa7c556758a109941e33e4fc", size = 67916 } | |||
| wheels = [ | |||
| { url = "https://files.pythonhosted.org/packages/3f/27/4570e78fc0bf5ea0ca45eb1de3818a23787af9b390c0b0a0033a1b8236f9/diskcache-5.6.3-py3-none-any.whl", hash = "sha256:5e31b2d5fbad117cc363ebaf6b689474db18a1f6438bc82358b024abd4c2ca19", size = 45550 }, | |||
| ] | |||
| [[package]] | |||
| name = "distro" | |||
| version = "1.9.0" | |||
| @@ -1496,6 +1514,18 @@ wheels = [ | |||
| { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277 }, | |||
| ] | |||
| [[package]] | |||
| name = "docker-pycreds" | |||
| version = "0.4.0" | |||
| source = { registry = "https://pypi.org/simple" } | |||
| dependencies = [ | |||
| { name = "six" }, | |||
| ] | |||
| sdist = { url = "https://files.pythonhosted.org/packages/c5/e6/d1f6c00b7221e2d7c4b470132c931325c8b22c51ca62417e300f5ce16009/docker-pycreds-0.4.0.tar.gz", hash = "sha256:6ce3270bcaf404cc4c3e27e4b6c70d3521deae82fb508767870fdbf772d584d4", size = 8754 } | |||
| wheels = [ | |||
| { url = "https://files.pythonhosted.org/packages/f5/e8/f6bd1eee09314e7e6dee49cbe2c5e22314ccdb38db16c9fc72d2fa80d054/docker_pycreds-0.4.0-py2.py3-none-any.whl", hash = "sha256:7266112468627868005106ec19cd0d722702d2b7d5912a28e19b826c3d37af49", size = 8982 }, | |||
| ] | |||
| [[package]] | |||
| name = "docstring-parser" | |||
| version = "0.16" | |||
| @@ -1840,6 +1870,30 @@ wheels = [ | |||
| { url = "https://files.pythonhosted.org/packages/11/b2/5d20664ef6a077bec9f27f7a7ee761edc64946d0b1e293726a3d074a9a18/gevent-24.11.1-cp312-cp312-win_amd64.whl", hash = "sha256:68bee86b6e1c041a187347ef84cf03a792f0b6c7238378bf6ba4118af11feaae", size = 1541631 }, | |||
| ] | |||
| [[package]] | |||
| name = "gitdb" | |||
| version = "4.0.12" | |||
| source = { registry = "https://pypi.org/simple" } | |||
| dependencies = [ | |||
| { name = "smmap" }, | |||
| ] | |||
| sdist = { url = "https://files.pythonhosted.org/packages/72/94/63b0fc47eb32792c7ba1fe1b694daec9a63620db1e313033d18140c2320a/gitdb-4.0.12.tar.gz", hash = "sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571", size = 394684 } | |||
| wheels = [ | |||
| { url = "https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl", hash = "sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf", size = 62794 }, | |||
| ] | |||
| [[package]] | |||
| name = "gitpython" | |||
| version = "3.1.44" | |||
| source = { registry = "https://pypi.org/simple" } | |||
| dependencies = [ | |||
| { name = "gitdb" }, | |||
| ] | |||
| sdist = { url = "https://files.pythonhosted.org/packages/c0/89/37df0b71473153574a5cdef8f242de422a0f5d26d7a9e231e6f169b4ad14/gitpython-3.1.44.tar.gz", hash = "sha256:c87e30b26253bf5418b01b0660f818967f3c503193838337fe5e573331249269", size = 214196 } | |||
| wheels = [ | |||
| { url = "https://files.pythonhosted.org/packages/1d/9a/4114a9057db2f1462d5c8f8390ab7383925fe1ac012eaa42402ad65c2963/GitPython-3.1.44-py3-none-any.whl", hash = "sha256:9e0e10cda9bed1ee64bc9a6de50e7e38a9c9943241cd7f585f6df3ed28011110", size = 207599 }, | |||
| ] | |||
| [[package]] | |||
| name = "gmpy2" | |||
| version = "2.2.1" | |||
| @@ -2087,6 +2141,39 @@ wheels = [ | |||
| { url = "https://files.pythonhosted.org/packages/47/3a/1a7cac16438f4e5319a0c879416d5e5032c98c3db2874e6e5300b3b475e6/gotrue-2.11.4-py3-none-any.whl", hash = "sha256:712e5018acc00d93cfc6d7bfddc3114eb3c420ab03b945757a8ba38c5fc3caa8", size = 41106 }, | |||
| ] | |||
| [[package]] | |||
| name = "gql" | |||
| version = "3.5.2" | |||
| source = { registry = "https://pypi.org/simple" } | |||
| dependencies = [ | |||
| { name = "anyio" }, | |||
| { name = "backoff" }, | |||
| { name = "graphql-core" }, | |||
| { name = "yarl" }, | |||
| ] | |||
| sdist = { url = "https://files.pythonhosted.org/packages/49/ef/5298d9d628b6a54b3b810052cb5a935d324fe28d9bfdeb741733d5c2446b/gql-3.5.2.tar.gz", hash = "sha256:07e1325b820c8ba9478e95de27ce9f23250486e7e79113dbb7659a442dc13e74", size = 180502 } | |||
| wheels = [ | |||
| { url = "https://files.pythonhosted.org/packages/ff/71/b028b937992056e721bbf0371e13819fcca0dacde7b3c821f775ed903917/gql-3.5.2-py2.py3-none-any.whl", hash = "sha256:c830ffc38b3997b2a146317b27758305ab3d0da3bde607b49f34e32affb23ba2", size = 74346 }, | |||
| ] | |||
| [package.optional-dependencies] | |||
| aiohttp = [ | |||
| { name = "aiohttp" }, | |||
| ] | |||
| requests = [ | |||
| { name = "requests" }, | |||
| { name = "requests-toolbelt" }, | |||
| ] | |||
| [[package]] | |||
| name = "graphql-core" | |||
| version = "3.2.4" | |||
| source = { registry = "https://pypi.org/simple" } | |||
| sdist = { url = "https://files.pythonhosted.org/packages/66/9e/aa527fb09a9d7399d5d7d2aa2da490e4580707652d3b4fc156996ae88a5b/graphql-core-3.2.4.tar.gz", hash = "sha256:acbe2e800980d0e39b4685dd058c2f4042660b89ebca38af83020fd872ff1264", size = 504611 } | |||
| wheels = [ | |||
| { url = "https://files.pythonhosted.org/packages/d1/33/cc72c4c658c6316f188a60bc4e5a91cd4ceaaa8c3e7e691ac9297e4e72c7/graphql_core-3.2.4-py3-none-any.whl", hash = "sha256:1604f2042edc5f3114f49cac9d77e25863be51b23a54a61a23245cf32f6476f0", size = 203179 }, | |||
| ] | |||
| [[package]] | |||
| name = "greenlet" | |||
| version = "3.1.1" | |||
| @@ -3815,6 +3902,15 @@ wheels = [ | |||
| { url = "https://files.pythonhosted.org/packages/37/f3/9b18362206b244167c958984b57c7f70a0289bfb59a530dd8af5f699b910/pillow-11.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:4dd43a78897793f60766563969442020e90eb7847463eca901e41ba186a7d4a5", size = 2375240 }, | |||
| ] | |||
| [[package]] | |||
| name = "platformdirs" | |||
| version = "4.3.7" | |||
| source = { registry = "https://pypi.org/simple" } | |||
| sdist = { url = "https://files.pythonhosted.org/packages/b6/2d/7d512a3913d60623e7eb945c6d1b4f0bddf1d0b7ada5225274c87e5b53d1/platformdirs-4.3.7.tar.gz", hash = "sha256:eb437d586b6a0986388f0d6f74aa0cde27b48d0e3d66843640bfb6bdcdb6e351", size = 21291 } | |||
| wheels = [ | |||
| { url = "https://files.pythonhosted.org/packages/6d/45/59578566b3275b8fd9157885918fcd0c4d74162928a5310926887b856a51/platformdirs-4.3.7-py3-none-any.whl", hash = "sha256:a03875334331946f13c549dbd8f4bac7a13a50a895a0eb1e8c6a8ace80d40a94", size = 18499 }, | |||
| ] | |||
| [[package]] | |||
| name = "pluggy" | |||
| version = "1.5.0" | |||
| @@ -4084,8 +4180,6 @@ wheels = [ | |||
| { url = "https://files.pythonhosted.org/packages/af/cd/ed6e429fb0792ce368f66e83246264dd3a7a045b0b1e63043ed22a063ce5/pycryptodome-3.19.1-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:7c9e222d0976f68d0cf6409cfea896676ddc1d98485d601e9508f90f60e2b0a2", size = 2144914 }, | |||
| { url = "https://files.pythonhosted.org/packages/f6/23/b064bd4cfbf2cc5f25afcde0e7c880df5b20798172793137ba4b62d82e72/pycryptodome-3.19.1-cp35-abi3-win32.whl", hash = "sha256:4805e053571140cb37cf153b5c72cd324bb1e3e837cbe590a19f69b6cf85fd03", size = 1713105 }, | |||
| { url = "https://files.pythonhosted.org/packages/7d/e0/ded1968a5257ab34216a0f8db7433897a2337d59e6d03be113713b346ea2/pycryptodome-3.19.1-cp35-abi3-win_amd64.whl", hash = "sha256:a470237ee71a1efd63f9becebc0ad84b88ec28e6784a2047684b693f458f41b7", size = 1749222 }, | |||
| { url = "https://files.pythonhosted.org/packages/1d/e3/0c9679cd66cf5604b1f070bdf4525a0c01a15187be287d8348b2eafb718e/pycryptodome-3.19.1-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:ed932eb6c2b1c4391e166e1a562c9d2f020bfff44a0e1b108f67af38b390ea89", size = 1629005 }, | |||
| { url = "https://files.pythonhosted.org/packages/13/75/0d63bf0daafd0580b17202d8a9dd57f28c8487f26146b3e2799b0c5a059c/pycryptodome-3.19.1-pp27-pypy_73-win32.whl", hash = "sha256:81e9d23c0316fc1b45d984a44881b220062336bbdc340aa9218e8d0656587934", size = 1697997 }, | |||
| ] | |||
| [[package]] | |||
| @@ -4939,6 +5033,38 @@ flask = [ | |||
| { name = "markupsafe" }, | |||
| ] | |||
| [[package]] | |||
| name = "setproctitle" | |||
| version = "1.3.5" | |||
| source = { registry = "https://pypi.org/simple" } | |||
| sdist = { url = "https://files.pythonhosted.org/packages/c4/4d/6a840c8d2baa07b57329490e7094f90aac177a1d5226bc919046f1106860/setproctitle-1.3.5.tar.gz", hash = "sha256:1e6eaeaf8a734d428a95d8c104643b39af7d247d604f40a7bebcf3960a853c5e", size = 26737 } | |||
| wheels = [ | |||
| { url = "https://files.pythonhosted.org/packages/ec/4a/9e0243c5df221102fb834a947f5753d9da06ad5f84e36b0e2e93f7865edb/setproctitle-1.3.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1c8dcc250872385f2780a5ea58050b58cbc8b6a7e8444952a5a65c359886c593", size = 17256 }, | |||
| { url = "https://files.pythonhosted.org/packages/c7/a1/76ad2ba6f5bd00609238e3d64eeded4598e742a5f25b5cc1a0efdae5f674/setproctitle-1.3.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ca82fae9eb4800231dd20229f06e8919787135a5581da245b8b05e864f34cc8b", size = 11893 }, | |||
| { url = "https://files.pythonhosted.org/packages/47/3a/75d11fedff5b21ba9a4c5fe3dfa5e596f831d094ef1896713a72e9e38833/setproctitle-1.3.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0424e1d33232322541cb36fb279ea5242203cd6f20de7b4fb2a11973d8e8c2ce", size = 31631 }, | |||
| { url = "https://files.pythonhosted.org/packages/5a/12/58220de5600e0ed2e5562297173187d863db49babb03491ffe9c101299bc/setproctitle-1.3.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fec8340ab543144d04a9d805d80a0aad73fdeb54bea6ff94e70d39a676ea4ec0", size = 32975 }, | |||
| { url = "https://files.pythonhosted.org/packages/fa/c4/fbb308680d83c1c7aa626950308318c6e6381a8273779163a31741f3c752/setproctitle-1.3.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eab441c89f181271ab749077dcc94045a423e51f2fb0b120a1463ef9820a08d0", size = 30126 }, | |||
| { url = "https://files.pythonhosted.org/packages/31/6e/baaf70bd9a881dd8c12cbccdd7ca0ff291024a37044a8245e942e12e7135/setproctitle-1.3.5-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2c371550a2288901a0dcd84192691ebd3197a43c95f3e0b396ed6d1cedf5c6c", size = 31135 }, | |||
| { url = "https://files.pythonhosted.org/packages/a6/dc/d8ab6b1c3d844dc14f596e3cce76604570848f8a67ba6a3812775ed2c015/setproctitle-1.3.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:78288ff5f9c415c56595b2257ad218936dd9fa726b36341b373b31ca958590fe", size = 30874 }, | |||
| { url = "https://files.pythonhosted.org/packages/d4/84/62a359b3aa51228bd88f78b44ebb0256a5b96dd2487881c1e984a59b617d/setproctitle-1.3.5-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f1f13a25fc46731acab518602bb1149bfd8b5fabedf8290a7c0926d61414769d", size = 29893 }, | |||
| { url = "https://files.pythonhosted.org/packages/e2/d6/b3c52c03ee41e7f006e1a737e0db1c58d1dc28e258b83548e653d0c34f1c/setproctitle-1.3.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1534d6cd3854d035e40bf4c091984cbdd4d555d7579676d406c53c8f187c006f", size = 32293 }, | |||
| { url = "https://files.pythonhosted.org/packages/55/09/c0ba311879d9c05860503a7e2708ace85913b9a816786402a92c664fe930/setproctitle-1.3.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:62a01c76708daac78b9688ffb95268c57cb57fa90b543043cda01358912fe2db", size = 30247 }, | |||
| { url = "https://files.pythonhosted.org/packages/9e/43/cc7155461f0b5a48aebdb87d78239ff3a51ebda0905de478d9fa6ab92d9c/setproctitle-1.3.5-cp311-cp311-win32.whl", hash = "sha256:ea07f29735d839eaed985990a0ec42c8aecefe8050da89fec35533d146a7826d", size = 11476 }, | |||
| { url = "https://files.pythonhosted.org/packages/e7/57/6e937ac7aa52db69225f02db2cfdcb66ba1db6fdc65a4ddbdf78e214f72a/setproctitle-1.3.5-cp311-cp311-win_amd64.whl", hash = "sha256:ab3ae11e10d13d514d4a5a15b4f619341142ba3e18da48c40e8614c5a1b5e3c3", size = 12189 }, | |||
| { url = "https://files.pythonhosted.org/packages/2b/19/04755958495de57e4891de50f03e77b3fe9ca6716a86de00faa00ad0ee5a/setproctitle-1.3.5-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:523424b9be4dea97d95b8a584b183f35c7bab2d0a3d995b01febf5b8a8de90e4", size = 17250 }, | |||
| { url = "https://files.pythonhosted.org/packages/b9/3d/2ca9df5aa49b975296411dcbbe272cdb1c5e514c43b8be7d61751bb71a46/setproctitle-1.3.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b6ec1d86c1b4d7b5f2bdceadf213310cf24696b82480a2a702194b8a0bfbcb47", size = 11878 }, | |||
| { url = "https://files.pythonhosted.org/packages/36/d6/e90e23b4627e016a4f862d4f892be92c9765dd6bf1e27a48e52cd166d4a3/setproctitle-1.3.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea6c505264275a43e9b2acd2acfc11ac33caf52bc3167c9fced4418a810f6b1c", size = 31940 }, | |||
| { url = "https://files.pythonhosted.org/packages/15/13/167cdd55e00a8e10b36aad79646c3bf3c23fba0c08a9b8db9b74622c1b13/setproctitle-1.3.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0b91e68e6685998e6353f296100ecabc313a6cb3e413d66a03d74b988b61f5ff", size = 33370 }, | |||
| { url = "https://files.pythonhosted.org/packages/9b/22/574a110527df133409a75053b7d6ff740993ccf30b8713d042f26840d351/setproctitle-1.3.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bc1fda208ae3a2285ad27aeab44c41daf2328abe58fa3270157a739866779199", size = 30628 }, | |||
| { url = "https://files.pythonhosted.org/packages/52/79/78b05c7d792c9167b917acdab1773b1ff73b016560f45d8155be2baa1a82/setproctitle-1.3.5-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:828727d220e46f048b82289018300a64547b46aaed96bf8810c05fe105426b41", size = 31672 }, | |||
| { url = "https://files.pythonhosted.org/packages/b0/62/4509735be062129694751ac55d5e1fbb6d86fa46a8689b7d5e2c23dae5b0/setproctitle-1.3.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:83b016221cf80028b2947be20630faa14e3e72a403e35f0ba29550b4e856767b", size = 31378 }, | |||
| { url = "https://files.pythonhosted.org/packages/72/e7/b394c55934b89f00c2ef7d5e6f18cca5d8dfa26ef628700c4de0c85e3f3d/setproctitle-1.3.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:6d8a411e752e794d052434139ca4234ffeceeb8d8d8ddc390a9051d7942b2726", size = 30370 }, | |||
| { url = "https://files.pythonhosted.org/packages/13/ee/e1f27bf52d2bec7060bb6311ab0ccede8de98ed5394e3a59e7a14a453fb5/setproctitle-1.3.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:50cfbf86b9c63a2c2903f1231f0a58edeb775e651ae1af84eec8430b0571f29b", size = 32875 }, | |||
| { url = "https://files.pythonhosted.org/packages/6e/08/13b561085d2de53b9becfa5578545d99114e9ff2aa3dc151bcaadf80b17e/setproctitle-1.3.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f3b5e2eacd572444770026c9dd3ddc7543ce427cdf452d40a408d1e95beefb30", size = 30903 }, | |||
| { url = "https://files.pythonhosted.org/packages/65/f0/6cd06fffff2553be7b0571447d0c0ef8b727ef44cc2d6a33452677a311c8/setproctitle-1.3.5-cp312-cp312-win32.whl", hash = "sha256:cf4e3ded98027de2596c6cc5bbd3302adfb3ca315c848f56516bb0b7e88de1e9", size = 11468 }, | |||
| { url = "https://files.pythonhosted.org/packages/c1/8c/e8a7cb568c4552618838941b332203bfc77ab0f2d67c1cb8f24dee0370ec/setproctitle-1.3.5-cp312-cp312-win_amd64.whl", hash = "sha256:f7a8c01ffd013dda2bed6e7d5cb59fbb609e72f805abf3ee98360f38f7758d9b", size = 12190 }, | |||
| ] | |||
| [[package]] | |||
| name = "setuptools" | |||
| version = "78.1.0" | |||
| @@ -4993,6 +5119,15 @@ wheels = [ | |||
| { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050 }, | |||
| ] | |||
| [[package]] | |||
| name = "smmap" | |||
| version = "5.0.2" | |||
| source = { registry = "https://pypi.org/simple" } | |||
| sdist = { url = "https://files.pythonhosted.org/packages/44/cd/a040c4b3119bbe532e5b0732286f805445375489fceaec1f48306068ee3b/smmap-5.0.2.tar.gz", hash = "sha256:26ea65a03958fa0c8a1c7e8c7a58fdc77221b8910f6be2131affade476898ad5", size = 22329 } | |||
| wheels = [ | |||
| { url = "https://files.pythonhosted.org/packages/04/be/d09147ad1ec7934636ad912901c5fd7667e1c858e19d355237db0d0cd5e4/smmap-5.0.2-py3-none-any.whl", hash = "sha256:b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e", size = 24303 }, | |||
| ] | |||
| [[package]] | |||
| name = "sniffio" | |||
| version = "1.3.1" | |||
| @@ -5876,6 +6011,26 @@ wheels = [ | |||
| { url = "https://files.pythonhosted.org/packages/c8/19/4ec628951a74043532ca2cf5d97b7b14863931476d117c471e8e2b1eb39f/urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", size = 128369 }, | |||
| ] | |||
| [[package]] | |||
| name = "uuid-utils" | |||
| version = "0.10.0" | |||
| source = { registry = "https://pypi.org/simple" } | |||
| sdist = { url = "https://files.pythonhosted.org/packages/66/0a/cbdb2eb4845dafeb632d02a18f47b02f87f2ce4f25266f5e3c017976ce89/uuid_utils-0.10.0.tar.gz", hash = "sha256:5db0e1890e8f008657ffe6ded4d9459af724ab114cfe82af1557c87545301539", size = 18828 } | |||
| wheels = [ | |||
| { url = "https://files.pythonhosted.org/packages/44/54/9d22fa16b19e5d1676eba510f08a9c458d96e2a62ff2c8ebad64251afb18/uuid_utils-0.10.0-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:8d5a4508feefec62456cd6a41bcdde458d56827d908f226803b886d22a3d5e63", size = 573006 }, | |||
| { url = "https://files.pythonhosted.org/packages/08/8e/f895c6e52aa603e521fbc13b8626ba5dd99b6e2f5a55aa96ba5b232f4c53/uuid_utils-0.10.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:dbefc2b9113f9dfe56bdae58301a2b3c53792221410d422826f3d1e3e6555fe7", size = 292543 }, | |||
| { url = "https://files.pythonhosted.org/packages/b6/58/cc4834f377a5e97d6e184408ad96d13042308de56643b6e24afe1f6f34df/uuid_utils-0.10.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffc49c33edf87d1ec8112a9b43e4cf55326877716f929c165a2cc307d31c73d5", size = 323340 }, | |||
| { url = "https://files.pythonhosted.org/packages/37/e3/6aeddf148f6a7dd7759621b000e8c85382ec83f52ae79b60842d1dc3ab6b/uuid_utils-0.10.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0636b6208f69d5a4e629707ad2a89a04dfa8d1023e1999181f6830646ca048a1", size = 329653 }, | |||
| { url = "https://files.pythonhosted.org/packages/0c/00/dd6c2164ace70b7b1671d9129267df331481d7d1e5f9c5e6a564f07953f6/uuid_utils-0.10.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7bc06452856b724df9dedfc161c3582199547da54aeb81915ec2ed54f92d19b0", size = 365471 }, | |||
| { url = "https://files.pythonhosted.org/packages/b4/e7/0ab8080fcae5462a7b5e555c1cef3d63457baffb97a59b9bc7b005a3ecb1/uuid_utils-0.10.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:263b2589111c61decdd74a762e8f850c9e4386fb78d2cf7cb4dfc537054cda1b", size = 325844 }, | |||
| { url = "https://files.pythonhosted.org/packages/73/39/52d94e9ef75b03f44b39ffc6ac3167e93e74ef4d010a93d25589d9f48540/uuid_utils-0.10.0-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a558db48b7096de6b4d2d2210d82bba8586a6d55f99106b03bb7d01dc5c5bcd6", size = 344389 }, | |||
| { url = "https://files.pythonhosted.org/packages/7c/29/4824566f62666238290d99c62a58e4ab2a8b9cf2eccf94cebd9b3359131e/uuid_utils-0.10.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:807465067f3c892514230326ac71a79b28a8dfe2c88ecd2d5675fc844f3c76b5", size = 510078 }, | |||
| { url = "https://files.pythonhosted.org/packages/5e/8f/bbcc7130d652462c685f0d3bd26bb214b754215b476340885a4cb50fb89a/uuid_utils-0.10.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:57423d4a2b9d7b916de6dbd75ba85465a28f9578a89a97f7d3e098d9aa4e5d4a", size = 515937 }, | |||
| { url = "https://files.pythonhosted.org/packages/23/f8/34e0c00f5f188604d336713e6a020fcf53b10998e8ab24735a39ab076740/uuid_utils-0.10.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:76d8d660f18ff6b767e319b1b5f927350cd92eafa4831d7ef5b57fdd1d91f974", size = 494111 }, | |||
| { url = "https://files.pythonhosted.org/packages/1a/52/b7f0066cc90a7a9c28d54061ed195cd617fde822e5d6ac3ccc88509c3c44/uuid_utils-0.10.0-cp39-abi3-win32.whl", hash = "sha256:6c11a71489338837db0b902b75e1ba7618d5d29f05fde4f68b3f909177dbc226", size = 173520 }, | |||
| { url = "https://files.pythonhosted.org/packages/8b/15/f04f58094674d333974243fb45d2c740cf4b79186fb707168e57943c84a3/uuid_utils-0.10.0-cp39-abi3-win_amd64.whl", hash = "sha256:11c55ae64f6c0a7a0c741deae8ca2a4eaa11e9c09dbb7bec2099635696034cf7", size = 182965 }, | |||
| ] | |||
| [[package]] | |||
| name = "uuid6" | |||
| version = "2024.7.10" | |||
| @@ -5965,6 +6120,36 @@ wheels = [ | |||
| { url = "https://files.pythonhosted.org/packages/37/da/7ccbe82470dc27e1cfd0466dc637248be906eb8447c28a40c1c74cf617ee/volcengine_compat-1.0.156-py3-none-any.whl", hash = "sha256:4abc149a7601ebad8fa2d28fab50c7945145cf74daecb71bca797b0bdc82c5a5", size = 677272 }, | |||
| ] | |||
| [[package]] | |||
| name = "wandb" | |||
| version = "0.18.3" | |||
| source = { registry = "https://pypi.org/simple" } | |||
| dependencies = [ | |||
| { name = "click" }, | |||
| { name = "docker-pycreds" }, | |||
| { name = "gitpython" }, | |||
| { name = "platformdirs" }, | |||
| { name = "protobuf" }, | |||
| { name = "psutil" }, | |||
| { name = "pyyaml" }, | |||
| { name = "requests" }, | |||
| { name = "sentry-sdk" }, | |||
| { name = "setproctitle" }, | |||
| { name = "setuptools" }, | |||
| ] | |||
| sdist = { url = "https://files.pythonhosted.org/packages/cc/57/8a61979c40a7a0a5206ef3369ed474326135bf292f172019f35dca97a235/wandb-0.18.3.tar.gz", hash = "sha256:eb2574cea72bc908c6ce1b37edf7a889619e6e06e1b4714eecfe0662ded43c06", size = 8686381 } | |||
| wheels = [ | |||
| { url = "https://files.pythonhosted.org/packages/1c/4a/6fa1d584ecd69cea5b9943ec5cfa36276cbd567efa8709135a7e4ab89cfb/wandb-0.18.3-py3-none-any.whl", hash = "sha256:7da64f7da0ff7572439de10bfd45534e8811e71e78ac2ccc3b818f1c0f3a9aef", size = 5015658 }, | |||
| { url = "https://files.pythonhosted.org/packages/59/8f/deef595ca67833ea5aceb5da5fc10759a5e8f8bce85b17761b1614fa2ba9/wandb-0.18.3-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:6674d8a5c40c79065b9c7eb765136756d5ebc9457a5f9abc820a660fb23f8b67", size = 10081571 }, | |||
| { url = "https://files.pythonhosted.org/packages/06/85/b55642d095407369dd7ad1d8ea1e7f410d60fcdb6c29bcc9afb1e5522d51/wandb-0.18.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:741f566e409a2684d3047e4cc25e8e914d78196b901190937b24b6abb8b052e5", size = 10008319 }, | |||
| { url = "https://files.pythonhosted.org/packages/b4/53/5387afaab29876e669973b3bb5bda829e3c10e509caef59f614bf20c0106/wandb-0.18.3-py3-none-macosx_11_0_x86_64.whl", hash = "sha256:8be5e877570b693001c52dcc2089e48e6a4dcbf15f3adf5c9349f95148b59d58", size = 10250633 }, | |||
| { url = "https://files.pythonhosted.org/packages/bd/79/2fa554283afa7259e296313160164947daf52e0d42b04d6ecf9c5af01e15/wandb-0.18.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d788852bd4739fa18de3918f309c3a955b5cef3247fae1c40df3a63af637e1a0", size = 12339454 }, | |||
| { url = "https://files.pythonhosted.org/packages/86/a6/11eaa16c96469b4d6fc0fb3271e70d5bbe2c3a93c15fc677de9a1aa4374a/wandb-0.18.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab81424eb207d78239a8d69c90521a70074fb81e3709055484e43c76fe44dc08", size = 12970950 }, | |||
| { url = "https://files.pythonhosted.org/packages/13/dd/ccaa5a51e2557368300eec9e362b5688151e45a052e33017633baa3011a9/wandb-0.18.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:2c91315b8b62423eae18577d66a4b4bb8e4341a7d5c849cb2963e3b3dff0bf6d", size = 13038220 }, | |||
| { url = "https://files.pythonhosted.org/packages/bc/6f/fabbf2161078556384ef48f3db89182773010cdd14900986004e702b85f5/wandb-0.18.3-py3-none-win32.whl", hash = "sha256:92a647dab783938ec87776a9fae8a13e72e6dad939c53e357cdea9d2570f0ad8", size = 12573298 }, | |||
| { url = "https://files.pythonhosted.org/packages/d8/7b/e94b46d620d26b2e1f486f2746febdcb6579be20f361355b40263ddd8262/wandb-0.18.3-py3-none-win_amd64.whl", hash = "sha256:29cac2cfa3124241fed22cfedc9a52e1500275ee9bbb0b428ce4bf63c4723bf0", size = 12573303 }, | |||
| ] | |||
| [[package]] | |||
| name = "watchfiles" | |||
| version = "1.0.5" | |||
| @@ -6011,6 +6196,28 @@ wheels = [ | |||
| { url = "https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", size = 34166 }, | |||
| ] | |||
| [[package]] | |||
| name = "weave" | |||
| version = "0.51.43" | |||
| source = { registry = "https://pypi.org/simple" } | |||
| dependencies = [ | |||
| { name = "diskcache" }, | |||
| { name = "emoji" }, | |||
| { name = "gql", extra = ["aiohttp", "requests"] }, | |||
| { name = "jsonschema" }, | |||
| { name = "numpy" }, | |||
| { name = "packaging" }, | |||
| { name = "pydantic" }, | |||
| { name = "rich" }, | |||
| { name = "tenacity" }, | |||
| { name = "uuid-utils" }, | |||
| { name = "wandb" }, | |||
| ] | |||
| sdist = { url = "https://files.pythonhosted.org/packages/e1/b4/8fb1e21bc0b0442be9c4c5e4644847596cd75a35a313a5887f1eadda8da2/weave-0.51.43.tar.gz", hash = "sha256:bab4ba6f7ba33f1975e5f6399b7fc4ad6b25c0e2cd22d197bb9358a7b9596b91", size = 368936 } | |||
| wheels = [ | |||
| { url = "https://files.pythonhosted.org/packages/a8/40/1e374d3f1f8389a4228426b5a87aae7428a7eb74dfa633de98d86796eb41/weave-0.51.43-py3-none-any.whl", hash = "sha256:2e9faa0e21bd5a6fea363142891ee4f2e347951b98f0d7082acb0273432cb940", size = 473685 }, | |||
| ] | |||
| [[package]] | |||
| name = "weaviate-client" | |||
| version = "3.21.0" | |||
| @@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next' | |||
| import { useBoolean } from 'ahooks' | |||
| import TracingIcon from './tracing-icon' | |||
| import ProviderPanel from './provider-panel' | |||
| import type { LangFuseConfig, LangSmithConfig, OpikConfig } from './type' | |||
| import type { LangFuseConfig, LangSmithConfig, OpikConfig, WeaveConfig } from './type' | |||
| import { TracingProvider } from './type' | |||
| import ProviderConfigModal from './provider-config-modal' | |||
| import Indicator from '@/app/components/header/indicator' | |||
| @@ -26,7 +26,8 @@ export type PopupProps = { | |||
| langSmithConfig: LangSmithConfig | null | |||
| langFuseConfig: LangFuseConfig | null | |||
| opikConfig: OpikConfig | null | |||
| onConfigUpdated: (provider: TracingProvider, payload: LangSmithConfig | LangFuseConfig | OpikConfig) => void | |||
| weaveConfig: WeaveConfig | null | |||
| onConfigUpdated: (provider: TracingProvider, payload: LangSmithConfig | LangFuseConfig | OpikConfig | WeaveConfig) => void | |||
| onConfigRemoved: (provider: TracingProvider) => void | |||
| } | |||
| @@ -40,6 +41,7 @@ const ConfigPopup: FC<PopupProps> = ({ | |||
| langSmithConfig, | |||
| langFuseConfig, | |||
| opikConfig, | |||
| weaveConfig, | |||
| onConfigUpdated, | |||
| onConfigRemoved, | |||
| }) => { | |||
| @@ -63,7 +65,7 @@ const ConfigPopup: FC<PopupProps> = ({ | |||
| } | |||
| }, [onChooseProvider]) | |||
| const handleConfigUpdated = useCallback((payload: LangSmithConfig | LangFuseConfig | OpikConfig) => { | |||
| const handleConfigUpdated = useCallback((payload: LangSmithConfig | LangFuseConfig | OpikConfig | WeaveConfig) => { | |||
| onConfigUpdated(currentProvider!, payload) | |||
| hideConfigModal() | |||
| }, [currentProvider, hideConfigModal, onConfigUpdated]) | |||
| @@ -73,8 +75,8 @@ const ConfigPopup: FC<PopupProps> = ({ | |||
| hideConfigModal() | |||
| }, [currentProvider, hideConfigModal, onConfigRemoved]) | |||
| const providerAllConfigured = langSmithConfig && langFuseConfig && opikConfig | |||
| const providerAllNotConfigured = !langSmithConfig && !langFuseConfig && !opikConfig | |||
| const providerAllConfigured = langSmithConfig && langFuseConfig && opikConfig && weaveConfig | |||
| const providerAllNotConfigured = !langSmithConfig && !langFuseConfig && !opikConfig && !weaveConfig | |||
| const switchContent = ( | |||
| <Switch | |||
| @@ -123,33 +125,51 @@ const ConfigPopup: FC<PopupProps> = ({ | |||
| /> | |||
| ) | |||
| const weavePanel = ( | |||
| <ProviderPanel | |||
| type={TracingProvider.weave} | |||
| readOnly={readOnly} | |||
| config={weaveConfig} | |||
| hasConfigured={!!weaveConfig} | |||
| onConfig={handleOnConfig(TracingProvider.weave)} | |||
| isChosen={chosenProvider === TracingProvider.weave} | |||
| onChoose={handleOnChoose(TracingProvider.weave)} | |||
| key="weave-provider-panel" | |||
| /> | |||
| ) | |||
| const configuredProviderPanel = () => { | |||
| const configuredPanels: JSX.Element[] = [] | |||
| if (langSmithConfig) | |||
| configuredPanels.push(langSmithPanel) | |||
| if (langFuseConfig) | |||
| configuredPanels.push(langfusePanel) | |||
| if (langSmithConfig) | |||
| configuredPanels.push(langSmithPanel) | |||
| if (opikConfig) | |||
| configuredPanels.push(opikPanel) | |||
| if (weaveConfig) | |||
| configuredPanels.push(weavePanel) | |||
| return configuredPanels | |||
| } | |||
| const moreProviderPanel = () => { | |||
| const notConfiguredPanels: JSX.Element[] = [] | |||
| if (!langSmithConfig) | |||
| notConfiguredPanels.push(langSmithPanel) | |||
| if (!langFuseConfig) | |||
| notConfiguredPanels.push(langfusePanel) | |||
| if (!langSmithConfig) | |||
| notConfiguredPanels.push(langSmithPanel) | |||
| if (!opikConfig) | |||
| notConfiguredPanels.push(opikPanel) | |||
| if (!weaveConfig) | |||
| notConfiguredPanels.push(weavePanel) | |||
| return notConfiguredPanels | |||
| } | |||
| @@ -158,7 +178,9 @@ const ConfigPopup: FC<PopupProps> = ({ | |||
| return langSmithConfig | |||
| if (currentProvider === TracingProvider.langfuse) | |||
| return langFuseConfig | |||
| return opikConfig | |||
| if (currentProvider === TracingProvider.opik) | |||
| return opikConfig | |||
| return weaveConfig | |||
| } | |||
| return ( | |||
| @@ -199,9 +221,10 @@ const ConfigPopup: FC<PopupProps> = ({ | |||
| <> | |||
| <div className='system-xs-medium-uppercase text-text-tertiary'>{t(`${I18N_PREFIX}.configProviderTitle.${providerAllConfigured ? 'configured' : 'notConfigured'}`)}</div> | |||
| <div className='mt-2 space-y-2'> | |||
| {langSmithPanel} | |||
| {langfusePanel} | |||
| {langSmithPanel} | |||
| {opikPanel} | |||
| {weavePanel} | |||
| </div> | |||
| </> | |||
| ) | |||
| @@ -4,4 +4,5 @@ export const docURL = { | |||
| [TracingProvider.langSmith]: 'https://docs.smith.langchain.com/', | |||
| [TracingProvider.langfuse]: 'https://docs.langfuse.com', | |||
| [TracingProvider.opik]: 'https://www.comet.com/docs/opik/tracing/integrations/dify#setup-instructions', | |||
| [TracingProvider.weave]: 'https://weave-docs.wandb.ai/', | |||
| } | |||
| @@ -7,12 +7,12 @@ import { | |||
| import { useTranslation } from 'react-i18next' | |||
| import { usePathname } from 'next/navigation' | |||
| import { useBoolean } from 'ahooks' | |||
| import type { LangFuseConfig, LangSmithConfig, OpikConfig } from './type' | |||
| import type { LangFuseConfig, LangSmithConfig, OpikConfig, WeaveConfig } from './type' | |||
| import { TracingProvider } from './type' | |||
| import TracingIcon from './tracing-icon' | |||
| import ConfigButton from './config-button' | |||
| import cn from '@/utils/classnames' | |||
| import { LangfuseIcon, LangsmithIcon, OpikIcon } from '@/app/components/base/icons/src/public/tracing' | |||
| import { LangfuseIcon, LangsmithIcon, OpikIcon, WeaveIcon } from '@/app/components/base/icons/src/public/tracing' | |||
| import Indicator from '@/app/components/header/indicator' | |||
| import { fetchTracingConfig as doFetchTracingConfig, fetchTracingStatus, updateTracingStatus } from '@/service/apps' | |||
| import type { TracingStatus } from '@/models/app' | |||
| @@ -82,12 +82,15 @@ const Panel: FC = () => { | |||
| ? LangfuseIcon | |||
| : inUseTracingProvider === TracingProvider.opik | |||
| ? OpikIcon | |||
| : LangsmithIcon | |||
| : inUseTracingProvider === TracingProvider.weave | |||
| ? WeaveIcon | |||
| : LangsmithIcon | |||
| const [langSmithConfig, setLangSmithConfig] = useState<LangSmithConfig | null>(null) | |||
| const [langFuseConfig, setLangFuseConfig] = useState<LangFuseConfig | null>(null) | |||
| const [opikConfig, setOpikConfig] = useState<OpikConfig | null>(null) | |||
| const hasConfiguredTracing = !!(langSmithConfig || langFuseConfig || opikConfig) | |||
| const [weaveConfig, setWeaveConfig] = useState<WeaveConfig | null>(null) | |||
| const hasConfiguredTracing = !!(langSmithConfig || langFuseConfig || opikConfig || weaveConfig) | |||
| const fetchTracingConfig = async () => { | |||
| const { tracing_config: langSmithConfig, has_not_configured: langSmithHasNotConfig } = await doFetchTracingConfig({ appId, provider: TracingProvider.langSmith }) | |||
| @@ -99,6 +102,9 @@ const Panel: FC = () => { | |||
| const { tracing_config: opikConfig, has_not_configured: OpikHasNotConfig } = await doFetchTracingConfig({ appId, provider: TracingProvider.opik }) | |||
| if (!OpikHasNotConfig) | |||
| setOpikConfig(opikConfig as OpikConfig) | |||
| const { tracing_config: weaveConfig, has_not_configured: weaveHasNotConfig } = await doFetchTracingConfig({ appId, provider: TracingProvider.weave }) | |||
| if (!weaveHasNotConfig) | |||
| setWeaveConfig(weaveConfig as WeaveConfig) | |||
| } | |||
| const handleTracingConfigUpdated = async (provider: TracingProvider) => { | |||
| @@ -110,6 +116,8 @@ const Panel: FC = () => { | |||
| setLangFuseConfig(tracing_config as LangFuseConfig) | |||
| else if (provider === TracingProvider.opik) | |||
| setOpikConfig(tracing_config as OpikConfig) | |||
| else if (provider === TracingProvider.weave) | |||
| setWeaveConfig(tracing_config as WeaveConfig) | |||
| } | |||
| const handleTracingConfigRemoved = (provider: TracingProvider) => { | |||
| @@ -119,6 +127,8 @@ const Panel: FC = () => { | |||
| setLangFuseConfig(null) | |||
| else if (provider === TracingProvider.opik) | |||
| setOpikConfig(null) | |||
| else if (provider === TracingProvider.weave) | |||
| setWeaveConfig(null) | |||
| if (provider === inUseTracingProvider) { | |||
| handleTracingStatusChange({ | |||
| enabled: false, | |||
| @@ -178,6 +188,7 @@ const Panel: FC = () => { | |||
| langSmithConfig={langSmithConfig} | |||
| langFuseConfig={langFuseConfig} | |||
| opikConfig={opikConfig} | |||
| weaveConfig={weaveConfig} | |||
| onConfigUpdated={handleTracingConfigUpdated} | |||
| onConfigRemoved={handleTracingConfigRemoved} | |||
| controlShowPopup={controlShowPopup} | |||
| @@ -212,6 +223,7 @@ const Panel: FC = () => { | |||
| langSmithConfig={langSmithConfig} | |||
| langFuseConfig={langFuseConfig} | |||
| opikConfig={opikConfig} | |||
| weaveConfig={weaveConfig} | |||
| onConfigUpdated={handleTracingConfigUpdated} | |||
| onConfigRemoved={handleTracingConfigRemoved} | |||
| controlShowPopup={controlShowPopup} | |||
| @@ -4,7 +4,7 @@ import React, { useCallback, useState } from 'react' | |||
| import { useTranslation } from 'react-i18next' | |||
| import { useBoolean } from 'ahooks' | |||
| import Field from './field' | |||
| import type { LangFuseConfig, LangSmithConfig, OpikConfig } from './type' | |||
| import type { LangFuseConfig, LangSmithConfig, OpikConfig, WeaveConfig } from './type' | |||
| import { TracingProvider } from './type' | |||
| import { docURL } from './config' | |||
| import { | |||
| @@ -22,10 +22,10 @@ import Divider from '@/app/components/base/divider' | |||
| type Props = { | |||
| appId: string | |||
| type: TracingProvider | |||
| payload?: LangSmithConfig | LangFuseConfig | OpikConfig | null | |||
| payload?: LangSmithConfig | LangFuseConfig | OpikConfig | WeaveConfig | null | |||
| onRemoved: () => void | |||
| onCancel: () => void | |||
| onSaved: (payload: LangSmithConfig | LangFuseConfig | OpikConfig) => void | |||
| onSaved: (payload: LangSmithConfig | LangFuseConfig | OpikConfig | WeaveConfig) => void | |||
| onChosen: (provider: TracingProvider) => void | |||
| } | |||
| @@ -50,6 +50,13 @@ const opikConfigTemplate = { | |||
| workspace: '', | |||
| } | |||
| const weaveConfigTemplate = { | |||
| api_key: '', | |||
| entity: '', | |||
| project: '', | |||
| endpoint: '', | |||
| } | |||
| const ProviderConfigModal: FC<Props> = ({ | |||
| appId, | |||
| type, | |||
| @@ -63,7 +70,7 @@ const ProviderConfigModal: FC<Props> = ({ | |||
| const isEdit = !!payload | |||
| const isAdd = !isEdit | |||
| const [isSaving, setIsSaving] = useState(false) | |||
| const [config, setConfig] = useState<LangSmithConfig | LangFuseConfig | OpikConfig>((() => { | |||
| const [config, setConfig] = useState<LangSmithConfig | LangFuseConfig | OpikConfig | WeaveConfig>((() => { | |||
| if (isEdit) | |||
| return payload | |||
| @@ -73,7 +80,10 @@ const ProviderConfigModal: FC<Props> = ({ | |||
| else if (type === TracingProvider.langfuse) | |||
| return langFuseConfigTemplate | |||
| return opikConfigTemplate | |||
| else if (type === TracingProvider.opik) | |||
| return opikConfigTemplate | |||
| return weaveConfigTemplate | |||
| })()) | |||
| const [isShowRemoveConfirm, { | |||
| setTrue: showRemoveConfirm, | |||
| @@ -127,6 +137,14 @@ const ProviderConfigModal: FC<Props> = ({ | |||
| // const postData = config as OpikConfig | |||
| } | |||
| if (type === TracingProvider.weave) { | |||
| const postData = config as WeaveConfig | |||
| if (!errorMessage && !postData.api_key) | |||
| errorMessage = t('common.errorMsg.fieldRequired', { field: 'API Key' }) | |||
| if (!errorMessage && !postData.project) | |||
| errorMessage = t('common.errorMsg.fieldRequired', { field: t(`${I18N_PREFIX}.project`) }) | |||
| } | |||
| return errorMessage | |||
| }, [config, t, type]) | |||
| const handleSave = useCallback(async () => { | |||
| @@ -176,6 +194,40 @@ const ProviderConfigModal: FC<Props> = ({ | |||
| </div> | |||
| <div className='space-y-4'> | |||
| {type === TracingProvider.weave && ( | |||
| <> | |||
| <Field | |||
| label='API Key' | |||
| labelClassName='!text-sm' | |||
| isRequired | |||
| value={(config as WeaveConfig).api_key} | |||
| onChange={handleConfigChange('api_key')} | |||
| placeholder={t(`${I18N_PREFIX}.placeholder`, { key: 'API Key' })!} | |||
| /> | |||
| <Field | |||
| label={t(`${I18N_PREFIX}.project`)!} | |||
| labelClassName='!text-sm' | |||
| isRequired | |||
| value={(config as WeaveConfig).project} | |||
| onChange={handleConfigChange('project')} | |||
| placeholder={t(`${I18N_PREFIX}.placeholder`, { key: t(`${I18N_PREFIX}.project`) })!} | |||
| /> | |||
| <Field | |||
| label='Entity' | |||
| labelClassName='!text-sm' | |||
| value={(config as WeaveConfig).entity} | |||
| onChange={handleConfigChange('entity')} | |||
| placeholder={t(`${I18N_PREFIX}.placeholder`, { key: 'Entity' })!} | |||
| /> | |||
| <Field | |||
| label='Endpoint' | |||
| labelClassName='!text-sm' | |||
| value={(config as WeaveConfig).endpoint} | |||
| onChange={handleConfigChange('endpoint')} | |||
| placeholder={'https://trace.wandb.ai/'} | |||
| /> | |||
| </> | |||
| )} | |||
| {type === TracingProvider.langSmith && ( | |||
| <> | |||
| <Field | |||
| @@ -263,7 +315,6 @@ const ProviderConfigModal: FC<Props> = ({ | |||
| /> | |||
| </> | |||
| )} | |||
| </div> | |||
| <div className='my-8 flex h-8 items-center justify-between'> | |||
| <a | |||
| @@ -7,7 +7,7 @@ import { | |||
| import { useTranslation } from 'react-i18next' | |||
| import { TracingProvider } from './type' | |||
| import cn from '@/utils/classnames' | |||
| import { LangfuseIconBig, LangsmithIconBig, OpikIconBig } from '@/app/components/base/icons/src/public/tracing' | |||
| import { LangfuseIconBig, LangsmithIconBig, OpikIconBig, WeaveIconBig } from '@/app/components/base/icons/src/public/tracing' | |||
| import { Eye as View } from '@/app/components/base/icons/src/vender/solid/general' | |||
| const I18N_PREFIX = 'app.tracing' | |||
| @@ -27,6 +27,7 @@ const getIcon = (type: TracingProvider) => { | |||
| [TracingProvider.langSmith]: LangsmithIconBig, | |||
| [TracingProvider.langfuse]: LangfuseIconBig, | |||
| [TracingProvider.opik]: OpikIconBig, | |||
| [TracingProvider.weave]: WeaveIconBig, | |||
| })[type] | |||
| } | |||
| @@ -2,6 +2,7 @@ export enum TracingProvider { | |||
| langSmith = 'langsmith', | |||
| langfuse = 'langfuse', | |||
| opik = 'opik', | |||
| weave = 'weave', | |||
| } | |||
| export type LangSmithConfig = { | |||
| @@ -22,3 +23,10 @@ export type OpikConfig = { | |||
| workspace: string | |||
| url: string | |||
| } | |||
| export type WeaveConfig = { | |||
| api_key: string | |||
| entity: string | |||
| project: string | |||
| endpoint: string | |||
| } | |||
| @@ -0,0 +1,16 @@ | |||
| // GENERATE BY script | |||
| // DON NOT EDIT IT MANUALLY | |||
| import * as React from 'react' | |||
| import data from './WeaveIcon.json' | |||
| import IconBase from '@/app/components/base/icons/IconBase' | |||
| import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase' | |||
| const Icon = React.forwardRef<React.MutableRefObject<SVGElement>, Omit<IconBaseProps, 'data'>>(( | |||
| props, | |||
| ref, | |||
| ) => <IconBase {...props} ref={ref} data={data as IconData} />) | |||
| Icon.displayName = 'WeaveIcon' | |||
| export default Icon | |||
| @@ -0,0 +1,16 @@ | |||
| // GENERATE BY script | |||
| // DON NOT EDIT IT MANUALLY | |||
| import * as React from 'react' | |||
| import data from './WeaveIconBig.json' | |||
| import IconBase from '@/app/components/base/icons/IconBase' | |||
| import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase' | |||
| const Icon = React.forwardRef<React.MutableRefObject<SVGElement>, Omit<IconBaseProps, 'data'>>(( | |||
| props, | |||
| ref, | |||
| ) => <IconBase {...props} ref={ref} data={data as IconData} />) | |||
| Icon.displayName = 'WeaveIconBig' | |||
| export default Icon | |||
| @@ -5,3 +5,5 @@ export { default as LangsmithIcon } from './LangsmithIcon' | |||
| export { default as OpikIconBig } from './OpikIconBig' | |||
| export { default as OpikIcon } from './OpikIcon' | |||
| export { default as TracingIcon } from './TracingIcon' | |||
| export { default as WeaveIconBig } from './WeaveIconBig' | |||
| export { default as WeaveIcon } from './WeaveIcon' | |||
| @@ -161,6 +161,10 @@ const translation = { | |||
| title: 'Opik', | |||
| description: 'Opik is an open-source platform for evaluating, testing, and monitoring LLM applications.', | |||
| }, | |||
| weave: { | |||
| title: 'Weave', | |||
| description: 'Weave is an open-source platform for evaluating, testing, and monitoring LLM applications.', | |||
| }, | |||
| inUse: 'In use', | |||
| configProvider: { | |||
| title: 'Config ', | |||
| @@ -1,5 +1,5 @@ | |||
| import type { LangFuseConfig, LangSmithConfig, OpikConfig, TracingProvider } from '@/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/type' | |||
| import type { App, AppMode, AppSSO, AppTemplate, SiteConfig } from '@/types/app' | |||
| import type { LangFuseConfig, LangSmithConfig, OpikConfig, TracingProvider, WeaveConfig } from '@/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/type' | |||
| import type { App, AppSSO, AppTemplate, SiteConfig } from '@/types/app' | |||
| import type { Dependency } from '@/app/components/plugins/types' | |||
| export enum DSLImportMode { | |||
| @@ -111,5 +111,5 @@ export type TracingStatus = { | |||
| export type TracingConfig = { | |||
| tracing_provider: TracingProvider | |||
| tracing_config: LangSmithConfig | LangFuseConfig | OpikConfig | |||
| tracing_config: LangSmithConfig | LangFuseConfig | OpikConfig | WeaveConfig | |||
| } | |||