David Chu commited on
feat: restful api endpoint
Browse files- Dockerfile +2 -3
- {tools → app}/__init__.py +0 -0
- app/agent.py +40 -0
- app/main.py +36 -0
- system_instruction.txt → app/system_instruction.txt +0 -0
- app/tools/__init__.py +0 -0
- {tools → app/tools}/dailymed.py +0 -0
- {tools → app/tools}/literature.py +0 -0
- {tools → app/tools}/pubmed.py +0 -0
- main.py +6 -38
- pyproject.toml +1 -0
- uv.lock +148 -0
Dockerfile
CHANGED
|
@@ -26,8 +26,7 @@ RUN --mount=type=cache,target=/home/appuser/.cache/uv,uid=1001,gid=1001 \
|
|
| 26 |
uv --cache-dir=/home/appuser/.cache/uv sync --frozen --no-install-project --no-dev
|
| 27 |
|
| 28 |
COPY --chown=1001 main.py main.py
|
| 29 |
-
COPY --chown=1001
|
| 30 |
-
COPY --chown=1001 system_instruction.txt system_instruction.txt
|
| 31 |
|
| 32 |
RUN uv sync --frozen --no-cache --no-dev --compile-bytecode
|
| 33 |
|
|
@@ -35,4 +34,4 @@ EXPOSE 8501
|
|
| 35 |
|
| 36 |
HEALTHCHECK CMD curl --fail http://localhost:8501/_stcore/health
|
| 37 |
|
| 38 |
-
|
|
|
|
| 26 |
uv --cache-dir=/home/appuser/.cache/uv sync --frozen --no-install-project --no-dev
|
| 27 |
|
| 28 |
COPY --chown=1001 main.py main.py
|
| 29 |
+
COPY --chown=1001 app/ app/
|
|
|
|
| 30 |
|
| 31 |
RUN uv sync --frozen --no-cache --no-dev --compile-bytecode
|
| 32 |
|
|
|
|
| 34 |
|
| 35 |
HEALTHCHECK CMD curl --fail http://localhost:8501/_stcore/health
|
| 36 |
|
| 37 |
+
CMD ["streamlit", "run", "main.py", "--server.port=8501", "--server.address=0.0.0.0"]
|
{tools → app}/__init__.py
RENAMED
|
File without changes
|
app/agent.py
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json
|
| 2 |
+
import re
|
| 3 |
+
from pathlib import Path
|
| 4 |
+
|
| 5 |
+
from google import genai
|
| 6 |
+
from google.genai import types
|
| 7 |
+
|
| 8 |
+
from app.tools import dailymed, literature
|
| 9 |
+
|
| 10 |
+
SYSTEM_INSTRUCTION = (Path(__file__).parent / "system_instruction.txt").read_text()
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
def respond(client: genai.Client, query: str) -> list[dict]:
|
| 14 |
+
config = types.GenerateContentConfig(
|
| 15 |
+
tools=[
|
| 16 |
+
dailymed.find_drug_set_ids,
|
| 17 |
+
dailymed.find_drug_instruction,
|
| 18 |
+
literature.search_medical_literature,
|
| 19 |
+
],
|
| 20 |
+
system_instruction=SYSTEM_INSTRUCTION,
|
| 21 |
+
)
|
| 22 |
+
resp = client.models.generate_content(
|
| 23 |
+
model="gemini-2.5-flash-preview-04-17",
|
| 24 |
+
contents=query,
|
| 25 |
+
config=config,
|
| 26 |
+
)
|
| 27 |
+
|
| 28 |
+
output = ((resp.text) or "").strip()
|
| 29 |
+
|
| 30 |
+
if output.startswith("```"):
|
| 31 |
+
# Extract content inside the first markdown code block (``` or ```json)
|
| 32 |
+
match = re.match(r"^```(?:json)?\s*([\s\S]*?)\s*```", output)
|
| 33 |
+
if match:
|
| 34 |
+
output = match.group(1).strip()
|
| 35 |
+
|
| 36 |
+
try:
|
| 37 |
+
return json.loads(output)
|
| 38 |
+
except json.decoder.JSONDecodeError as err:
|
| 39 |
+
print(err)
|
| 40 |
+
return [{"text": output}]
|
app/main.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
|
| 3 |
+
from fastapi import FastAPI
|
| 4 |
+
from google import genai
|
| 5 |
+
from pydantic import BaseModel
|
| 6 |
+
|
| 7 |
+
from app import agent
|
| 8 |
+
|
| 9 |
+
app = FastAPI()
|
| 10 |
+
|
| 11 |
+
gemini = genai.Client(api_key=os.environ["GOOGLE_API_KEY"])
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
class Source(BaseModel):
|
| 15 |
+
title: str
|
| 16 |
+
url: str
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
class Statement(BaseModel):
|
| 20 |
+
text: str
|
| 21 |
+
sources: list[Source] | None = None
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
class Statements(BaseModel):
|
| 25 |
+
statements: list[Statement]
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
@app.get("/health")
|
| 29 |
+
def health_check():
|
| 30 |
+
return "ok"
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
@app.get("/ask", response_model=Statements)
|
| 34 |
+
def ask(query: str):
|
| 35 |
+
output = agent.respond(gemini, query)
|
| 36 |
+
return {"statements": output}
|
system_instruction.txt → app/system_instruction.txt
RENAMED
|
File without changes
|
app/tools/__init__.py
ADDED
|
File without changes
|
{tools → app/tools}/dailymed.py
RENAMED
|
File without changes
|
{tools → app/tools}/literature.py
RENAMED
|
File without changes
|
{tools → app/tools}/pubmed.py
RENAMED
|
File without changes
|
main.py
CHANGED
|
@@ -7,47 +7,14 @@ import streamlit as st
|
|
| 7 |
from google import genai
|
| 8 |
from google.genai import types
|
| 9 |
|
| 10 |
-
from
|
| 11 |
|
| 12 |
-
SYSTEM_INSTRUCTION = Path("system_instruction.txt").read_text()
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
def respond(client: genai.Client, query: str) -> str:
|
| 16 |
-
config = types.GenerateContentConfig(
|
| 17 |
-
tools=[
|
| 18 |
-
dailymed.find_drug_set_ids,
|
| 19 |
-
dailymed.find_drug_instruction,
|
| 20 |
-
literature.search_medical_literature,
|
| 21 |
-
],
|
| 22 |
-
system_instruction=SYSTEM_INSTRUCTION,
|
| 23 |
-
)
|
| 24 |
-
response = client.models.generate_content(
|
| 25 |
-
model="gemini-2.5-flash-preview-04-17",
|
| 26 |
-
contents=query,
|
| 27 |
-
config=config,
|
| 28 |
-
)
|
| 29 |
-
return response.text or ""
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
def format_output(response: str) -> tuple[str, str]:
|
| 33 |
-
response = response.strip()
|
| 34 |
-
|
| 35 |
-
if response.startswith("```"):
|
| 36 |
-
# Extract content inside the first markdown code block (``` or ```json)
|
| 37 |
-
match = re.match(r"^```(?:json)?\s*([\s\S]*?)\s*```", response)
|
| 38 |
-
if match:
|
| 39 |
-
response = match.group(1).strip()
|
| 40 |
-
|
| 41 |
-
try:
|
| 42 |
-
statements = json.loads(response.strip())
|
| 43 |
-
except json.decoder.JSONDecodeError as err:
|
| 44 |
-
print(err)
|
| 45 |
-
return response, ""
|
| 46 |
|
|
|
|
| 47 |
try:
|
| 48 |
answer = ""
|
| 49 |
citations = {}
|
| 50 |
-
for statement in
|
| 51 |
text = statement["text"].strip()
|
| 52 |
answer = (
|
| 53 |
answer + f"\n{text}"
|
|
@@ -65,7 +32,7 @@ def format_output(response: str) -> tuple[str, str]:
|
|
| 65 |
answer += " ".join(f"[^{i}]" for i in sorted(citation_ids))
|
| 66 |
except KeyError as err:
|
| 67 |
print(err)
|
| 68 |
-
return response, ""
|
| 69 |
|
| 70 |
footnotes = "\n".join(f"[^{id}]: {citation}" for citation, id in citations.items())
|
| 71 |
return answer, footnotes
|
|
@@ -83,7 +50,8 @@ def main():
|
|
| 83 |
if submit:
|
| 84 |
with st.spinner("Thinking...", show_time=True):
|
| 85 |
output = respond(gemini_client, query)
|
| 86 |
-
|
|
|
|
| 87 |
response.markdown(f"{answer}\n\n{footnotes}")
|
| 88 |
|
| 89 |
|
|
|
|
| 7 |
from google import genai
|
| 8 |
from google.genai import types
|
| 9 |
|
| 10 |
+
from app.agent import respond
|
| 11 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
|
| 13 |
+
def format_output(response: list[dict]) -> tuple[str, str]:
|
| 14 |
try:
|
| 15 |
answer = ""
|
| 16 |
citations = {}
|
| 17 |
+
for statement in response:
|
| 18 |
text = statement["text"].strip()
|
| 19 |
answer = (
|
| 20 |
answer + f"\n{text}"
|
|
|
|
| 32 |
answer += " ".join(f"[^{i}]" for i in sorted(citation_ids))
|
| 33 |
except KeyError as err:
|
| 34 |
print(err)
|
| 35 |
+
return str(response), ""
|
| 36 |
|
| 37 |
footnotes = "\n".join(f"[^{id}]: {citation}" for citation, id in citations.items())
|
| 38 |
return answer, footnotes
|
|
|
|
| 50 |
if submit:
|
| 51 |
with st.spinner("Thinking...", show_time=True):
|
| 52 |
output = respond(gemini_client, query)
|
| 53 |
+
|
| 54 |
+
answer, footnotes = format_output(output)
|
| 55 |
response.markdown(f"{answer}\n\n{footnotes}")
|
| 56 |
|
| 57 |
|
pyproject.toml
CHANGED
|
@@ -5,6 +5,7 @@ description = "Add your description here"
|
|
| 5 |
readme = "README.md"
|
| 6 |
requires-python = ">=3.12"
|
| 7 |
dependencies = [
|
|
|
|
| 8 |
"google-genai>=1.14.0",
|
| 9 |
"httpx>=0.28.1",
|
| 10 |
"pydantic>=2.11.4",
|
|
|
|
| 5 |
readme = "README.md"
|
| 6 |
requires-python = ">=3.12"
|
| 7 |
dependencies = [
|
| 8 |
+
"fastapi[standard]>=0.115.12",
|
| 9 |
"google-genai>=1.14.0",
|
| 10 |
"httpx>=0.28.1",
|
| 11 |
"pydantic>=2.11.4",
|
uv.lock
CHANGED
|
@@ -187,11 +187,21 @@ wheels = [
|
|
| 187 |
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
|
| 188 |
]
|
| 189 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 190 |
[[package]]
|
| 191 |
name = "elna"
|
| 192 |
version = "0.1.0"
|
| 193 |
source = { virtual = "." }
|
| 194 |
dependencies = [
|
|
|
|
| 195 |
{ name = "google-genai" },
|
| 196 |
{ name = "httpx" },
|
| 197 |
{ name = "pydantic" },
|
|
@@ -202,6 +212,7 @@ dependencies = [
|
|
| 202 |
|
| 203 |
[package.metadata]
|
| 204 |
requires-dist = [
|
|
|
|
| 205 |
{ name = "google-genai", specifier = ">=1.14.0" },
|
| 206 |
{ name = "httpx", specifier = ">=0.28.1" },
|
| 207 |
{ name = "pydantic", specifier = ">=2.11.4" },
|
|
@@ -210,6 +221,62 @@ requires-dist = [
|
|
| 210 |
{ name = "tenacity", specifier = ">=9.1.2" },
|
| 211 |
]
|
| 212 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 213 |
[[package]]
|
| 214 |
name = "fastcore"
|
| 215 |
version = "1.8.2"
|
|
@@ -407,6 +474,18 @@ wheels = [
|
|
| 407 |
{ url = "https://files.pythonhosted.org/packages/01/0e/b27cdbaccf30b890c40ed1da9fd4a3593a5cf94dae54fb34f8a4b74fcd3f/jsonschema_specifications-2025.4.1-py3-none-any.whl", hash = "sha256:4653bffbd6584f7de83a67e0d620ef16900b390ddc7939d56684d6c81e33f1af", size = 18437, upload-time = "2025-04-23T12:34:05.422Z" },
|
| 408 |
]
|
| 409 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 410 |
[[package]]
|
| 411 |
name = "markupsafe"
|
| 412 |
version = "3.0.2"
|
|
@@ -445,6 +524,15 @@ wheels = [
|
|
| 445 |
{ url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739, upload-time = "2024-10-18T15:21:42.784Z" },
|
| 446 |
]
|
| 447 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 448 |
[[package]]
|
| 449 |
name = "narwhals"
|
| 450 |
version = "1.38.2"
|
|
@@ -725,6 +813,15 @@ wheels = [
|
|
| 725 |
{ url = "https://files.pythonhosted.org/packages/ab/4c/b888e6cf58bd9db9c93f40d1c6be8283ff49d88919231afe93a6bcf61626/pydeck-0.9.1-py2.py3-none-any.whl", hash = "sha256:b3f75ba0d273fc917094fa61224f3f6076ca8752b93d46faf3bcfd9f9d59b038", size = 6900403, upload-time = "2024-05-10T15:36:17.36Z" },
|
| 726 |
]
|
| 727 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 728 |
[[package]]
|
| 729 |
name = "python-dateutil"
|
| 730 |
version = "2.9.0.post0"
|
|
@@ -840,6 +937,33 @@ wheels = [
|
|
| 840 |
{ url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928, upload-time = "2024-05-29T15:37:47.027Z" },
|
| 841 |
]
|
| 842 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 843 |
[[package]]
|
| 844 |
name = "rpds-py"
|
| 845 |
version = "0.24.0"
|
|
@@ -899,6 +1023,15 @@ wheels = [
|
|
| 899 |
{ url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696, upload-time = "2025-04-16T09:51:17.142Z" },
|
| 900 |
]
|
| 901 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 902 |
[[package]]
|
| 903 |
name = "six"
|
| 904 |
version = "1.17.0"
|
|
@@ -1012,6 +1145,21 @@ wheels = [
|
|
| 1012 |
{ url = "https://files.pythonhosted.org/packages/61/cc/58b1adeb1bb46228442081e746fcdbc4540905c87e8add7c277540934edb/tornado-6.4.2-cp38-abi3-win_amd64.whl", hash = "sha256:908b71bf3ff37d81073356a5fadcc660eb10c1476ee6e2725588626ce7e5ca38", size = 438907, upload-time = "2024-11-22T03:06:36.71Z" },
|
| 1013 |
]
|
| 1014 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1015 |
[[package]]
|
| 1016 |
name = "typing-extensions"
|
| 1017 |
version = "4.13.2"
|
|
|
|
| 187 |
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
|
| 188 |
]
|
| 189 |
|
| 190 |
+
[[package]]
|
| 191 |
+
name = "dnspython"
|
| 192 |
+
version = "2.7.0"
|
| 193 |
+
source = { registry = "https://pypi.org/simple" }
|
| 194 |
+
sdist = { url = "https://files.pythonhosted.org/packages/b5/4a/263763cb2ba3816dd94b08ad3a33d5fdae34ecb856678773cc40a3605829/dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1", size = 345197, upload-time = "2024-10-05T20:14:59.362Z" }
|
| 195 |
+
wheels = [
|
| 196 |
+
{ url = "https://files.pythonhosted.org/packages/68/1b/e0a87d256e40e8c888847551b20a017a6b98139178505dc7ffb96f04e954/dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86", size = 313632, upload-time = "2024-10-05T20:14:57.687Z" },
|
| 197 |
+
]
|
| 198 |
+
|
| 199 |
[[package]]
|
| 200 |
name = "elna"
|
| 201 |
version = "0.1.0"
|
| 202 |
source = { virtual = "." }
|
| 203 |
dependencies = [
|
| 204 |
+
{ name = "fastapi", extra = ["standard"] },
|
| 205 |
{ name = "google-genai" },
|
| 206 |
{ name = "httpx" },
|
| 207 |
{ name = "pydantic" },
|
|
|
|
| 212 |
|
| 213 |
[package.metadata]
|
| 214 |
requires-dist = [
|
| 215 |
+
{ name = "fastapi", extras = ["standard"], specifier = ">=0.115.12" },
|
| 216 |
{ name = "google-genai", specifier = ">=1.14.0" },
|
| 217 |
{ name = "httpx", specifier = ">=0.28.1" },
|
| 218 |
{ name = "pydantic", specifier = ">=2.11.4" },
|
|
|
|
| 221 |
{ name = "tenacity", specifier = ">=9.1.2" },
|
| 222 |
]
|
| 223 |
|
| 224 |
+
[[package]]
|
| 225 |
+
name = "email-validator"
|
| 226 |
+
version = "2.2.0"
|
| 227 |
+
source = { registry = "https://pypi.org/simple" }
|
| 228 |
+
dependencies = [
|
| 229 |
+
{ name = "dnspython" },
|
| 230 |
+
{ name = "idna" },
|
| 231 |
+
]
|
| 232 |
+
sdist = { url = "https://files.pythonhosted.org/packages/48/ce/13508a1ec3f8bb981ae4ca79ea40384becc868bfae97fd1c942bb3a001b1/email_validator-2.2.0.tar.gz", hash = "sha256:cb690f344c617a714f22e66ae771445a1ceb46821152df8e165c5f9a364582b7", size = 48967, upload-time = "2024-06-20T11:30:30.034Z" }
|
| 233 |
+
wheels = [
|
| 234 |
+
{ url = "https://files.pythonhosted.org/packages/d7/ee/bf0adb559ad3c786f12bcbc9296b3f5675f529199bef03e2df281fa1fadb/email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631", size = 33521, upload-time = "2024-06-20T11:30:28.248Z" },
|
| 235 |
+
]
|
| 236 |
+
|
| 237 |
+
[[package]]
|
| 238 |
+
name = "fastapi"
|
| 239 |
+
version = "0.115.12"
|
| 240 |
+
source = { registry = "https://pypi.org/simple" }
|
| 241 |
+
dependencies = [
|
| 242 |
+
{ name = "pydantic" },
|
| 243 |
+
{ name = "starlette" },
|
| 244 |
+
{ name = "typing-extensions" },
|
| 245 |
+
]
|
| 246 |
+
sdist = { url = "https://files.pythonhosted.org/packages/f4/55/ae499352d82338331ca1e28c7f4a63bfd09479b16395dce38cf50a39e2c2/fastapi-0.115.12.tar.gz", hash = "sha256:1e2c2a2646905f9e83d32f04a3f86aff4a286669c6c950ca95b5fd68c2602681", size = 295236, upload-time = "2025-03-23T22:55:43.822Z" }
|
| 247 |
+
wheels = [
|
| 248 |
+
{ url = "https://files.pythonhosted.org/packages/50/b3/b51f09c2ba432a576fe63758bddc81f78f0c6309d9e5c10d194313bf021e/fastapi-0.115.12-py3-none-any.whl", hash = "sha256:e94613d6c05e27be7ffebdd6ea5f388112e5e430c8f7d6494a9d1d88d43e814d", size = 95164, upload-time = "2025-03-23T22:55:42.101Z" },
|
| 249 |
+
]
|
| 250 |
+
|
| 251 |
+
[package.optional-dependencies]
|
| 252 |
+
standard = [
|
| 253 |
+
{ name = "email-validator" },
|
| 254 |
+
{ name = "fastapi-cli", extra = ["standard"] },
|
| 255 |
+
{ name = "httpx" },
|
| 256 |
+
{ name = "jinja2" },
|
| 257 |
+
{ name = "python-multipart" },
|
| 258 |
+
{ name = "uvicorn", extra = ["standard"] },
|
| 259 |
+
]
|
| 260 |
+
|
| 261 |
+
[[package]]
|
| 262 |
+
name = "fastapi-cli"
|
| 263 |
+
version = "0.0.7"
|
| 264 |
+
source = { registry = "https://pypi.org/simple" }
|
| 265 |
+
dependencies = [
|
| 266 |
+
{ name = "rich-toolkit" },
|
| 267 |
+
{ name = "typer" },
|
| 268 |
+
{ name = "uvicorn", extra = ["standard"] },
|
| 269 |
+
]
|
| 270 |
+
sdist = { url = "https://files.pythonhosted.org/packages/fe/73/82a5831fbbf8ed75905bacf5b2d9d3dfd6f04d6968b29fe6f72a5ae9ceb1/fastapi_cli-0.0.7.tar.gz", hash = "sha256:02b3b65956f526412515907a0793c9094abd4bfb5457b389f645b0ea6ba3605e", size = 16753, upload-time = "2024-12-15T14:28:10.028Z" }
|
| 271 |
+
wheels = [
|
| 272 |
+
{ url = "https://files.pythonhosted.org/packages/a1/e6/5daefc851b514ce2287d8f5d358ae4341089185f78f3217a69d0ce3a390c/fastapi_cli-0.0.7-py3-none-any.whl", hash = "sha256:d549368ff584b2804336c61f192d86ddea080c11255f375959627911944804f4", size = 10705, upload-time = "2024-12-15T14:28:06.18Z" },
|
| 273 |
+
]
|
| 274 |
+
|
| 275 |
+
[package.optional-dependencies]
|
| 276 |
+
standard = [
|
| 277 |
+
{ name = "uvicorn", extra = ["standard"] },
|
| 278 |
+
]
|
| 279 |
+
|
| 280 |
[[package]]
|
| 281 |
name = "fastcore"
|
| 282 |
version = "1.8.2"
|
|
|
|
| 474 |
{ url = "https://files.pythonhosted.org/packages/01/0e/b27cdbaccf30b890c40ed1da9fd4a3593a5cf94dae54fb34f8a4b74fcd3f/jsonschema_specifications-2025.4.1-py3-none-any.whl", hash = "sha256:4653bffbd6584f7de83a67e0d620ef16900b390ddc7939d56684d6c81e33f1af", size = 18437, upload-time = "2025-04-23T12:34:05.422Z" },
|
| 475 |
]
|
| 476 |
|
| 477 |
+
[[package]]
|
| 478 |
+
name = "markdown-it-py"
|
| 479 |
+
version = "3.0.0"
|
| 480 |
+
source = { registry = "https://pypi.org/simple" }
|
| 481 |
+
dependencies = [
|
| 482 |
+
{ name = "mdurl" },
|
| 483 |
+
]
|
| 484 |
+
sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" }
|
| 485 |
+
wheels = [
|
| 486 |
+
{ url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload-time = "2023-06-03T06:41:11.019Z" },
|
| 487 |
+
]
|
| 488 |
+
|
| 489 |
[[package]]
|
| 490 |
name = "markupsafe"
|
| 491 |
version = "3.0.2"
|
|
|
|
| 524 |
{ url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739, upload-time = "2024-10-18T15:21:42.784Z" },
|
| 525 |
]
|
| 526 |
|
| 527 |
+
[[package]]
|
| 528 |
+
name = "mdurl"
|
| 529 |
+
version = "0.1.2"
|
| 530 |
+
source = { registry = "https://pypi.org/simple" }
|
| 531 |
+
sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" }
|
| 532 |
+
wheels = [
|
| 533 |
+
{ url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" },
|
| 534 |
+
]
|
| 535 |
+
|
| 536 |
[[package]]
|
| 537 |
name = "narwhals"
|
| 538 |
version = "1.38.2"
|
|
|
|
| 813 |
{ url = "https://files.pythonhosted.org/packages/ab/4c/b888e6cf58bd9db9c93f40d1c6be8283ff49d88919231afe93a6bcf61626/pydeck-0.9.1-py2.py3-none-any.whl", hash = "sha256:b3f75ba0d273fc917094fa61224f3f6076ca8752b93d46faf3bcfd9f9d59b038", size = 6900403, upload-time = "2024-05-10T15:36:17.36Z" },
|
| 814 |
]
|
| 815 |
|
| 816 |
+
[[package]]
|
| 817 |
+
name = "pygments"
|
| 818 |
+
version = "2.19.1"
|
| 819 |
+
source = { registry = "https://pypi.org/simple" }
|
| 820 |
+
sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581, upload-time = "2025-01-06T17:26:30.443Z" }
|
| 821 |
+
wheels = [
|
| 822 |
+
{ url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293, upload-time = "2025-01-06T17:26:25.553Z" },
|
| 823 |
+
]
|
| 824 |
+
|
| 825 |
[[package]]
|
| 826 |
name = "python-dateutil"
|
| 827 |
version = "2.9.0.post0"
|
|
|
|
| 937 |
{ url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928, upload-time = "2024-05-29T15:37:47.027Z" },
|
| 938 |
]
|
| 939 |
|
| 940 |
+
[[package]]
|
| 941 |
+
name = "rich"
|
| 942 |
+
version = "14.0.0"
|
| 943 |
+
source = { registry = "https://pypi.org/simple" }
|
| 944 |
+
dependencies = [
|
| 945 |
+
{ name = "markdown-it-py" },
|
| 946 |
+
{ name = "pygments" },
|
| 947 |
+
]
|
| 948 |
+
sdist = { url = "https://files.pythonhosted.org/packages/a1/53/830aa4c3066a8ab0ae9a9955976fb770fe9c6102117c8ec4ab3ea62d89e8/rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725", size = 224078, upload-time = "2025-03-30T14:15:14.23Z" }
|
| 949 |
+
wheels = [
|
| 950 |
+
{ url = "https://files.pythonhosted.org/packages/0d/9b/63f4c7ebc259242c89b3acafdb37b41d1185c07ff0011164674e9076b491/rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0", size = 243229, upload-time = "2025-03-30T14:15:12.283Z" },
|
| 951 |
+
]
|
| 952 |
+
|
| 953 |
+
[[package]]
|
| 954 |
+
name = "rich-toolkit"
|
| 955 |
+
version = "0.14.6"
|
| 956 |
+
source = { registry = "https://pypi.org/simple" }
|
| 957 |
+
dependencies = [
|
| 958 |
+
{ name = "click" },
|
| 959 |
+
{ name = "rich" },
|
| 960 |
+
{ name = "typing-extensions" },
|
| 961 |
+
]
|
| 962 |
+
sdist = { url = "https://files.pythonhosted.org/packages/f6/31/b6d055f291a660a7bcaec4bcc9457b9fef8ecb6293e527b1eef1840aefd4/rich_toolkit-0.14.6.tar.gz", hash = "sha256:9dbd40e83414b84e828bf899115fff8877ce5951b73175f44db142902f07645d", size = 110805, upload-time = "2025-05-12T19:19:15.284Z" }
|
| 963 |
+
wheels = [
|
| 964 |
+
{ url = "https://files.pythonhosted.org/packages/2e/3c/7a824c0514e87c61000583ac22c8321da6dc8e58a93d5f56e583482a2ee0/rich_toolkit-0.14.6-py3-none-any.whl", hash = "sha256:764f3a5f9e4b539ce805596863299e8982599514906dc5e3ccc2d390ef74c301", size = 24815, upload-time = "2025-05-12T19:19:13.713Z" },
|
| 965 |
+
]
|
| 966 |
+
|
| 967 |
[[package]]
|
| 968 |
name = "rpds-py"
|
| 969 |
version = "0.24.0"
|
|
|
|
| 1023 |
{ url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696, upload-time = "2025-04-16T09:51:17.142Z" },
|
| 1024 |
]
|
| 1025 |
|
| 1026 |
+
[[package]]
|
| 1027 |
+
name = "shellingham"
|
| 1028 |
+
version = "1.5.4"
|
| 1029 |
+
source = { registry = "https://pypi.org/simple" }
|
| 1030 |
+
sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" }
|
| 1031 |
+
wheels = [
|
| 1032 |
+
{ url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" },
|
| 1033 |
+
]
|
| 1034 |
+
|
| 1035 |
[[package]]
|
| 1036 |
name = "six"
|
| 1037 |
version = "1.17.0"
|
|
|
|
| 1145 |
{ url = "https://files.pythonhosted.org/packages/61/cc/58b1adeb1bb46228442081e746fcdbc4540905c87e8add7c277540934edb/tornado-6.4.2-cp38-abi3-win_amd64.whl", hash = "sha256:908b71bf3ff37d81073356a5fadcc660eb10c1476ee6e2725588626ce7e5ca38", size = 438907, upload-time = "2024-11-22T03:06:36.71Z" },
|
| 1146 |
]
|
| 1147 |
|
| 1148 |
+
[[package]]
|
| 1149 |
+
name = "typer"
|
| 1150 |
+
version = "0.15.4"
|
| 1151 |
+
source = { registry = "https://pypi.org/simple" }
|
| 1152 |
+
dependencies = [
|
| 1153 |
+
{ name = "click" },
|
| 1154 |
+
{ name = "rich" },
|
| 1155 |
+
{ name = "shellingham" },
|
| 1156 |
+
{ name = "typing-extensions" },
|
| 1157 |
+
]
|
| 1158 |
+
sdist = { url = "https://files.pythonhosted.org/packages/6c/89/c527e6c848739be8ceb5c44eb8208c52ea3515c6cf6406aa61932887bf58/typer-0.15.4.tar.gz", hash = "sha256:89507b104f9b6a0730354f27c39fae5b63ccd0c95b1ce1f1a6ba0cfd329997c3", size = 101559, upload-time = "2025-05-14T16:34:57.704Z" }
|
| 1159 |
+
wheels = [
|
| 1160 |
+
{ url = "https://files.pythonhosted.org/packages/c9/62/d4ba7afe2096d5659ec3db8b15d8665bdcb92a3c6ff0b95e99895b335a9c/typer-0.15.4-py3-none-any.whl", hash = "sha256:eb0651654dcdea706780c466cf06d8f174405a659ffff8f163cfbfee98c0e173", size = 45258, upload-time = "2025-05-14T16:34:55.583Z" },
|
| 1161 |
+
]
|
| 1162 |
+
|
| 1163 |
[[package]]
|
| 1164 |
name = "typing-extensions"
|
| 1165 |
version = "4.13.2"
|