Defs extraction working?

This commit is contained in:
Cyber MacGeddon 2025-04-18 09:21:21 +01:00
parent 8b24fa4209
commit 4bbd050d05
4 changed files with 106 additions and 93 deletions

View file

@ -6,9 +6,8 @@ from . producer import Producer
from . publisher import Publisher from . publisher import Publisher
from . subscriber import Subscriber from . subscriber import Subscriber
from . metrics import ProcessorMetrics, ConsumerMetrics, ProducerMetrics from . metrics import ProcessorMetrics, ConsumerMetrics, ProducerMetrics
from . flow_processor import FlowProcessor, SubscriberSpec, ProducerSpec from . flow_processor import FlowProcessor
from . flow_processor import ConsumerSpec, SettingSpec from . flow_processor import ConsumerSpec, SettingSpec
from . flow_processor import SubscriberSpec, ProducerSpec
from . request_response import RequestResponseService from . request_response import RequestResponseService

View file

@ -5,84 +5,74 @@ get entity definitions which are output as graph edges along with
entity/context definitions for embedding. entity/context definitions for embedding.
""" """
import json
import asyncio
import urllib.parse import urllib.parse
from pulsar.schema import JsonSchema from pulsar.schema import JsonSchema
import uuid
from .... schema import Chunk, Triple, Triples, Metadata, Value from .... schema import Chunk, Triple, Triples, Metadata, Value
from .... schema import EntityContext, EntityContexts from .... schema import EntityContext, EntityContexts
from .... schema import chunk_ingest_queue, triples_store_queue from .... schema import PromptRequest, PromptResponse
from .... schema import entity_contexts_ingest_queue
from .... schema import prompt_request_queue
from .... schema import prompt_response_queue
from .... log_level import LogLevel from .... log_level import LogLevel
from .... clients.prompt_client import PromptClient from .... clients.prompt_client import PromptClient
from .... rdf import TRUSTGRAPH_ENTITIES, DEFINITION, RDF_LABEL, SUBJECT_OF from .... rdf import TRUSTGRAPH_ENTITIES, DEFINITION, RDF_LABEL, SUBJECT_OF
from .... base import ConsumerProducer
from .... base import FlowProcessor, SubscriberSpec, ConsumerSpec
from .... base import ProducerSpec
DEFINITION_VALUE = Value(value=DEFINITION, is_uri=True) DEFINITION_VALUE = Value(value=DEFINITION, is_uri=True)
RDF_LABEL_VALUE = Value(value=RDF_LABEL, is_uri=True) RDF_LABEL_VALUE = Value(value=RDF_LABEL, is_uri=True)
SUBJECT_OF_VALUE = Value(value=SUBJECT_OF, is_uri=True) SUBJECT_OF_VALUE = Value(value=SUBJECT_OF, is_uri=True)
module = "kg-extract-definitions" default_ident = "kg-extract-definitions"
default_input_queue = chunk_ingest_queue class Processor(FlowProcessor):
default_output_queue = triples_store_queue
default_entity_context_queue = entity_contexts_ingest_queue
default_subscriber = module
class Processor(ConsumerProducer):
def __init__(self, **params): def __init__(self, **params):
input_queue = params.get("input_queue", default_input_queue) id = params.get("id")
output_queue = params.get("output_queue", default_output_queue)
ec_queue = params.get(
"entity_context_queue",
default_entity_context_queue
)
subscriber = params.get("subscriber", default_subscriber)
pr_request_queue = params.get(
"prompt_request_queue", prompt_request_queue
)
pr_response_queue = params.get(
"prompt_response_queue", prompt_response_queue
)
super(Processor, self).__init__( super(Processor, self).__init__(
**params | { **params | {
"input_queue": input_queue, "id": id,
"output_queue": output_queue,
"subscriber": subscriber,
"input_schema": Chunk,
"output_schema": Triples,
"prompt_request_queue": pr_request_queue,
"prompt_response_queue": pr_response_queue,
} }
) )
self.ec_prod = self.client.create_producer( self.register_specification(
topic=ec_queue, ConsumerSpec(
schema=JsonSchema(EntityContexts), name = "input",
schema = Chunk,
handler = self.on_message
)
) )
__class__.pubsub_metric.info({ self.register_specification(
"input_queue": input_queue, ProducerSpec(
"output_queue": output_queue, name = "prompt-request",
"entity_context_queue": ec_queue, schema = PromptRequest
"prompt_request_queue": pr_request_queue, )
"prompt_response_queue": pr_response_queue, )
"subscriber": subscriber,
"input_schema": Chunk.__name__,
"output_schema": Triples.__name__,
"vector_schema": EntityContexts.__name__,
})
self.prompt = PromptClient( self.register_specification(
pulsar_host=self.pulsar_host, SubscriberSpec(
pulsar_api_key=self.pulsar_api_key, name = "prompt-response",
input_queue=pr_request_queue, schema = PromptResponse,
output_queue=pr_response_queue, )
subscriber = module + "-prompt", )
self.register_specification(
ProducerSpec(
name = "triples",
schema = Triples
)
)
self.register_specification(
ProducerSpec(
name = "entity-contexts",
schema = EntityContexts
)
) )
def to_uri(self, text): def to_uri(self, text):
@ -97,32 +87,71 @@ class Processor(ConsumerProducer):
return self.prompt.request_definitions(chunk) return self.prompt.request_definitions(chunk)
async def emit_edges(self, metadata, triples): async def emit_triples(self, pub, metadata, triples):
t = Triples( t = Triples(
metadata=metadata, metadata=metadata,
triples=triples, triples=triples,
) )
await self.send(t) await pub.send(t)
async def emit_ecs(self, metadata, entities): async def emit_ecs(self, pub, metadata, entities):
t = EntityContexts( t = EntityContexts(
metadata=metadata, metadata=metadata,
entities=entities, entities=entities,
) )
self.ec_prod.send(t) await pub.send(t)
async def handle(self, msg): async def on_message(self, msg, consumer, flow):
id = str(uuid.uuid4())
v = msg.value() v = msg.value()
print(f"Indexing {v.metadata.id}...", flush=True) print(f"Indexing {v.metadata.id}...", flush=True)
chunk = v.chunk.decode("utf-8") chunk = v.chunk.decode("utf-8")
print(chunk, flush=True)
try: try:
defs = self.get_definitions(chunk) q = await flow.consumer["prompt-response"].subscribe(id)
try:
await flow.producer["prompt-request"].send(
PromptRequest(
id="extract-definitions",
terms={
"text": json.dumps(chunk)
},
),
properties={"id": id}
)
# FIXME: hard-coded?
resp = await asyncio.wait_for(
q.get(),
timeout=600
)
print("Response", resp, flush=True)
if resp.error is not None:
print("Error:", resp.error.message, flush=True)
raise RuntimeError(resp.error.message)
if resp.object is None:
raise RuntimeError("Expecting object in prompt response")
defs = json.loads(resp.object)
except Exception as e:
print("Prompt exception:", e, flush=True)
raise e
finally:
await flow.consumer["prompt-response"].unsubscribe(id)
triples = [] triples = []
entities = [] entities = []
@ -134,8 +163,8 @@ class Processor(ConsumerProducer):
for defn in defs: for defn in defs:
s = defn.name s = defn["entity"]
o = defn.definition o = defn["definition"]
if s == "": continue if s == "": continue
if o == "": continue if o == "": continue
@ -166,13 +195,13 @@ class Processor(ConsumerProducer):
ec = EntityContext( ec = EntityContext(
entity=s_value, entity=s_value,
context=defn.definition, context=defn["definition"],
) )
entities.append(ec) entities.append(ec)
await self.emit_edges( await self.emit_triples(
flow.producer["triples"],
Metadata( Metadata(
id=v.metadata.id, id=v.metadata.id,
metadata=[], metadata=[],
@ -183,6 +212,7 @@ class Processor(ConsumerProducer):
) )
await self.emit_ecs( await self.emit_ecs(
flow.producer["entity-contexts"],
Metadata( Metadata(
id=v.metadata.id, id=v.metadata.id,
metadata=[], metadata=[],
@ -200,30 +230,9 @@ class Processor(ConsumerProducer):
@staticmethod @staticmethod
def add_args(parser): def add_args(parser):
ConsumerProducer.add_args( FlowProcessor.add_args(parser)
parser, default_input_queue, default_subscriber,
default_output_queue,
)
parser.add_argument(
'-e', '--entity-context-queue',
default=default_entity_context_queue,
help=f'Entity context queue (default: {default_entity_context_queue})'
)
parser.add_argument(
'--prompt-request-queue',
default=prompt_request_queue,
help=f'Prompt request queue (default: {prompt_request_queue})',
)
parser.add_argument(
'--prompt-completion-response-queue',
default=prompt_response_queue,
help=f'Prompt response queue (default: {prompt_response_queue})',
)
def run(): def run():
Processor.launch(module, __doc__) Processor.launch(default_ident, __doc__)

View file

@ -53,6 +53,8 @@ class PromptManager:
async def invoke(self, id, input, llm): async def invoke(self, id, input, llm):
print("Invoke...", flush=True)
if id not in self.prompts: if id not in self.prompts:
raise RuntimeError("ID invalid") raise RuntimeError("ID invalid")
@ -76,12 +78,13 @@ class PromptManager:
try: try:
obj = self.parse_json(resp) obj = self.parse_json(resp)
except: except:
print("Parse fail:", resp, flush=True)
raise RuntimeError("JSON parse fail") raise RuntimeError("JSON parse fail")
if self.prompts[id].schema: if self.prompts[id].schema:
try: try:
print(self.prompts[id].schema, flush=True)
validate(instance=obj, schema=self.prompts[id].schema) validate(instance=obj, schema=self.prompts[id].schema)
print("Validated", flush=True)
except Exception as e: except Exception as e:
raise RuntimeError(f"Schema validation fail: {e}") raise RuntimeError(f"Schema validation fail: {e}")

View file

@ -11,8 +11,9 @@ from .... schema import Definition, Relationship, Triple
from .... schema import Topic from .... schema import Topic
from .... schema import PromptRequest, PromptResponse, Error from .... schema import PromptRequest, PromptResponse, Error
from .... schema import TextCompletionRequest, TextCompletionResponse from .... schema import TextCompletionRequest, TextCompletionResponse
from .... base import FlowProcessor, SubscriberSpec, ConsumerSpec
from .... base import ProducerSpec from .... base import FlowProcessor
from .... base import ProducerSpec, SubscriberSpec, ConsumerSpec
from . prompt_manager import PromptConfiguration, Prompt, PromptManager from . prompt_manager import PromptConfiguration, Prompt, PromptManager
@ -172,10 +173,11 @@ class Processor(FlowProcessor):
finally: finally:
await flow.consumer["text-completion-response"].unsubscribe(id) await flow.consumer["text-completion-response"].unsubscribe(id)
print(resp, flush=True)
if isinstance(resp, str): if isinstance(resp, str):
print("Send text response...", flush=True) print("Send text response...", flush=True)
print(resp, flush=True)
r = PromptResponse( r = PromptResponse(
text=resp, text=resp,