mirror of
https://github.com/run-llama/notebookllama.git
synced 2026-07-01 22:14:04 -04:00
Merge pull request #3 from run-llama/clelia/add-observability
Adding observability dashboard
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
OPENAI_API_KEY="sk-***"
|
||||
LLAMACLOUD_API_KEY="llx-***"
|
||||
ELEVENLABS_API_KEY="sk_***"
|
||||
pgql_db="postgres"
|
||||
pgql_user="localhost"
|
||||
pgql_psw="admin"
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
name: GitHub Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v[0-9].[0-9]+.[0-9]+*"
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Create GitHub Release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
generateReleaseNotes: true
|
||||
@@ -40,6 +40,12 @@ uv run tools/create_llama_cloud_index.py
|
||||
|
||||
And you're ready to set up the app!
|
||||
|
||||
Launch Postgres and Jaeger:
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Run the **MCP** server:
|
||||
|
||||
```bash
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
name: instrumentation
|
||||
|
||||
services:
|
||||
jaeger:
|
||||
image: jaegertracing/all-in-one:latest
|
||||
ports:
|
||||
- 16686:16686
|
||||
- 4317:4317
|
||||
- 4318:4318
|
||||
- 9411:9411
|
||||
environment:
|
||||
- COLLECTOR_ZIPKIN_HOST_PORT=:9411
|
||||
|
||||
postgres:
|
||||
image: postgres
|
||||
ports:
|
||||
- 5432:5432
|
||||
environment:
|
||||
POSTGRES_DB: $pgql_db
|
||||
POSTGRES_USER: $pgql_user
|
||||
POSTGRES_PASSWORD: $pgql_psw
|
||||
volumes:
|
||||
- pgdata:/var/lib/postgresql/data
|
||||
|
||||
adminer:
|
||||
image: adminer
|
||||
ports:
|
||||
- "8080:8080"
|
||||
|
||||
volumes:
|
||||
pgdata:
|
||||
+6
-2
@@ -1,7 +1,7 @@
|
||||
[project]
|
||||
name = "notebooklm-clone"
|
||||
version = "0.1.0"
|
||||
description = "Add your description here"
|
||||
version = "0.2.0"
|
||||
description = "An OSS and LlamaCloud-backed alternative to NotebookLM"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.13"
|
||||
dependencies = [
|
||||
@@ -15,10 +15,14 @@ dependencies = [
|
||||
"llama-index-embeddings-openai>=0.3.1",
|
||||
"llama-index-indices-managed-llama-cloud>=0.6.11",
|
||||
"llama-index-llms-openai>=0.4.7",
|
||||
"llama-index-observability-otel>=0.1.1",
|
||||
"llama-index-tools-mcp>=0.2.5",
|
||||
"llama-index-workflows>=1.0.1",
|
||||
"mypy>=1.16.1",
|
||||
"opentelemetry-exporter-otlp-proto-http>=1.34.1",
|
||||
"plotly>=6.2.0",
|
||||
"pre-commit>=4.2.0",
|
||||
"psycopg2-binary>=2.9.10",
|
||||
"pydub>=0.25.1",
|
||||
"pytest>=8.4.1",
|
||||
"pytest-asyncio>=1.0.0",
|
||||
|
||||
@@ -3,12 +3,36 @@ import io
|
||||
import os
|
||||
import asyncio
|
||||
import tempfile as temp
|
||||
from dotenv import load_dotenv
|
||||
import time
|
||||
import streamlit.components.v1 as components
|
||||
|
||||
from pathlib import Path
|
||||
from audio import PODCAST_GEN
|
||||
from typing import Tuple
|
||||
from workflow import NotebookLMWorkflow, FileInputEvent, NotebookOutputEvent
|
||||
from instrumentation import OtelTracesSqlEngine
|
||||
from llama_index.observability.otel import LlamaIndexOpenTelemetry
|
||||
from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
|
||||
OTLPSpanExporter,
|
||||
)
|
||||
|
||||
load_dotenv()
|
||||
|
||||
# define a custom span exporter
|
||||
span_exporter = OTLPSpanExporter("http://0.0.0.0:4318/v1/traces")
|
||||
|
||||
# initialize the instrumentation object
|
||||
instrumentor = LlamaIndexOpenTelemetry(
|
||||
service_name_or_resource="agent.traces",
|
||||
span_exporter=span_exporter,
|
||||
debug=True,
|
||||
)
|
||||
sql_engine = OtelTracesSqlEngine(
|
||||
engine_url=f"postgresql+psycopg2://{os.getenv('pgql_user')}:{os.getenv('pgql_psw')}@localhost:5432/{os.getenv('pgql_db')}",
|
||||
table_name="agent_traces",
|
||||
service_name="agent.traces",
|
||||
)
|
||||
|
||||
WF = NotebookLMWorkflow(timeout=600)
|
||||
|
||||
@@ -24,6 +48,7 @@ async def run_workflow(file: io.BytesIO) -> Tuple[str, str, str, str, str]:
|
||||
content = file.getvalue()
|
||||
with open(fl.name, "wb") as f:
|
||||
f.write(content)
|
||||
st_time = int(time.time() * 1000000)
|
||||
ev = FileInputEvent(file=fl.name)
|
||||
result: NotebookOutputEvent = await WF.run(start_event=ev)
|
||||
q_and_a = ""
|
||||
@@ -34,7 +59,9 @@ async def run_workflow(file: io.BytesIO) -> Tuple[str, str, str, str, str]:
|
||||
mind_map = result.mind_map
|
||||
if Path(mind_map).is_file():
|
||||
mind_map = read_html_file(mind_map)
|
||||
os.remove(mind_map)
|
||||
os.remove(result.mind_map)
|
||||
end_time = int(time.time() * 1000000)
|
||||
sql_engine.to_sql_database(start_time=st_time, end_time=end_time)
|
||||
return result.md_content, result.summary, q_and_a, bullet_points, mind_map
|
||||
|
||||
|
||||
@@ -138,3 +165,6 @@ if file_input is not None:
|
||||
|
||||
else:
|
||||
st.info("Please upload a PDF file to get started.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
instrumentor.start_registering()
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
import requests
|
||||
import time
|
||||
import csv
|
||||
import pandas as pd
|
||||
import tempfile as temp
|
||||
import os
|
||||
|
||||
from sqlalchemy import Engine, create_engine, Connection, Result
|
||||
from typing import Optional, Dict, Any, List, Literal, Union, cast
|
||||
|
||||
|
||||
class OtelTracesSqlEngine:
|
||||
def __init__(
|
||||
self,
|
||||
engine: Optional[Engine] = None,
|
||||
engine_url: Optional[str] = None,
|
||||
table_name: Optional[str] = None,
|
||||
service_name: Optional[str] = None,
|
||||
):
|
||||
self.service_name: str = service_name or "service"
|
||||
self.table_name: str = table_name or "otel_traces"
|
||||
self._connection: Optional[Connection] = None
|
||||
if engine:
|
||||
self._engine: Engine = engine
|
||||
elif engine_url:
|
||||
self._engine = create_engine(url=engine_url)
|
||||
else:
|
||||
raise ValueError("One of engine or engine_setup_kwargs must be set")
|
||||
|
||||
def _connect(self) -> None:
|
||||
self._connection = self._engine.connect()
|
||||
|
||||
def _export(
|
||||
self,
|
||||
start_time: Optional[int] = None,
|
||||
end_time: Optional[int] = None,
|
||||
limit: Optional[int] = None,
|
||||
) -> Dict[str, Any]:
|
||||
url = "http://localhost:16686/api/traces"
|
||||
params = {
|
||||
"service": self.service_name,
|
||||
"start": start_time
|
||||
or int(time.time() * 1000000) - (24 * 60 * 60 * 1000000),
|
||||
"end": end_time or int(time.time() * 1000000),
|
||||
"limit": limit or 1000,
|
||||
}
|
||||
response = requests.get(url, params=params)
|
||||
print(response.json())
|
||||
return response.json()
|
||||
|
||||
def _to_pandas(self, data: Dict[str, Any]) -> pd.DataFrame:
|
||||
rows: List[Dict[str, Any]] = []
|
||||
# Loop over each trace
|
||||
for trace in data.get("data", []):
|
||||
trace_id = trace.get("traceID")
|
||||
service_map = {
|
||||
pid: proc.get("serviceName")
|
||||
for pid, proc in trace.get("processes", {}).items()
|
||||
}
|
||||
|
||||
for span in trace.get("spans", []):
|
||||
span_id = span.get("spanID")
|
||||
operation = span.get("operationName")
|
||||
start = span.get("startTime")
|
||||
duration = span.get("duration")
|
||||
process_id = span.get("processID")
|
||||
service = service_map.get(process_id, "")
|
||||
status = next(
|
||||
(
|
||||
tag.get("value")
|
||||
for tag in span.get("tags", [])
|
||||
if tag.get("key") == "otel.status_code"
|
||||
),
|
||||
"",
|
||||
)
|
||||
parent_span_id = None
|
||||
if span.get("references"):
|
||||
parent_span_id = span["references"][0].get("spanID")
|
||||
|
||||
rows.append(
|
||||
{
|
||||
"trace_id": trace_id,
|
||||
"span_id": span_id,
|
||||
"parent_span_id": parent_span_id,
|
||||
"operation_name": operation,
|
||||
"start_time": start,
|
||||
"duration": duration,
|
||||
"status_code": status,
|
||||
"service_name": service,
|
||||
}
|
||||
)
|
||||
|
||||
# Define the CSV header
|
||||
fieldnames = [
|
||||
"trace_id",
|
||||
"span_id",
|
||||
"parent_span_id",
|
||||
"operation_name",
|
||||
"start_time",
|
||||
"duration",
|
||||
"status_code",
|
||||
"service_name",
|
||||
]
|
||||
|
||||
fl = temp.NamedTemporaryFile(suffix=".csv", delete=False, delete_on_close=False)
|
||||
# Write to CSV
|
||||
with open(fl.name, "w", newline="") as csvfile:
|
||||
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
|
||||
writer.writeheader()
|
||||
writer.writerows(rows)
|
||||
|
||||
df = pd.read_csv(fl)
|
||||
os.remove(fl.name)
|
||||
return df
|
||||
|
||||
def _to_sql(
|
||||
self,
|
||||
dataframe: pd.DataFrame,
|
||||
if_exists_policy: Optional[Literal["fail", "replace", "append"]] = None,
|
||||
) -> None:
|
||||
if not self._connection:
|
||||
self._connect()
|
||||
dataframe.to_sql(
|
||||
name=self.table_name,
|
||||
con=self._connection,
|
||||
if_exists=if_exists_policy or "append",
|
||||
)
|
||||
|
||||
def to_sql_database(
|
||||
self,
|
||||
start_time: Optional[int] = None,
|
||||
end_time: Optional[int] = None,
|
||||
limit: Optional[int] = None,
|
||||
if_exists_policy: Optional[Literal["fail", "replace", "append"]] = None,
|
||||
) -> None:
|
||||
data = self._export(start_time=start_time, end_time=end_time, limit=limit)
|
||||
df = self._to_pandas(data=data)
|
||||
self._to_sql(dataframe=df, if_exists_policy=if_exists_policy)
|
||||
|
||||
def execute(
|
||||
self,
|
||||
statement: Any,
|
||||
parameters: Optional[Any] = None,
|
||||
execution_options: Optional[Any] = None,
|
||||
return_pandas: bool = False,
|
||||
) -> Union[Result, pd.DataFrame]:
|
||||
if not self._connection:
|
||||
self._connect()
|
||||
if not return_pandas:
|
||||
self._connection = cast(Connection, self._connection)
|
||||
return self._connection.execute(
|
||||
statement=statement,
|
||||
parameters=parameters,
|
||||
execution_options=execution_options,
|
||||
)
|
||||
return pd.read_sql(sql=statement, con=self._connection)
|
||||
|
||||
def to_pandas(
|
||||
self,
|
||||
) -> pd.DataFrame:
|
||||
if not self._connection:
|
||||
self._connect()
|
||||
return pd.read_sql_table(table_name=self.table_name, con=self._connection)
|
||||
|
||||
def disconnect(self) -> None:
|
||||
if not self._connection:
|
||||
raise ValueError("Engine was never connected!")
|
||||
self._engine.dispose(close=True)
|
||||
@@ -0,0 +1,169 @@
|
||||
import sys
|
||||
import os
|
||||
import pandas as pd
|
||||
import streamlit as st
|
||||
import plotly.express as px
|
||||
import plotly.graph_objects as go
|
||||
|
||||
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
||||
|
||||
from dotenv import load_dotenv
|
||||
from instrumentation import OtelTracesSqlEngine
|
||||
from sqlalchemy import text
|
||||
|
||||
load_dotenv()
|
||||
|
||||
sql_engine = OtelTracesSqlEngine(
|
||||
engine_url=f"postgresql+psycopg2://{os.getenv('pgql_user')}:{os.getenv('pgql_psw')}@localhost:5432/{os.getenv('pgql_db')}",
|
||||
table_name="agent_traces",
|
||||
service_name="agent.traces",
|
||||
)
|
||||
|
||||
|
||||
def display_sql() -> pd.DataFrame:
|
||||
query = """CREATE TABLE IF NOT EXISTS agent_traces (
|
||||
trace_id TEXT NOT NULL,
|
||||
span_id TEXT NOT NULL,
|
||||
parent_span_id TEXT NULL,
|
||||
operation_name TEXT NOT NULL,
|
||||
start_time BIGINT NOT NULL,
|
||||
duration INTEGER NOT NULL,
|
||||
status_code TEXT NOT NULL,
|
||||
service_name TEXT NOT NULL
|
||||
);"""
|
||||
sql_engine.execute(text(query))
|
||||
return sql_engine.to_pandas()
|
||||
|
||||
|
||||
def filter_traces(sql_query: str):
|
||||
df = sql_engine.execute(text(sql_query), return_pandas=True)
|
||||
return df
|
||||
|
||||
|
||||
def create_latency_chart(df: pd.DataFrame):
|
||||
"""Create a line chart showing latency (duration) over time"""
|
||||
if df.empty:
|
||||
st.warning("No data available for latency chart")
|
||||
return
|
||||
|
||||
# Convert start_time from nanoseconds to datetime
|
||||
df_chart = df.copy()
|
||||
progressive_count = list(range(0, len(df_chart["start_time"])))
|
||||
df_chart["progressive_count"] = progressive_count
|
||||
|
||||
fig = px.line(
|
||||
df_chart,
|
||||
x="progressive_count",
|
||||
y="duration",
|
||||
title="Latency Overview",
|
||||
labels={"duration": "Duration (ns)", "timestamp": "Time"},
|
||||
hover_data=["operation_name", "status_code"],
|
||||
)
|
||||
|
||||
fig.update_layout(
|
||||
xaxis_title="Time", yaxis_title="Duration (nanoseconds)", hovermode="x unified"
|
||||
)
|
||||
|
||||
st.plotly_chart(fig)
|
||||
|
||||
|
||||
def create_status_pie_chart(df: pd.DataFrame):
|
||||
"""Create a pie chart showing status code distribution"""
|
||||
if df.empty:
|
||||
st.warning("No data available for status code chart")
|
||||
return
|
||||
|
||||
# Count status codes
|
||||
status_counts = df["status_code"].value_counts()
|
||||
|
||||
# Map common status codes to more readable labels
|
||||
status_labels = {
|
||||
"OK": "OK",
|
||||
"ERROR": "ERROR",
|
||||
"UNSET": "UNSET",
|
||||
"200": "OK (200)",
|
||||
"500": "ERROR (500)",
|
||||
"404": "ERROR (404)",
|
||||
}
|
||||
|
||||
# Create labels and values for the pie chart
|
||||
labels = [status_labels.get(status, status) for status in status_counts.index]
|
||||
values = status_counts.values
|
||||
|
||||
# Define colors
|
||||
colors = []
|
||||
for status in status_counts.index:
|
||||
if status in ["OK", "200"]:
|
||||
colors.append("#28a745") # Green for OK
|
||||
elif status in ["ERROR", "500", "404"]:
|
||||
colors.append("#dc3545") # Red for ERROR
|
||||
else:
|
||||
colors.append("#6c757d") # Gray for others
|
||||
|
||||
fig = go.Figure(
|
||||
data=[go.Pie(labels=labels, values=values, hole=0.3, marker_colors=colors)]
|
||||
)
|
||||
|
||||
fig.update_layout(
|
||||
title="Status Code Distribution",
|
||||
annotations=[dict(text="Status", x=0.5, y=0.5, font_size=20, showarrow=False)],
|
||||
)
|
||||
|
||||
st.plotly_chart(fig)
|
||||
|
||||
|
||||
# Streamlit UI
|
||||
st.set_page_config(page_title="NotebookLlaMa - Observability Dashboard", page_icon="🔍")
|
||||
|
||||
st.sidebar.header("Observability Dashboard🔍")
|
||||
st.sidebar.info("To switch to the other pages, select them from above!🔺")
|
||||
st.markdown("---")
|
||||
st.markdown("## NotebookLlaMa - Observability Dashboard🔍")
|
||||
|
||||
# Get the data
|
||||
df_data = display_sql()
|
||||
|
||||
# Charts section
|
||||
st.markdown("## 📊 Analytics Overview")
|
||||
|
||||
if not df_data.empty:
|
||||
col1, col2 = st.columns(2)
|
||||
|
||||
with col1:
|
||||
create_latency_chart(df_data)
|
||||
|
||||
with col2:
|
||||
create_status_pie_chart(df_data)
|
||||
else:
|
||||
st.info("No trace data available yet. Charts will appear once data is collected.")
|
||||
|
||||
st.markdown("---")
|
||||
|
||||
# SQL Query section
|
||||
st.markdown("### SQL Query")
|
||||
sql_query = st.text_input(label="")
|
||||
|
||||
st.markdown("## Traces Table")
|
||||
dataframe = st.dataframe(data=df_data)
|
||||
|
||||
if st.button("Run SQL query", type="primary"):
|
||||
if sql_query.strip():
|
||||
try:
|
||||
filtered_df = filter_traces(sql_query=sql_query)
|
||||
st.markdown("### Query Results")
|
||||
dataframe = st.dataframe(data=filtered_df)
|
||||
|
||||
# Update charts with filtered data
|
||||
if not filtered_df.empty:
|
||||
st.markdown("### Updated Charts")
|
||||
col1, col2 = st.columns(2)
|
||||
|
||||
with col1:
|
||||
create_latency_chart(filtered_df)
|
||||
|
||||
with col2:
|
||||
create_status_pie_chart(filtered_df)
|
||||
except Exception as e:
|
||||
st.error(f"Error executing query: {str(e)}")
|
||||
else:
|
||||
st.warning("Please enter a SQL query")
|
||||
@@ -0,0 +1,84 @@
|
||||
import socket
|
||||
import pytest
|
||||
import pandas as pd
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from src.notebooklm_clone.instrumentation import OtelTracesSqlEngine
|
||||
from sqlalchemy import text
|
||||
|
||||
ENV = load_dotenv()
|
||||
|
||||
|
||||
def is_port_open(host: str, port: int, timeout: float = 2.0) -> bool:
|
||||
"""Check if a TCP port is open on a given host."""
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
||||
sock.settimeout(timeout)
|
||||
result = sock.connect_ex((host, port))
|
||||
return result == 0
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def otel_data() -> pd.DataFrame:
|
||||
return pd.DataFrame(
|
||||
{
|
||||
"trace_id": ["abc123", "abc123", "def456"],
|
||||
"span_id": ["span1", "span2", "span3"],
|
||||
"parent_span_id": [None, "span1", "span2"],
|
||||
"operation_name": [
|
||||
"ServiceA.handle_request",
|
||||
"ServiceA.query_db",
|
||||
"ServiceB.send_email",
|
||||
],
|
||||
"start_time": [1750618321000000, 1750618321000100, 1750618321000200],
|
||||
"duration": [150, 300, 500],
|
||||
"status_code": ["OK", "OK", "ERROR"],
|
||||
"service_name": ["service-a", "service-a", "service-b"],
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
condition=not is_port_open(host="localhost", port=5432) and not ENV,
|
||||
reason="Either Postgres is currently unavailable or you did not set any env variables in a .env file",
|
||||
)
|
||||
def test_engine(otel_data: pd.DataFrame) -> None:
|
||||
engine_url = f"postgresql+psycopg2://{os.getenv('pgql_user')}:{os.getenv('pgql_psw')}@localhost:5432/{os.getenv('pgql_db')}"
|
||||
sql_engine = OtelTracesSqlEngine(engine_url=engine_url, table_name="test")
|
||||
res = sql_engine.execute(text("DROP TABLE IF EXISTS test;"))
|
||||
res.close()
|
||||
sql_engine._to_sql(dataframe=otel_data)
|
||||
res1 = sql_engine.execute(
|
||||
text(
|
||||
"SELECT span_id, operation_name, duration FROM test WHERE status_code = 'ERROR'"
|
||||
)
|
||||
)
|
||||
res2 = sql_engine.execute(
|
||||
text(
|
||||
"SELECT service_name, AVG(duration) AS avg_duration FROM test GROUP BY service_name;"
|
||||
)
|
||||
)
|
||||
res1_data = res1.fetchall()
|
||||
res2_data = res2.fetchall()
|
||||
|
||||
# Compare just the values
|
||||
assert len(res1_data) == 1
|
||||
assert res1_data[0].span_id == "span3"
|
||||
assert res1_data[0].operation_name == "ServiceB.send_email"
|
||||
assert res1_data[0].duration == 500
|
||||
|
||||
assert len(res2_data) == 2
|
||||
# Sort by service_name for consistent comparison
|
||||
res2_sorted = sorted(res2_data, key=lambda x: x.service_name)
|
||||
assert res2_sorted[0].service_name == "service-a"
|
||||
assert res2_sorted[0].avg_duration == 225.0
|
||||
assert res2_sorted[1].service_name == "service-b"
|
||||
assert res2_sorted[1].avg_duration == 500.0
|
||||
assert isinstance(sql_engine.to_pandas(), pd.DataFrame)
|
||||
res3 = sql_engine.execute(
|
||||
text(
|
||||
"SELECT service_name, AVG(duration) AS avg_duration FROM test GROUP BY service_name;"
|
||||
),
|
||||
return_pandas=True,
|
||||
)
|
||||
assert isinstance(res3, pd.DataFrame)
|
||||
@@ -544,6 +544,18 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/1d/9a/4114a9057db2f1462d5c8f8390ab7383925fe1ac012eaa42402ad65c2963/GitPython-3.1.44-py3-none-any.whl", hash = "sha256:9e0e10cda9bed1ee64bc9a6de50e7e38a9c9943241cd7f585f6df3ed28011110", size = 207599, upload-time = "2025-01-02T07:32:40.731Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "googleapis-common-protos"
|
||||
version = "1.70.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "protobuf" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/39/24/33db22342cf4a2ea27c9955e6713140fedd51e8b141b5ce5260897020f1a/googleapis_common_protos-1.70.0.tar.gz", hash = "sha256:0e1b44e0ea153e6594f9f394fef15193a68aaaea2d843f83e2742717ca753257", size = 145903, upload-time = "2025-04-14T10:17:02.924Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/86/f1/62a193f0227cf15a920390abe675f386dec35f7ae3ffe6da582d3ade42c7/googleapis_common_protos-1.70.0-py3-none-any.whl", hash = "sha256:b8bfcca8c25a2bb253e0e0b0adaf8c00773e5e6af6fd92397576680b807e0fd8", size = 294530, upload-time = "2025-04-14T10:17:01.271Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "greenlet"
|
||||
version = "3.2.3"
|
||||
@@ -644,6 +656,18 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "importlib-metadata"
|
||||
version = "8.7.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "zipp" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/76/66/650a33bd90f786193e4de4b3ad86ea60b53c89b669a5c7be931fac31cdb0/importlib_metadata-8.7.0.tar.gz", hash = "sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000", size = 56641, upload-time = "2025-04-27T15:29:01.736Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/20/b0/36bd937216ec521246249be3bf9855081de4c5e06a0c9b4219dbeda50373/importlib_metadata-8.7.0-py3-none-any.whl", hash = "sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd", size = 27656, upload-time = "2025-04-27T15:29:00.214Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iniconfig"
|
||||
version = "2.1.0"
|
||||
@@ -912,6 +936,22 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/61/e9/391926dad180ced6bb37a62edddb8483fbecde411239bd5e726841bb77b4/llama_index_llms_openai-0.4.7-py3-none-any.whl", hash = "sha256:3b8d9d3c1bcadc2cff09724de70f074f43eafd5b7048a91247c9a41b7cd6216d", size = 25365, upload-time = "2025-06-16T03:38:45.72Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "llama-index-observability-otel"
|
||||
version = "0.1.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "llama-index-core" },
|
||||
{ name = "opentelemetry-api" },
|
||||
{ name = "opentelemetry-sdk" },
|
||||
{ name = "opentelemetry-semantic-conventions" },
|
||||
{ name = "termcolor" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/10/f2/22c28678fad040c579b9280769ffb79dc5c60d061b8a4b2e0d764787ceb0/llama_index_observability_otel-0.1.1.tar.gz", hash = "sha256:a3f25d0105225d609a198506ecb27c24e420ad28871cd8f2227ee27e55765eda", size = 6391, upload-time = "2025-05-29T04:24:11.04Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ab/3f/14796f0e0f975378e913240041bb3658216432eceb34d9b02eb39c4dd604/llama_index_observability_otel-0.1.1-py3-none-any.whl", hash = "sha256:d70ccd207c1ad6f31e6697cd8bca093e170c8589042beef17741fd56cef9f115", size = 6311, upload-time = "2025-05-29T04:24:09.826Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "llama-index-tools-mcp"
|
||||
version = "0.2.5"
|
||||
@@ -1155,7 +1195,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "notebooklm-clone"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
source = { virtual = "." }
|
||||
dependencies = [
|
||||
{ name = "audioop-lts" },
|
||||
@@ -1168,10 +1208,14 @@ dependencies = [
|
||||
{ name = "llama-index-embeddings-openai" },
|
||||
{ name = "llama-index-indices-managed-llama-cloud" },
|
||||
{ name = "llama-index-llms-openai" },
|
||||
{ name = "llama-index-observability-otel" },
|
||||
{ name = "llama-index-tools-mcp" },
|
||||
{ name = "llama-index-workflows" },
|
||||
{ name = "mypy" },
|
||||
{ name = "opentelemetry-exporter-otlp-proto-http" },
|
||||
{ name = "plotly" },
|
||||
{ name = "pre-commit" },
|
||||
{ name = "psycopg2-binary" },
|
||||
{ name = "pydub" },
|
||||
{ name = "pytest" },
|
||||
{ name = "pytest-asyncio" },
|
||||
@@ -1192,10 +1236,14 @@ requires-dist = [
|
||||
{ name = "llama-index-embeddings-openai", specifier = ">=0.3.1" },
|
||||
{ name = "llama-index-indices-managed-llama-cloud", specifier = ">=0.6.11" },
|
||||
{ name = "llama-index-llms-openai", specifier = ">=0.4.7" },
|
||||
{ name = "llama-index-observability-otel", specifier = ">=0.1.1" },
|
||||
{ name = "llama-index-tools-mcp", specifier = ">=0.2.5" },
|
||||
{ name = "llama-index-workflows", specifier = ">=1.0.1" },
|
||||
{ name = "mypy", specifier = ">=1.16.1" },
|
||||
{ name = "opentelemetry-exporter-otlp-proto-http", specifier = ">=1.34.1" },
|
||||
{ name = "plotly", specifier = ">=6.2.0" },
|
||||
{ name = "pre-commit", specifier = ">=4.2.0" },
|
||||
{ name = "psycopg2-binary", specifier = ">=2.9.10" },
|
||||
{ name = "pydub", specifier = ">=0.25.1" },
|
||||
{ name = "pytest", specifier = ">=8.4.1" },
|
||||
{ name = "pytest-asyncio", specifier = ">=1.0.0" },
|
||||
@@ -1265,6 +1313,88 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/12/cf/03675d8bd8ecbf4445504d8071adab19f5f993676795708e36402ab38263/openapi_pydantic-0.5.1-py3-none-any.whl", hash = "sha256:a3a09ef4586f5bd760a8df7f43028b60cafb6d9f61de2acba9574766255ab146", size = 96381, upload-time = "2025-01-08T19:29:25.275Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-api"
|
||||
version = "1.34.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "importlib-metadata" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/4d/5e/94a8cb759e4e409022229418294e098ca7feca00eb3c467bb20cbd329bda/opentelemetry_api-1.34.1.tar.gz", hash = "sha256:64f0bd06d42824843731d05beea88d4d4b6ae59f9fe347ff7dfa2cc14233bbb3", size = 64987, upload-time = "2025-06-10T08:55:19.818Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a5/3a/2ba85557e8dc024c0842ad22c570418dc02c36cbd1ab4b832a93edf071b8/opentelemetry_api-1.34.1-py3-none-any.whl", hash = "sha256:b7df4cb0830d5a6c29ad0c0691dbae874d8daefa934b8b1d642de48323d32a8c", size = 65767, upload-time = "2025-06-10T08:54:56.717Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-exporter-otlp-proto-common"
|
||||
version = "1.34.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "opentelemetry-proto" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/86/f0/ff235936ee40db93360233b62da932d4fd9e8d103cd090c6bcb9afaf5f01/opentelemetry_exporter_otlp_proto_common-1.34.1.tar.gz", hash = "sha256:b59a20a927facd5eac06edaf87a07e49f9e4a13db487b7d8a52b37cb87710f8b", size = 20817, upload-time = "2025-06-10T08:55:22.55Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/72/e8/8b292a11cc8d8d87ec0c4089ae21b6a58af49ca2e51fa916435bc922fdc7/opentelemetry_exporter_otlp_proto_common-1.34.1-py3-none-any.whl", hash = "sha256:8e2019284bf24d3deebbb6c59c71e6eef3307cd88eff8c633e061abba33f7e87", size = 18834, upload-time = "2025-06-10T08:55:00.806Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-exporter-otlp-proto-http"
|
||||
version = "1.34.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "googleapis-common-protos" },
|
||||
{ name = "opentelemetry-api" },
|
||||
{ name = "opentelemetry-exporter-otlp-proto-common" },
|
||||
{ name = "opentelemetry-proto" },
|
||||
{ name = "opentelemetry-sdk" },
|
||||
{ name = "requests" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/19/8f/954bc725961cbe425a749d55c0ba1df46832a5999eae764d1a7349ac1c29/opentelemetry_exporter_otlp_proto_http-1.34.1.tar.gz", hash = "sha256:aaac36fdce46a8191e604dcf632e1f9380c7d5b356b27b3e0edb5610d9be28ad", size = 15351, upload-time = "2025-06-10T08:55:24.657Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/79/54/b05251c04e30c1ac70cf4a7c5653c085dfcf2c8b98af71661d6a252adc39/opentelemetry_exporter_otlp_proto_http-1.34.1-py3-none-any.whl", hash = "sha256:5251f00ca85872ce50d871f6d3cc89fe203b94c3c14c964bbdc3883366c705d8", size = 17744, upload-time = "2025-06-10T08:55:03.802Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-proto"
|
||||
version = "1.34.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "protobuf" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/66/b3/c3158dd012463bb7c0eb7304a85a6f63baeeb5b4c93a53845cf89f848c7e/opentelemetry_proto-1.34.1.tar.gz", hash = "sha256:16286214e405c211fc774187f3e4bbb1351290b8dfb88e8948af209ce85b719e", size = 34344, upload-time = "2025-06-10T08:55:32.25Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/28/ab/4591bfa54e946350ce8b3f28e5c658fe9785e7cd11e9c11b1671a867822b/opentelemetry_proto-1.34.1-py3-none-any.whl", hash = "sha256:eb4bb5ac27f2562df2d6857fc557b3a481b5e298bc04f94cc68041f00cebcbd2", size = 55692, upload-time = "2025-06-10T08:55:14.904Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-sdk"
|
||||
version = "1.34.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "opentelemetry-api" },
|
||||
{ name = "opentelemetry-semantic-conventions" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/6f/41/fe20f9036433da8e0fcef568984da4c1d1c771fa072ecd1a4d98779dccdd/opentelemetry_sdk-1.34.1.tar.gz", hash = "sha256:8091db0d763fcd6098d4781bbc80ff0971f94e260739aa6afe6fd379cdf3aa4d", size = 159441, upload-time = "2025-06-10T08:55:33.028Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/07/1b/def4fe6aa73f483cabf4c748f4c25070d5f7604dcc8b52e962983491b29e/opentelemetry_sdk-1.34.1-py3-none-any.whl", hash = "sha256:308effad4059562f1d92163c61c8141df649da24ce361827812c40abb2a1e96e", size = 118477, upload-time = "2025-06-10T08:55:16.02Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-semantic-conventions"
|
||||
version = "0.55b1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "opentelemetry-api" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/5d/f0/f33458486da911f47c4aa6db9bda308bb80f3236c111bf848bd870c16b16/opentelemetry_semantic_conventions-0.55b1.tar.gz", hash = "sha256:ef95b1f009159c28d7a7849f5cbc71c4c34c845bb514d66adfdf1b3fff3598b3", size = 119829, upload-time = "2025-06-10T08:55:33.881Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/1a/89/267b0af1b1d0ba828f0e60642b6a5116ac1fd917cde7fc02821627029bd1/opentelemetry_semantic_conventions-0.55b1-py3-none-any.whl", hash = "sha256:5da81dfdf7d52e3d37f8fe88d5e771e191de924cfff5f550ab0b8f7b2409baed", size = 196223, upload-time = "2025-06-10T08:55:17.638Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "25.0"
|
||||
@@ -1370,6 +1500,19 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/fe/39/979e8e21520d4e47a0bbe349e2713c0aac6f3d853d0e5b34d76206c439aa/platformdirs-4.3.8-py3-none-any.whl", hash = "sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4", size = 18567, upload-time = "2025-05-07T22:47:40.376Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "plotly"
|
||||
version = "6.2.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "narwhals" },
|
||||
{ name = "packaging" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/6e/5c/0efc297df362b88b74957a230af61cd6929f531f72f48063e8408702ffba/plotly-6.2.0.tar.gz", hash = "sha256:9dfa23c328000f16c928beb68927444c1ab9eae837d1fe648dbcda5360c7953d", size = 6801941, upload-time = "2025-06-26T16:20:45.765Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ed/20/f2b7ac96a91cc5f70d81320adad24cc41bf52013508d649b1481db225780/plotly-6.2.0-py3-none-any.whl", hash = "sha256:32c444d4c940887219cb80738317040363deefdfee4f354498cc0b6dab8978bd", size = 9635469, upload-time = "2025-06-26T16:20:40.76Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pluggy"
|
||||
version = "1.6.0"
|
||||
@@ -1450,16 +1593,35 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "protobuf"
|
||||
version = "6.31.1"
|
||||
version = "5.29.5"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/52/f3/b9655a711b32c19720253f6f06326faf90580834e2e83f840472d752bc8b/protobuf-6.31.1.tar.gz", hash = "sha256:d8cac4c982f0b957a4dc73a80e2ea24fab08e679c0de9deb835f4a12d69aca9a", size = 441797, upload-time = "2025-05-28T19:25:54.947Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/43/29/d09e70352e4e88c9c7a198d5645d7277811448d76c23b00345670f7c8a38/protobuf-5.29.5.tar.gz", hash = "sha256:bc1463bafd4b0929216c35f437a8e28731a2b7fe3d98bb77a600efced5a15c84", size = 425226, upload-time = "2025-05-28T23:51:59.82Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/f3/6f/6ab8e4bf962fd5570d3deaa2d5c38f0a363f57b4501047b5ebeb83ab1125/protobuf-6.31.1-cp310-abi3-win32.whl", hash = "sha256:7fa17d5a29c2e04b7d90e5e32388b8bfd0e7107cd8e616feef7ed3fa6bdab5c9", size = 423603, upload-time = "2025-05-28T19:25:41.198Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/44/3a/b15c4347dd4bf3a1b0ee882f384623e2063bb5cf9fa9d57990a4f7df2fb6/protobuf-6.31.1-cp310-abi3-win_amd64.whl", hash = "sha256:426f59d2964864a1a366254fa703b8632dcec0790d8862d30034d8245e1cd447", size = 435283, upload-time = "2025-05-28T19:25:44.275Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6a/c9/b9689a2a250264a84e66c46d8862ba788ee7a641cdca39bccf64f59284b7/protobuf-6.31.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:6f1227473dc43d44ed644425268eb7c2e488ae245d51c6866d19fe158e207402", size = 425604, upload-time = "2025-05-28T19:25:45.702Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/76/a1/7a5a94032c83375e4fe7e7f56e3976ea6ac90c5e85fac8576409e25c39c3/protobuf-6.31.1-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:a40fc12b84c154884d7d4c4ebd675d5b3b5283e155f324049ae396b95ddebc39", size = 322115, upload-time = "2025-05-28T19:25:47.128Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fa/b1/b59d405d64d31999244643d88c45c8241c58f17cc887e73bcb90602327f8/protobuf-6.31.1-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:4ee898bf66f7a8b0bd21bce523814e6fbd8c6add948045ce958b73af7e8878c6", size = 321070, upload-time = "2025-05-28T19:25:50.036Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f7/af/ab3c51ab7507a7325e98ffe691d9495ee3d3aa5f589afad65ec920d39821/protobuf-6.31.1-py3-none-any.whl", hash = "sha256:720a6c7e6b77288b85063569baae8536671b39f15cc22037ec7045658d80489e", size = 168724, upload-time = "2025-05-28T19:25:53.926Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5f/11/6e40e9fc5bba02988a214c07cf324595789ca7820160bfd1f8be96e48539/protobuf-5.29.5-cp310-abi3-win32.whl", hash = "sha256:3f1c6468a2cfd102ff4703976138844f78ebd1fb45f49011afc5139e9e283079", size = 422963, upload-time = "2025-05-28T23:51:41.204Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/81/7f/73cefb093e1a2a7c3ffd839e6f9fcafb7a427d300c7f8aef9c64405d8ac6/protobuf-5.29.5-cp310-abi3-win_amd64.whl", hash = "sha256:3f76e3a3675b4a4d867b52e4a5f5b78a2ef9565549d4037e06cf7b0942b1d3fc", size = 434818, upload-time = "2025-05-28T23:51:44.297Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/dd/73/10e1661c21f139f2c6ad9b23040ff36fee624310dc28fba20d33fdae124c/protobuf-5.29.5-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e38c5add5a311f2a6eb0340716ef9b039c1dfa428b28f25a7838ac329204a671", size = 418091, upload-time = "2025-05-28T23:51:45.907Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6c/04/98f6f8cf5b07ab1294c13f34b4e69b3722bb609c5b701d6c169828f9f8aa/protobuf-5.29.5-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:fa18533a299d7ab6c55a238bf8629311439995f2e7eca5caaff08663606e9015", size = 319824, upload-time = "2025-05-28T23:51:47.545Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/85/e4/07c80521879c2d15f321465ac24c70efe2381378c00bf5e56a0f4fbac8cd/protobuf-5.29.5-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:63848923da3325e1bf7e9003d680ce6e14b07e55d0473253a690c3a8b8fd6e61", size = 319942, upload-time = "2025-05-28T23:51:49.11Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7e/cc/7e77861000a0691aeea8f4566e5d3aa716f2b1dece4a24439437e41d3d25/protobuf-5.29.5-py3-none-any.whl", hash = "sha256:6cf42630262c59b2d8de33954443d94b746c952b01434fc58a417fdbd2e84bd5", size = 172823, upload-time = "2025-05-28T23:51:58.157Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "psycopg2-binary"
|
||||
version = "2.9.10"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/cb/0e/bdc8274dc0585090b4e3432267d7be4dfbfd8971c0fa59167c711105a6bf/psycopg2-binary-2.9.10.tar.gz", hash = "sha256:4b3df0e6990aa98acda57d983942eff13d824135fe2250e6522edaa782a06de2", size = 385764, upload-time = "2024-10-16T11:24:58.126Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/3e/30/d41d3ba765609c0763505d565c4d12d8f3c79793f0d0f044ff5a28bf395b/psycopg2_binary-2.9.10-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:26540d4a9a4e2b096f1ff9cce51253d0504dca5a85872c7f7be23be5a53eb18d", size = 3044699, upload-time = "2024-10-16T11:21:42.841Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/35/44/257ddadec7ef04536ba71af6bc6a75ec05c5343004a7ec93006bee66c0bc/psycopg2_binary-2.9.10-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:e217ce4d37667df0bc1c397fdcd8de5e81018ef305aed9415c3b093faaeb10fb", size = 3275245, upload-time = "2024-10-16T11:21:51.989Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1b/11/48ea1cd11de67f9efd7262085588790a95d9dfcd9b8a687d46caf7305c1a/psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:245159e7ab20a71d989da00f280ca57da7641fa2cdcf71749c193cea540a74f7", size = 2851631, upload-time = "2024-10-16T11:21:57.584Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/62/e0/62ce5ee650e6c86719d621a761fe4bc846ab9eff8c1f12b1ed5741bf1c9b/psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c4ded1a24b20021ebe677b7b08ad10bf09aac197d6943bfe6fec70ac4e4690d", size = 3082140, upload-time = "2024-10-16T11:22:02.005Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/27/ce/63f946c098611f7be234c0dd7cb1ad68b0b5744d34f68062bb3c5aa510c8/psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3abb691ff9e57d4a93355f60d4f4c1dd2d68326c968e7db17ea96df3c023ef73", size = 3264762, upload-time = "2024-10-16T11:22:06.412Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/43/25/c603cd81402e69edf7daa59b1602bd41eb9859e2824b8c0855d748366ac9/psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8608c078134f0b3cbd9f89b34bd60a943b23fd33cc5f065e8d5f840061bd0673", size = 3020967, upload-time = "2024-10-16T11:22:11.583Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5f/d6/8708d8c6fca531057fa170cdde8df870e8b6a9b136e82b361c65e42b841e/psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:230eeae2d71594103cd5b93fd29d1ace6420d0b86f4778739cb1a5a32f607d1f", size = 2872326, upload-time = "2024-10-16T11:22:16.406Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ce/ac/5b1ea50fc08a9df82de7e1771537557f07c2632231bbab652c7e22597908/psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:bb89f0a835bcfc1d42ccd5f41f04870c1b936d8507c6df12b7737febc40f0909", size = 2822712, upload-time = "2024-10-16T11:22:21.366Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c4/fc/504d4503b2abc4570fac3ca56eb8fed5e437bf9c9ef13f36b6621db8ef00/psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f0c2d907a1e102526dd2986df638343388b94c33860ff3bbe1384130828714b1", size = 2920155, upload-time = "2024-10-16T11:22:25.684Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b2/d1/323581e9273ad2c0dbd1902f3fb50c441da86e894b6e25a73c3fda32c57e/psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f8157bed2f51db683f31306aa497311b560f2265998122abe1dce6428bd86567", size = 2959356, upload-time = "2024-10-16T11:22:30.562Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/08/50/d13ea0a054189ae1bc21af1d85b6f8bb9bbc5572991055d70ad9006fe2d6/psycopg2_binary-2.9.10-cp313-cp313-win_amd64.whl", hash = "sha256:27422aa5f11fbcd9b18da48373eb67081243662f9b46e6fd07c3eb46e4535142", size = 2569224, upload-time = "2025-01-04T20:09:19.234Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1947,6 +2109,15 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138", size = 28248, upload-time = "2025-04-02T08:25:07.678Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "3.1.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ca/6c/3d75c196ac07ac8749600b60b03f4f6094d54e132c4d94ebac6ee0e0add0/termcolor-3.1.0.tar.gz", hash = "sha256:6a6dd7fbee581909eeec6a756cff1d7f7c376063b14e4a298dc4980309e55970", size = 14324, upload-time = "2025-04-30T11:37:53.791Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/4f/bd/de8d508070629b6d84a30d01d57e4a65c69aa7f5abe7560b8fad3b50ea59/termcolor-3.1.0-py3-none-any.whl", hash = "sha256:591dd26b5c2ce03b9e43f391264626557873ce1d379019786f99b0c2bee140aa", size = 7684, upload-time = "2025-04-30T11:37:52.382Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiktoken"
|
||||
version = "0.9.0"
|
||||
@@ -2233,3 +2404,12 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/94/c3/b2e9f38bc3e11191981d57ea08cab2166e74ea770024a646617c9cddd9f6/yarl-1.20.1-cp313-cp313t-win_amd64.whl", hash = "sha256:541d050a355bbbc27e55d906bc91cb6fe42f96c01413dd0f4ed5a5240513874f", size = 93003, upload-time = "2025-06-10T00:45:27.752Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b4/2d/2345fce04cfd4bee161bf1e7d9cdc702e3e16109021035dbb24db654a622/yarl-1.20.1-py3-none-any.whl", hash = "sha256:83b8eb083fe4683c6115795d9fc1cfaf2cbbefb19b3a1cb68f6527460f483a77", size = 46542, upload-time = "2025-06-10T00:46:07.521Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zipp"
|
||||
version = "3.23.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547, upload-time = "2025-06-08T17:06:39.4Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276, upload-time = "2025-06-08T17:06:38.034Z" },
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user