Merge pull request #401 from trustgraph-ai/release/v1.0

1.0 -> master
This commit is contained in:
cybermaggedon 2025-05-28 11:31:31 +01:00 committed by GitHub
commit b8822b7ce0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
47 changed files with 343 additions and 159 deletions

View file

@ -4,14 +4,16 @@
# like to avoid re-doing this. # like to avoid re-doing this.
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
FROM docker.io/fedora:40 AS base FROM docker.io/fedora:42 AS base
ENV PIP_BREAK_SYSTEM_PACKAGES=1 ENV PIP_BREAK_SYSTEM_PACKAGES=1
RUN dnf install -y python3 python3-pip python3-wheel python3-aiohttp && \ RUN dnf install -y python3.12 && \
dnf clean all alternatives --install /usr/bin/python python /usr/bin/python3.12 1 && \
python -m ensurepip --upgrade && \
RUN pip3 install --no-cache-dir pulsar-client==3.5.0 pip3 install --no-cache-dir wheel aiohttp && \
pip3 install --no-cache-dir pulsar-client==3.7.0 && \
dnf clean all
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
# Build a container which contains the built Python packages. The build # Build a container which contains the built Python packages. The build

View file

@ -4,14 +4,16 @@
# like to avoid re-doing this. # like to avoid re-doing this.
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
FROM docker.io/fedora:40 AS base FROM docker.io/fedora:42 AS base
ENV PIP_BREAK_SYSTEM_PACKAGES=1 ENV PIP_BREAK_SYSTEM_PACKAGES=1
RUN dnf install -y python3 python3-pip python3-wheel python3-aiohttp \ RUN dnf install -y python3.12 && \
python3-rdflib alternatives --install /usr/bin/python python /usr/bin/python3.12 1 && \
python -m ensurepip --upgrade && \
RUN pip3 install --no-cache-dir boto3 pulsar-client==3.5.0 pip3 install --no-cache-dir wheel aiohttp && \
pip3 install --no-cache-dir pulsar-client==3.7.0 && \
dnf clean all
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
# Build a container which contains the built Python packages. The build # Build a container which contains the built Python packages. The build

View file

@ -4,21 +4,25 @@
# like to avoid re-doing this. # like to avoid re-doing this.
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
FROM docker.io/fedora:40 AS base FROM docker.io/fedora:42 AS base
ENV PIP_BREAK_SYSTEM_PACKAGES=1 ENV PIP_BREAK_SYSTEM_PACKAGES=1
RUN dnf install -y python3 python3-pip python3-wheel python3-aiohttp \ RUN dnf install -y python3.12 && \
python3-rdflib alternatives --install /usr/bin/python python /usr/bin/python3.12 1 && \
python -m ensurepip --upgrade && \
pip3 install --no-cache-dir wheel aiohttp rdflib && \
pip3 install --no-cache-dir pulsar-client==3.7.0 && \
dnf clean all
RUN pip3 install --no-cache-dir \ RUN pip3 install --no-cache-dir \
anthropic cohere mistralai openai google-generativeai \ anthropic cohere mistralai openai google-generativeai \
ollama \ ollama \
langchain==0.3.13 langchain-core==0.3.28 \ langchain==0.3.25 langchain-core==0.3.60 \
langchain-text-splitters==0.3.4 \ langchain-text-splitters==0.3.8 \
langchain-community==0.3.13 \ langchain-community==0.3.24 \
pymilvus \ pymilvus \
pulsar-client==3.5.0 cassandra-driver pyyaml \ pulsar-client==3.7.0 cassandra-driver pyyaml \
neo4j tiktoken falkordb && \ neo4j tiktoken falkordb && \
pip3 cache purge pip3 cache purge

View file

@ -4,22 +4,26 @@
# like to avoid re-doing this. # like to avoid re-doing this.
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
FROM docker.io/fedora:40 AS ai FROM docker.io/fedora:42 AS ai
ENV PIP_BREAK_SYSTEM_PACKAGES=1 ENV PIP_BREAK_SYSTEM_PACKAGES=1
RUN dnf install -y python3 python3-pip python3-wheel python3-aiohttp \ RUN dnf install -y python3.12 && \
python3-rdflib alternatives --install /usr/bin/python python /usr/bin/python3.12 1 && \
python -m ensurepip --upgrade && \
pip3 install --no-cache-dir wheel aiohttp && \
pip3 install --no-cache-dir pulsar-client==3.7.0 && \
dnf clean all
RUN pip3 install torch==2.5.1+cpu \ RUN pip3 install torch==2.5.1+cpu \
--index-url https://download.pytorch.org/whl/cpu --index-url https://download.pytorch.org/whl/cpu
RUN pip3 install --no-cache-dir \ RUN pip3 install --no-cache-dir \
langchain==0.3.13 langchain-core==0.3.28 langchain-huggingface==0.1.2 \ langchain==0.3.25 langchain-core==0.3.60 langchain-huggingface==0.2.0 \
langchain-community==0.3.13 \ langchain-community==0.3.24 \
sentence-transformers==3.4.0 transformers==4.47.1 \ sentence-transformers==4.1.0 transformers==4.51.3 \
huggingface-hub==0.27.0 \ huggingface-hub==0.31.2 \
pulsar-client==3.5.0 pulsar-client==3.7.0
# Most commonly used embeddings model, just build it into the container # Most commonly used embeddings model, just build it into the container
# image # image

View file

@ -4,14 +4,16 @@
# like to avoid re-doing this. # like to avoid re-doing this.
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
FROM docker.io/fedora:40 AS base FROM docker.io/fedora:42 AS base
ENV PIP_BREAK_SYSTEM_PACKAGES=1 ENV PIP_BREAK_SYSTEM_PACKAGES=1
RUN dnf install -y python3 python3-pip python3-wheel python3-aiohttp \ RUN dnf install -y python3.12 && \
python3-rdflib tesseract poppler poppler-utils alternatives --install /usr/bin/python python /usr/bin/python3.12 1 && \
python -m ensurepip --upgrade && \
RUN pip3 install --no-cache-dir pytesseract pulsar-client==3.5.0 pip3 install --no-cache-dir wheel aiohttp && \
pip3 install --no-cache-dir pulsar-client==3.7.0 && \
dnf clean all
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
# Build a container which contains the built Python packages. The build # Build a container which contains the built Python packages. The build

View file

@ -4,15 +4,17 @@
# like to avoid re-doing this. # like to avoid re-doing this.
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
FROM docker.io/fedora:40 AS base FROM docker.io/fedora:42 AS base
ENV PIP_BREAK_SYSTEM_PACKAGES=1 ENV PIP_BREAK_SYSTEM_PACKAGES=1
RUN dnf install -y python3 python3-pip python3-wheel python3-aiohttp \ RUN dnf install -y python3.12 && \
python3-rdflib alternatives --install /usr/bin/python python /usr/bin/python3.12 1 && \
python -m ensurepip --upgrade && \
RUN pip3 install --no-cache-dir \ pip3 install --no-cache-dir wheel aiohttp && \
google-cloud-aiplatform pulsar-client==3.5.0 pip3 install --no-cache-dir pulsar-client==3.7.0 && \
pip3 install --no-cache-dir google-cloud-aiplatform && \
dnf clean all
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
# Build a container which contains the built Python packages. The build # Build a container which contains the built Python packages. The build
@ -47,5 +49,3 @@ RUN \
WORKDIR / WORKDIR /

View file

@ -24,7 +24,7 @@ class Flow:
else: else:
return self.api.request(f"flow", request) return self.api.request(f"flow", request)
def id(self, id="0000"): def id(self, id="default"):
return FlowInstance(api=self, id=id) return FlowInstance(api=self, id=id)
def list_classes(self): def list_classes(self):

View file

@ -39,7 +39,7 @@ class Knowledge:
self.request(request = input) self.request(request = input)
def load_kg_core(self, id, user="trustgraph", flow="0000", def load_kg_core(self, id, user="trustgraph", flow="default",
collection="default"): collection="default"):
# The input consists of system and prompt strings # The input consists of system and prompt strings
@ -53,7 +53,7 @@ class Knowledge:
self.request(request = input) self.request(request = input)
def unload_kg_core(self, id, user="trustgraph", flow="0000"): def unload_kg_core(self, id, user="trustgraph", flow="default"):
# The input consists of system and prompt strings # The input consists of system and prompt strings
input = { input = {

View file

@ -208,7 +208,7 @@ class Library:
return {} return {}
def start_processing( def start_processing(
self, id, document_id, flow="0000", self, id, document_id, flow="default",
user="trustgraph", collection="default", tags=[], user="trustgraph", collection="default", tags=[],
): ):

View file

@ -127,8 +127,12 @@ class RequestResponseSpec(Spec):
rr = self.impl( rr = self.impl(
client = processor.pulsar_client, client = processor.pulsar_client,
# Make subscription names unique, so that all subscribers get
# to see all response messages
subscription = ( subscription = (
processor.id + "--" + flow.name + "--" + self.request_name processor.id + "--" + flow.name + "--" + self.request_name +
"--" + str(uuid.uuid4())
), ),
consumer_name = flow.id, consumer_name = flow.id,
request_topic = definition[self.request_name], request_topic = definition[self.request_name],

View file

@ -34,7 +34,7 @@ setuptools.setup(
python_requires='>=3.8', python_requires='>=3.8',
download_url = "https://github.com/trustgraph-ai/trustgraph/archive/refs/tags/v" + version + ".tar.gz", download_url = "https://github.com/trustgraph-ai/trustgraph/archive/refs/tags/v" + version + ".tar.gz",
install_requires=[ install_requires=[
"trustgraph-base>=0.23,<0.24", "trustgraph-base>=1.0,<1.1",
"pulsar-client", "pulsar-client",
"prometheus-client", "prometheus-client",
"boto3", "boto3",

View file

@ -71,8 +71,8 @@ def main():
parser.add_argument( parser.add_argument(
'-f', '--flow-id', '-f', '--flow-id',
default="0000", default="default",
help=f'Flow ID (default: 0000)' help=f'Flow ID (default: default)'
) )
parser.add_argument( parser.add_argument(

View file

@ -110,8 +110,8 @@ def main():
parser.add_argument( parser.add_argument(
'-f', '--flow-id', '-f', '--flow-id',
default="0000", default="default",
help=f'Flow ID (default: 0000)' help=f'Flow ID (default: default)'
) )
parser.add_argument( parser.add_argument(

View file

@ -39,8 +39,8 @@ def main():
parser.add_argument( parser.add_argument(
'-f', '--flow-id', '-f', '--flow-id',
default="0000", default="default",
help=f'Flow ID (default: 0000)' help=f'Flow ID (default: default)'
) )
parser.add_argument( parser.add_argument(

View file

@ -47,8 +47,8 @@ def main():
parser.add_argument( parser.add_argument(
'-f', '--flow-id', '-f', '--flow-id',
default="0000", default="default",
help=f'Flow ID (default: 0000)' help=f'Flow ID (default: default)'
) )
parser.add_argument( parser.add_argument(

View file

@ -47,8 +47,8 @@ def main():
parser.add_argument( parser.add_argument(
'-f', '--flow-id', '-f', '--flow-id',
default="0000", default="default",
help=f'Flow ID (default: 0000)' help=f'Flow ID (default: default)'
) )
args = parser.parse_args() args = parser.parse_args()

View file

@ -42,8 +42,8 @@ def main():
parser.add_argument( parser.add_argument(
'-f', '--flow-id', '-f', '--flow-id',
default="0000", default="default",
help=f'Flow ID (default: 0000)' help=f'Flow ID (default: default)'
) )
parser.add_argument( parser.add_argument(

View file

@ -191,8 +191,8 @@ async def main(running):
parser.add_argument( parser.add_argument(
'-f', '--flow-id', '-f', '--flow-id',
default="0000", default="default",
help=f'Flow ID (default: 0000)' help=f'Flow ID (default: default)'
) )
parser.add_argument( parser.add_argument(

View file

@ -13,7 +13,7 @@ from trustgraph.api import Api
import json import json
default_url = os.getenv("TRUSTGRAPH_URL", 'http://localhost:8088/') default_url = os.getenv("TRUSTGRAPH_URL", 'http://localhost:8088/')
default_flow = "0000" default_flow = "default"
default_collection = "default" default_collection = "default"
def load_kg_core(url, user, id, flow, collection): def load_kg_core(url, user, id, flow, collection):

View file

@ -86,8 +86,8 @@ def main():
parser.add_argument( parser.add_argument(
'-f', '--flow-id', '-f', '--flow-id',
default="0000", default="default",
help=f'Flow ID (default: 0000)' help=f'Flow ID (default: default)'
) )
parser.add_argument( parser.add_argument(

View file

@ -40,8 +40,7 @@ documents = [
"id": "https://trustgraph.ai/doc/challenger-report-vol-1", "id": "https://trustgraph.ai/doc/challenger-report-vol-1",
"title": "Report of the Presidential Commission on the Space Shuttle Challenger Accident, Volume 1", "title": "Report of the Presidential Commission on the Space Shuttle Challenger Accident, Volume 1",
"comments": "The findings of the Commission regarding the circumstances surrounding the Challenger accident are reported and recommendations for corrective action are outlined", "comments": "The findings of the Commission regarding the circumstances surrounding the Challenger accident are reported and recommendations for corrective action are outlined",
# "url": "https://ntrs.nasa.gov/api/citations/19860015255/downloads/19860015255.pdf", "url": "https://ntrs.nasa.gov/api/citations/19860015255/downloads/19860015255.pdf",
"url": "file://19860015255.pdf",
"kind": "application/pdf", "kind": "application/pdf",
"date": datetime.datetime.now().date(), "date": datetime.datetime.now().date(),
"tags": ["nasa", "safety-engineering", "space-shuttle"], "tags": ["nasa", "safety-engineering", "space-shuttle"],
@ -740,10 +739,3 @@ def main():
main() main()
# https://warwick.ac.uk/fac/soc/pais/people/aldrich/publications/beyond.pdf
# https://www.ialeia.org/docs/Psychology_of_Intelligence_Analysis.pdf

View file

@ -88,8 +88,8 @@ def main():
parser.add_argument( parser.add_argument(
'-f', '--flow-id', '-f', '--flow-id',
default="0000", default="default",
help=f'Flow ID (default: 0000)' help=f'Flow ID (default: default)'
) )
parser.add_argument( parser.add_argument(

View file

@ -113,8 +113,8 @@ def main():
parser.add_argument( parser.add_argument(
'-f', '--flow-id', '-f', '--flow-id',
default="0000", default="default",
help=f'Flow ID (default: 0000)' help=f'Flow ID (default: default)'
) )
parser.add_argument( parser.add_argument(

View file

@ -161,8 +161,8 @@ async def main(running):
parser.add_argument( parser.add_argument(
'-f', '--flow-id', '-f', '--flow-id',
default="0000", default="default",
help=f'Flow ID (default: 0000)' help=f'Flow ID (default: default)'
) )
parser.add_argument( parser.add_argument(

View file

@ -63,8 +63,8 @@ def main():
parser.add_argument( parser.add_argument(
'-f', '--flow-id', '-f', '--flow-id',
default="0000", default="default",
help=f'Flow ID (default: 0000)' help=f'Flow ID (default: default)'
) )
parser.add_argument( parser.add_argument(

View file

@ -39,8 +39,8 @@ def main():
parser.add_argument( parser.add_argument(
'-f', '--flow-id', '-f', '--flow-id',
default="0000", default="default",
help=f'Flow ID (default: 0000)' help=f'Flow ID (default: default)'
) )
parser.add_argument( parser.add_argument(

View file

@ -54,8 +54,8 @@ def main():
parser.add_argument( parser.add_argument(
'-i', '--flow-id', '-i', '--flow-id',
default="0000", default="default",
help=f'Flow ID (default: 0000)', help=f'Flow ID (default: default)',
) )
parser.add_argument( parser.add_argument(

View file

@ -13,7 +13,7 @@ from trustgraph.api import Api
import json import json
default_url = os.getenv("TRUSTGRAPH_URL", 'http://localhost:8088/') default_url = os.getenv("TRUSTGRAPH_URL", 'http://localhost:8088/')
default_flow = "0000" default_flow = "default"
default_collection = "default" default_collection = "default"
def unload_kg_core(url, user, id, flow): def unload_kg_core(url, user, id, flow):

View file

@ -34,7 +34,7 @@ setuptools.setup(
python_requires='>=3.8', python_requires='>=3.8',
download_url = "https://github.com/trustgraph-ai/trustgraph/archive/refs/tags/v" + version + ".tar.gz", download_url = "https://github.com/trustgraph-ai/trustgraph/archive/refs/tags/v" + version + ".tar.gz",
install_requires=[ install_requires=[
"trustgraph-base>=0.23,<0.24", "trustgraph-base>=1.0,<1.1",
"requests", "requests",
"pulsar-client", "pulsar-client",
"aiohttp", "aiohttp",

View file

@ -34,8 +34,8 @@ setuptools.setup(
python_requires='>=3.8', python_requires='>=3.8',
download_url = "https://github.com/trustgraph-ai/trustgraph/archive/refs/tags/v" + version + ".tar.gz", download_url = "https://github.com/trustgraph-ai/trustgraph/archive/refs/tags/v" + version + ".tar.gz",
install_requires=[ install_requires=[
"trustgraph-base>=0.23,<0.24", "trustgraph-base>=1.0,<1.1",
"trustgraph-flow>=0.23,<0.24", "trustgraph-flow>=1.0,<1.1",
"torch", "torch",
"urllib3", "urllib3",
"transformers", "transformers",

View file

@ -0,0 +1,6 @@
#!/usr/bin/env python3
from trustgraph.model.text_completion.tgi import run
run()

View file

@ -34,7 +34,7 @@ setuptools.setup(
python_requires='>=3.8', python_requires='>=3.8',
download_url = "https://github.com/trustgraph-ai/trustgraph/archive/refs/tags/v" + version + ".tar.gz", download_url = "https://github.com/trustgraph-ai/trustgraph/archive/refs/tags/v" + version + ".tar.gz",
install_requires=[ install_requires=[
"trustgraph-base>=0.23,<0.24", "trustgraph-base>=1.0,<1.1",
"aiohttp", "aiohttp",
"anthropic", "anthropic",
"cassandra-driver", "cassandra-driver",
@ -42,7 +42,7 @@ setuptools.setup(
"cryptography", "cryptography",
"falkordb", "falkordb",
"fastembed", "fastembed",
"google-generativeai", "google-genai",
"ibis", "ibis",
"jsonschema", "jsonschema",
"langchain", "langchain",
@ -117,6 +117,7 @@ setuptools.setup(
"scripts/text-completion-mistral", "scripts/text-completion-mistral",
"scripts/text-completion-ollama", "scripts/text-completion-ollama",
"scripts/text-completion-openai", "scripts/text-completion-openai",
"scripts/text-completion-tgi",
"scripts/triples-query-cassandra", "scripts/triples-query-cassandra",
"scripts/triples-query-falkordb", "scripts/triples-query-falkordb",
"scripts/triples-query-memgraph", "scripts/triples-query-memgraph",

View file

@ -65,8 +65,6 @@ class LibrarianRequestor(ServiceRequestor):
def from_response(self, message): def from_response(self, message):
print(message)
response = {} response = {}
if message.document_metadata: if message.document_metadata:

View file

@ -149,7 +149,6 @@ class Mux:
break break
try: try:
print(id, svc, request)
await self.start_request_task( await self.start_request_task(
self.ws, id, flow, svc, request, workers self.ws, id, flow, svc, request, workers

View file

@ -82,8 +82,6 @@ class ServiceRequestor:
resp, fin = self.from_response(resp) resp, fin = self.from_response(resp)
print(resp, fin, flush=True)
if responder: if responder:
await responder(resp, fin) await responder(resp, fin)

View file

@ -76,8 +76,6 @@ class ServiceRequestor:
resp, fin = self.from_inbound(resp) resp, fin = self.from_inbound(resp)
print(resp, fin)
await self.receiver(resp, fin) await self.receiver(resp, fin)
if fin: break if fin: break

View file

@ -48,7 +48,6 @@ class TriplesQueryRequestor(ServiceRequestor):
) )
def from_response(self, message): def from_response(self, message):
print(message)
return { return {
"response": serialize_subgraph(message.triples) "response": serialize_subgraph(message.triples)
}, True }, True

View file

@ -47,10 +47,8 @@ class ConstantEndpoint:
data = await request.json() data = await request.json()
print(data)
async def responder(x, fin): async def responder(x, fin):
print(x) pass
resp = await self.dispatcher.process(data, responder) resp = await self.dispatcher.process(data, responder)

View file

@ -47,10 +47,8 @@ class VariableEndpoint:
data = await request.json() data = await request.json()
print(data)
async def responder(x, fin): async def responder(x, fin):
print(x) pass
resp = await self.dispatcher.process( resp = await self.dispatcher.process(
data, responder, request.match_info data, responder, request.match_info

View file

@ -4,10 +4,18 @@ Simple LLM service, performs text prompt completion using GoogleAIStudio.
Input is prompt, output is response. Input is prompt, output is response.
""" """
import google.generativeai as genai #
from google.generativeai.types import HarmCategory, HarmBlockThreshold # Using this SDK:
# https://googleapis.github.io/python-genai/genai.html#module-genai.client
#
# Seems to have simpler dependencies on the 'VertexAI' service, which
# TrustGraph implements in the trustgraph-vertexai package.
#
from google import genai
from google.genai import types
from google.genai.types import HarmCategory, HarmBlockThreshold
from google.api_core.exceptions import ResourceExhausted from google.api_core.exceptions import ResourceExhausted
from prometheus_client import Histogram
import os import os
from .... exceptions import TooManyRequests from .... exceptions import TooManyRequests
@ -15,7 +23,7 @@ from .... base import LlmService, LlmResult
default_ident = "text-completion" default_ident = "text-completion"
default_model = 'gemini-1.5-flash-002' default_model = 'gemini-2.0-flash-001'
default_temperature = 0.0 default_temperature = 0.0
default_max_output = 8192 default_max_output = 8192
default_api_key = os.getenv("GOOGLE_AI_STUDIO_KEY") default_api_key = os.getenv("GOOGLE_AI_STUDIO_KEY")
@ -40,58 +48,56 @@ class Processor(LlmService):
} }
) )
genai.configure(api_key=api_key) self.client = genai.Client(api_key=api_key)
self.model = model self.model = model
self.temperature = temperature self.temperature = temperature
self.max_output = max_output self.max_output = max_output
self.generation_config = {
"temperature": temperature,
"top_p": 1,
"top_k": 40,
"max_output_tokens": max_output,
"response_mime_type": "text/plain",
}
block_level = HarmBlockThreshold.BLOCK_ONLY_HIGH block_level = HarmBlockThreshold.BLOCK_ONLY_HIGH
self.safety_settings={ self.safety_settings = [
HarmCategory.HARM_CATEGORY_HATE_SPEECH: block_level, types.SafetySetting(
HarmCategory.HARM_CATEGORY_HARASSMENT: block_level, category = HarmCategory.HARM_CATEGORY_HATE_SPEECH,
HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT: block_level, threshold = block_level,
HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT: block_level, ),
types.SafetySetting(
category = HarmCategory.HARM_CATEGORY_HARASSMENT,
threshold = block_level,
),
types.SafetySetting(
category = HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT,
threshold = block_level,
),
types.SafetySetting(
category = HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
threshold = block_level,
),
# There is a documentation conflict on whether or not # There is a documentation conflict on whether or not
# CIVIC_INTEGRITY is a valid category # CIVIC_INTEGRITY is a valid category
# HarmCategory.HARM_CATEGORY_CIVIC_INTEGRITY: block_level, # HarmCategory.HARM_CATEGORY_CIVIC_INTEGRITY: block_level,
} ]
self.llm = genai.GenerativeModel(
model_name=model,
generation_config=self.generation_config,
safety_settings=self.safety_settings,
system_instruction="You are a helpful AI assistant.",
)
print("Initialised", flush=True) print("Initialised", flush=True)
async def generate_content(self, system, prompt): async def generate_content(self, system, prompt):
# FIXME: There's a system prompt above. Maybe if system changes, generation_config = types.GenerateContentConfig(
# then reset self.llm? It shouldn't do, because system prompt temperature = self.temperature,
# is set system wide? top_p = 1,
top_k = 40,
# Or... could keep different LLM structures for different system max_output_tokens = self.max_output,
# prompts? response_mime_type = "text/plain",
system_instruction = system,
prompt = system + "\n\n" + prompt safety_settings = self.safety_settings,
)
try: try:
chat_session = self.llm.start_chat( response = self.client.models.generate_content(
history=[ model=self.model,
] config=generation_config,
contents=prompt,
) )
response = chat_session.send_message(prompt)
resp = response.text resp = response.text
inputtokens = int(response.usage_metadata.prompt_token_count) inputtokens = int(response.usage_metadata.prompt_token_count)
@ -158,3 +164,4 @@ class Processor(LlmService):
def run(): def run():
Processor.launch(default_ident, __doc__) Processor.launch(default_ident, __doc__)

View file

@ -0,0 +1,3 @@
from . llm import *

View file

@ -0,0 +1,7 @@
#!/usr/bin/env python3
from . llm import run
if __name__ == '__main__':
run()

View file

@ -0,0 +1,137 @@
"""
Simple LLM service, performs text prompt completion using HuggingFace TGI
Input is prompt, output is response.
"""
import os
import aiohttp
from .... exceptions import TooManyRequests
from .... base import LlmService, LlmResult
default_ident = "text-completion"
default_temperature = 0.0
default_max_output = 2048
default_base_url = os.getenv("TGI_BASE_URL")
if default_base_url == "" or default_base_url is None:
default_base_url = "http://tgi-service:8899/v1"
class Processor(LlmService):
def __init__(self, **params):
base_url = params.get("url", default_base_url)
temperature = params.get("temperature", default_temperature)
max_output = params.get("max_output", default_max_output)
super(Processor, self).__init__(
**params | {
"temperature": temperature,
"max_output": max_output,
"url": base_url,
}
)
self.base_url = base_url
self.temperature = temperature
self.max_output = max_output
self.session = aiohttp.ClientSession()
print("Using TGI service at", base_url)
print("Initialised", flush=True)
async def generate_content(self, system, prompt):
headers = {
"Content-Type": "application/json",
}
request = {
"model": "tgi",
"messages": [
{
"role": "system",
"content": system,
},
{
"role": "user",
"content": prompt,
}
],
"max_tokens": self.max_output,
"temperature": self.temperature,
}
try:
url = f"{self.base_url}/chat/completions"
async with self.session.post(
url,
headers=headers,
json=request,
) as response:
if response.status != 200:
raise RuntimeError("Bad status: " + str(response.status))
resp = await response.json()
inputtokens = resp["usage"]["prompt_tokens"]
outputtokens = resp["usage"]["completion_tokens"]
ans = resp["choices"][0]["message"]["content"]
print(f"Input Tokens: {inputtokens}", flush=True)
print(f"Output Tokens: {outputtokens}", flush=True)
print(ans, flush=True)
resp = LlmResult(
text = ans,
in_token = inputtokens,
out_token = outputtokens,
model = "tgi",
)
return resp
# FIXME: Assuming TGI won't produce rate limits?
except Exception as e:
# Apart from rate limits, treat all exceptions as unrecoverable
print(f"Exception: {type(e)} {e}")
raise e
@staticmethod
def add_args(parser):
LlmService.add_args(parser)
parser.add_argument(
'-u', '--url',
default=default_base_url,
help=f'TGI service base URL (default: {default_base_url})'
)
parser.add_argument(
'-t', '--temperature',
type=float,
default=default_temperature,
help=f'LLM temperature parameter (default: {default_temperature})'
)
parser.add_argument(
'-x', '--max-output',
type=int,
default=default_max_output,
help=f'LLM max output tokens (default: {default_max_output})'
)
def run():
Processor.launch(default_ident, __doc__)

View file

@ -34,7 +34,7 @@ setuptools.setup(
python_requires='>=3.8', python_requires='>=3.8',
download_url = "https://github.com/trustgraph-ai/trustgraph/archive/refs/tags/v" + version + ".tar.gz", download_url = "https://github.com/trustgraph-ai/trustgraph/archive/refs/tags/v" + version + ".tar.gz",
install_requires=[ install_requires=[
"trustgraph-base>=0.23,<0.24", "trustgraph-base>=1.0,<1.1",
"pulsar-client", "pulsar-client",
"prometheus-client", "prometheus-client",
"boto3", "boto3",

View file

@ -34,7 +34,7 @@ setuptools.setup(
python_requires='>=3.8', python_requires='>=3.8',
download_url = "https://github.com/trustgraph-ai/trustgraph/archive/refs/tags/v" + version + ".tar.gz", download_url = "https://github.com/trustgraph-ai/trustgraph/archive/refs/tags/v" + version + ".tar.gz",
install_requires=[ install_requires=[
"trustgraph-base>=0.23,<0.24", "trustgraph-base>=1.0,<1.1",
"pulsar-client", "pulsar-client",
"google-cloud-aiplatform", "google-cloud-aiplatform",
"prometheus-client", "prometheus-client",

View file

@ -4,13 +4,26 @@ Simple LLM service, performs text prompt completion using VertexAI on
Google Cloud. Input is prompt, output is response. Google Cloud. Input is prompt, output is response.
""" """
#
# Somewhat perplexed by the Google Cloud SDK choices. We're going off this
# one, which uses the google-cloud-aiplatform library:
# https://cloud.google.com/python/docs/reference/vertexai/1.94.0
# It seems it is possible to invoke VertexAI from the google-genai
# SDK too:
# https://googleapis.github.io/python-genai/genai.html#module-genai.client
# That would make this code look very much like the GoogleAIStudio
# code. And maybe not reliant on the google-cloud-aiplatform library?
#
# This module's imports bring in a lot of libraries.
from google.oauth2 import service_account from google.oauth2 import service_account
import google import google
import vertexai import vertexai
from vertexai.preview.generative_models import ( # Why is preview here?
from vertexai.generative_models import (
Content, FunctionDeclaration, GenerativeModel, GenerationConfig, Content, FunctionDeclaration, GenerativeModel, GenerationConfig,
HarmCategory, HarmBlockThreshold, Part, Tool, HarmCategory, HarmBlockThreshold, Part, Tool, SafetySetting,
) )
from .... exceptions import TooManyRequests from .... exceptions import TooManyRequests
@ -18,7 +31,7 @@ from .... base import LlmService, LlmResult
default_ident = "text-completion" default_ident = "text-completion"
default_model = 'gemini-1.0-pro-001' default_model = 'gemini-2.0-flash-001'
default_region = 'us-central1' default_region = 'us-central1'
default_temperature = 0.0 default_temperature = 0.0
default_max_output = 8192 default_max_output = 8192
@ -59,12 +72,24 @@ class Processor(LlmService):
block_level = HarmBlockThreshold.BLOCK_ONLY_HIGH block_level = HarmBlockThreshold.BLOCK_ONLY_HIGH
# block_level = HarmBlockThreshold.BLOCK_NONE # block_level = HarmBlockThreshold.BLOCK_NONE
self.safety_settings = { self.safety_settings = [
HarmCategory.HARM_CATEGORY_HARASSMENT: block_level, SafetySetting(
HarmCategory.HARM_CATEGORY_HATE_SPEECH: block_level, category = HarmCategory.HARM_CATEGORY_HARASSMENT,
HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT: block_level, threshold = block_level,
HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT: block_level, ),
} SafetySetting(
category = HarmCategory.HARM_CATEGORY_HATE_SPEECH,
threshold = block_level,
),
SafetySetting(
category = HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT,
threshold = block_level,
),
SafetySetting(
category = HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
threshold = block_level,
),
]
print("Initialise VertexAI...", flush=True) print("Initialise VertexAI...", flush=True)
@ -101,8 +126,8 @@ class Processor(LlmService):
prompt = system + "\n\n" + prompt prompt = system + "\n\n" + prompt
response = self.llm.generate_content( response = self.llm.generate_content(
prompt, generation_config=self.generation_config, prompt, generation_config = self.generation_config,
safety_settings=self.safety_settings safety_settings = self.safety_settings,
) )
resp = LlmResult( resp = LlmResult(

View file

@ -34,12 +34,12 @@ setuptools.setup(
python_requires='>=3.8', python_requires='>=3.8',
download_url = "https://github.com/trustgraph-ai/trustgraph/archive/refs/tags/v" + version + ".tar.gz", download_url = "https://github.com/trustgraph-ai/trustgraph/archive/refs/tags/v" + version + ".tar.gz",
install_requires=[ install_requires=[
"trustgraph-base>=0.23,<0.24", "trustgraph-base>=1.0,<1.1",
"trustgraph-bedrock>=0.23,<0.24", "trustgraph-bedrock>=1.0,<1.1",
"trustgraph-cli>=0.23,<0.24", "trustgraph-cli>=1.0,<1.1",
"trustgraph-embeddings-hf>=0.23,<0.24", "trustgraph-embeddings-hf>=1.0,<1.1",
"trustgraph-flow>=0.23,<0.24", "trustgraph-flow>=1.0,<1.1",
"trustgraph-vertexai>=0.23,<0.24", "trustgraph-vertexai>=1.0,<1.1",
], ],
scripts=[ scripts=[
] ]