From bd1fabf46e9ec669839b37efc32e99161918bdf7 Mon Sep 17 00:00:00 2001 From: Thomas Howe Date: Thu, 18 Sep 2025 18:15:12 -0400 Subject: [PATCH] Add vCon library API reference and update LLM guide Added a comprehensive API reference for the vCon library in API_REFERENCE.md, detailing classes, methods, constants, and usage examples. Updated LLM_GUIDE.md to expand on vCon 0.3.0 features, including advanced party attributes, dialog types, extensions, civic address, party history, multimedia handling, security, validation, and best practices for LLM integration. --- API_REFERENCE.md | 975 +++++++++++++++++++++++++++++++++++++++++++++++ LLM_GUIDE.md | 607 +++++++++++++++++++++++++++-- 2 files changed, 1555 insertions(+), 27 deletions(-) create mode 100644 API_REFERENCE.md diff --git a/API_REFERENCE.md b/API_REFERENCE.md new file mode 100644 index 0000000..7dcde77 --- /dev/null +++ b/API_REFERENCE.md @@ -0,0 +1,975 @@ +# vCon Library API Reference + +Complete API documentation for the vCon library - a Python implementation of the vCon 0.3.0 specification for Virtual Conversation objects. + +## Table of Contents + +- [Overview](#overview) +- [Installation](#installation) +- [Core Classes](#core-classes) + - [Vcon](#vcon-class) + - [Party](#party-class) + - [Dialog](#dialog-class) + - [CivicAddress](#civicaddress-class) + - [PartyHistory](#partyhistory-class) + - [Attachment](#attachment-class) +- [Constants](#constants) +- [Examples](#examples) + +## Overview + +The vCon library provides a complete Python implementation of the vCon 0.3.0 specification for representing virtual conversations. It supports all features including parties, dialogs, attachments, analysis, digital signatures, and extensibility. + +## Installation + +```bash +pip install vcon +``` + +For image processing support: +```bash +pip install vcon[image] +``` + +## Core Classes + +### Vcon Class + +The main class for working with vCon objects. + +#### Constructor + +```python +Vcon(vcon_dict: Dict[str, Any] = None, property_handling: str = "default", strict_version: bool = False) +``` + +**Parameters:** +- `vcon_dict` (Dict[str, Any], optional): Dictionary representing a vCon. Defaults to empty dict. +- `property_handling` (str): How to handle non-standard properties: + - `"default"`: Keep non-standard properties (default) + - `"strict"`: Remove non-standard properties + - `"meta"`: Move non-standard properties to meta object +- `strict_version` (bool): If True, reject vCons not at version "0.3.0". Defaults to False. + +#### Class Methods + +##### `build_new() -> Vcon` +Create a new vCon object with default values. + +```python +vcon = Vcon.build_new() +``` + +##### `build_from_json(json_str: str, property_handling: str = "default", strict_version: bool = False) -> Vcon` +Create a vCon object from JSON string. + +```python +vcon = Vcon.build_from_json('{"uuid": "123", "vcon": "0.3.0"}') +``` + +##### `load(file_path_or_url: str, property_handling: str = "default", strict_version: bool = False) -> Vcon` +Load a vCon from file or URL. + +```python +# From file +vcon = Vcon.load("conversation.vcon.json") + +# From URL +vcon = Vcon.load("https://example.com/conversation.vcon.json") +``` + +##### `load_from_file(file_path: str, property_handling: str = "default", strict_version: bool = False) -> Vcon` +Load a vCon from a local file. + +##### `load_from_url(url: str, property_handling: str = "default", strict_version: bool = False) -> Vcon` +Load a vCon from a URL. + +##### `validate_file(file_path: str) -> Tuple[bool, List[str]]` +Validate a vCon file. + +```python +is_valid, errors = Vcon.validate_file("conversation.vcon.json") +``` + +##### `validate_json(json_str: str) -> Tuple[bool, List[str]]` +Validate a vCon JSON string. + +##### `generate_key_pair() -> Tuple[rsa.RSAPrivateKey, rsa.RSAPublicKey]` +Generate RSA key pair for digital signatures. + +```python +private_key, public_key = Vcon.generate_key_pair() +``` + +##### `uuid8_domain_name(domain_name: str) -> str` +Generate UUID8 with domain name. + +##### `uuid8_time(custom_c_62_bits: int) -> str` +Generate UUID8 with custom time bits. + +#### Instance Methods + +##### Party Management + +###### `add_party(party: Party) -> None` +Add a party to the vCon. + +```python +party = Party(tel="+1234567890", name="Alice", role="caller") +vcon.add_party(party) +``` + +###### `find_party_index(by: str, val: str) -> Optional[int]` +Find party index by field value. + +```python +index = vcon.find_party_index("tel", "+1234567890") +``` + +##### Dialog Management + +###### `add_dialog(dialog: Dialog) -> None` +Add a dialog to the vCon. + +```python +dialog = Dialog(type="text", start=datetime.now(), parties=[0, 1], body="Hello") +vcon.add_dialog(dialog) +``` + +###### `find_dialog(by: str, val: str) -> Optional[Dialog]` +Find dialog by field value. + +```python +dialog = vcon.find_dialog("type", "text") +``` + +###### `find_dialogs_by_type(type: str) -> List[Dict[str, Any]]` +Find all dialogs of a specific type. + +```python +text_dialogs = vcon.find_dialogs_by_type("text") +``` + +###### `add_transfer_dialog(start: Union[datetime, str], transfer_data: Dict[str, Any], parties: List[int]) -> None` +Add a transfer dialog. + +```python +transfer_data = { + "transferee": 0, + "transferor": 1, + "transfer_target": 2 +} +vcon.add_transfer_dialog(datetime.now(), transfer_data, [0, 1, 2]) +``` + +###### `add_incomplete_dialog(start: Union[datetime, str], disposition: str, parties: List[int]) -> None` +Add an incomplete dialog. + +```python +vcon.add_incomplete_dialog(datetime.now(), "no-answer", [0]) +``` + +##### Attachment Management + +###### `add_attachment(type: str, body: Any, encoding: str = "none") -> Attachment` +Add an attachment to the vCon. + +```python +attachment = vcon.add_attachment("transcript", "Full conversation...", "none") +``` + +###### `add_image(image_path: str, type: str = "image") -> Attachment` +Add an image attachment from file. + +```python +attachment = vcon.add_image("screenshot.png", "screenshot") +``` + +###### `find_attachment_by_type(type: str) -> Optional[Dict[str, Any]]` +Find attachment by type. + +```python +transcript = vcon.find_attachment_by_type("transcript") +``` + +##### Analysis Management + +###### `add_analysis(type: str, dialog: Union[int, List[int]], vendor: str, body: Any, encoding: str = "none") -> None` +Add analysis data to the vCon. + +```python +vcon.add_analysis( + type="sentiment", + dialog=[0, 1], + vendor="SentimentAnalyzer", + body={"sentiment": "positive", "confidence": 0.85}, + encoding="json" +) +``` + +###### `find_analysis_by_type(type: str) -> Optional[Dict[str, Any]]` +Find analysis by type. + +```python +sentiment = vcon.find_analysis_by_type("sentiment") +``` + +##### Tag Management + +###### `add_tag(tag_name: str, tag_value: str) -> None` +Add a tag to the vCon. + +```python +vcon.add_tag("customer_id", "12345") +``` + +###### `get_tag(tag_name: str) -> Optional[str]` +Get a tag value. + +```python +customer_id = vcon.get_tag("customer_id") +``` + +##### Extension Management + +###### `add_extension(extension: str) -> None` +Add an extension to the vCon. + +```python +vcon.add_extension("video") +``` + +###### `get_extensions() -> List[str]` +Get list of extensions. + +```python +extensions = vcon.get_extensions() +``` + +###### `remove_extension(extension: str) -> None` +Remove an extension. + +```python +vcon.remove_extension("video") +``` + +###### `add_must_support(extension: str) -> None` +Add a must-support extension. + +```python +vcon.add_must_support("encryption") +``` + +###### `get_must_support() -> List[str]` +Get list of must-support extensions. + +```python +must_support = vcon.get_must_support() +``` + +###### `remove_must_support(extension: str) -> None` +Remove a must-support extension. + +##### Security + +###### `sign(private_key: Union[rsa.RSAPrivateKey, bytes]) -> None` +Sign the vCon with a private key. + +```python +vcon.sign(private_key) +``` + +###### `verify(public_key: Union[rsa.RSAPublicKey, bytes]) -> bool` +Verify the vCon signature. + +```python +is_valid = vcon.verify(public_key) +``` + +##### Validation + +###### `is_valid() -> Tuple[bool, List[str]]` +Validate the vCon object. + +```python +is_valid, errors = vcon.is_valid() +``` + +##### Serialization + +###### `to_json() -> str` +Convert vCon to JSON string. + +```python +json_str = vcon.to_json() +``` + +###### `to_dict() -> Dict[str, Any]` +Convert vCon to dictionary. + +```python +vcon_dict = vcon.to_dict() +``` + +###### `dumps() -> str` +Alias for `to_json()`. + +###### `save_to_file(file_path: str) -> None` +Save vCon to file. + +```python +vcon.save_to_file("conversation.vcon.json") +``` + +##### HTTP Operations + +###### `post_to_url(url: str, headers: Optional[Dict[str, str]] = None) -> requests.Response` +Post vCon to URL. + +```python +response = vcon.post_to_url("https://api.example.com/vcon", headers={"Authorization": "Bearer token"}) +``` + +##### Timestamp Management + +###### `set_created_at(created_at: Union[str, datetime]) -> None` +Set the creation timestamp. + +###### `set_updated_at(timestamp: Union[str, datetime]) -> None` +Set the update timestamp. + +#### Properties + +##### `uuid -> str` +Get the vCon UUID. + +##### `vcon -> str` +Get the vCon version. + +##### `subject -> Optional[str]` +Get the vCon subject. + +##### `created_at` +Get the creation timestamp. + +##### `updated_at` +Get the update timestamp. + +##### `redacted` +Get the redacted flag. + +##### `appended` +Get the appended flag. + +##### `group` +Get the group information. + +##### `meta` +Get the metadata. + +##### `parties -> List[Party]` +Get list of parties. + +##### `dialog -> List[Dict[str, Any]]` +Get list of dialogs. + +##### `attachments -> List[Dict[str, Any]]` +Get list of attachments. + +##### `analysis -> List[Dict[str, Any]]` +Get list of analysis data. + +##### `tags -> Optional[Dict[str, Any]]` +Get all tags. + +### Party Class + +Represents a participant in a vCon conversation. + +#### Constructor + +```python +Party( + tel: Optional[str] = None, + stir: Optional[str] = None, + mailto: Optional[str] = None, + name: Optional[str] = None, + validation: Optional[str] = None, + gmlpos: Optional[str] = None, + civicaddress: Optional[CivicAddress] = None, + uuid: Optional[str] = None, + role: Optional[str] = None, + contact_list: Optional[str] = None, + meta: Optional[dict] = None, + sip: Optional[str] = None, + did: Optional[str] = None, + jCard: Optional[dict] = None, + timezone: Optional[str] = None, + **kwargs +) +``` + +**Parameters:** +- `tel` (str, optional): Telephone number +- `stir` (str, optional): STIR identifier +- `mailto` (str, optional): Email address +- `name` (str, optional): Display name +- `validation` (str, optional): Validation information +- `gmlpos` (str, optional): GML position coordinates +- `civicaddress` (CivicAddress, optional): Civic address information +- `uuid` (str, optional): Unique identifier +- `role` (str, optional): Role in conversation (e.g., "caller", "agent") +- `contact_list` (str, optional): Contact list reference +- `meta` (dict, optional): Additional metadata +- `sip` (str, optional): SIP URI for VoIP communication +- `did` (str, optional): Decentralized Identifier +- `jCard` (dict, optional): vCard format contact information +- `timezone` (str, optional): Party's timezone + +#### Methods + +##### `to_dict() -> Dict[str, Any]` +Convert Party to dictionary. + +```python +party_dict = party.to_dict() +``` + +### Dialog Class + +Represents a dialog segment in a vCon conversation. + +#### Constructor + +```python +Dialog( + type: str, + start: Union[datetime, str], + parties: List[int], + originator: Optional[int] = None, + mimetype: Optional[str] = None, + filename: Optional[str] = None, + body: Optional[str] = None, + encoding: Optional[str] = None, + url: Optional[str] = None, + alg: Optional[str] = None, + signature: Optional[str] = None, + disposition: Optional[str] = None, + party_history: Optional[List[PartyHistory]] = None, + transferee: Optional[int] = None, + transferor: Optional[int] = None, + transfer_target: Optional[int] = None, + original: Optional[int] = None, + consultation: Optional[int] = None, + target_dialog: Optional[int] = None, + campaign: Optional[str] = None, + interaction: Optional[str] = None, + skill: Optional[str] = None, + duration: Optional[float] = None, + meta: Optional[dict] = None, + metadata: Optional[Dict[str, Any]] = None, + transfer: Optional[Dict[str, Any]] = None, + signaling: Optional[Dict[str, Any]] = None, + resolution: Optional[str] = None, + frame_rate: Optional[float] = None, + codec: Optional[str] = None, + bitrate: Optional[int] = None, + thumbnail: Optional[str] = None, + session_id: Optional[str] = None, + content_hash: Optional[str] = None, + application: Optional[str] = None, + message_id: Optional[str] = None, + **kwargs +) +``` + +**Parameters:** +- `type` (str): Dialog type ("text", "recording", "transfer", "incomplete", "audio", "video") +- `start` (Union[datetime, str]): Start time +- `parties` (List[int]): List of party indices +- `originator` (int, optional): Originator party index +- `mimetype` (str, optional): MIME type of content +- `filename` (str, optional): Filename +- `body` (str, optional): Content body +- `encoding` (str, optional): Content encoding +- `url` (str, optional): External URL +- `alg` (str, optional): Signature algorithm +- `signature` (str, optional): Content signature +- `disposition` (str, optional): Disposition for incomplete dialogs +- `party_history` (List[PartyHistory], optional): Party event history +- `transferee` (int, optional): Transferee party index +- `transferor` (int, optional): Transferor party index +- `transfer_target` (int, optional): Transfer target party index +- `original` (int, optional): Original dialog index +- `consultation` (int, optional): Consultation dialog index +- `target_dialog` (int, optional): Target dialog index +- `campaign` (str, optional): Campaign identifier +- `interaction` (str, optional): Interaction identifier +- `skill` (str, optional): Skill identifier +- `duration` (float, optional): Dialog duration +- `meta` (dict, optional): Additional metadata +- `metadata` (Dict[str, Any], optional): Structured metadata +- `transfer` (Dict[str, Any], optional): Transfer-specific information +- `signaling` (Dict[str, Any], optional): Signaling information +- `resolution` (str, optional): Video resolution (e.g., "1920x1080") +- `frame_rate` (float, optional): Video frame rate +- `codec` (str, optional): Video codec +- `bitrate` (int, optional): Video bitrate +- `thumbnail` (str, optional): Base64-encoded thumbnail +- `session_id` (str, optional): Session identifier +- `content_hash` (str, optional): Content hash for external files +- `application` (str, optional): Application identifier +- `message_id` (str, optional): Message identifier + +#### Methods + +##### `to_dict() -> Dict[str, Any]` +Convert Dialog to dictionary. + +##### `add_external_data(url: str, filename: str, mimetype: str) -> None` +Add external data to dialog. + +##### `add_inline_data(body: str, filename: str, mimetype: str) -> None` +Add inline data to dialog. + +##### `is_external_data() -> bool` +Check if dialog has external data. + +##### `is_inline_data() -> bool` +Check if dialog has inline data. + +##### `is_text() -> bool` +Check if dialog is text type. + +##### `is_recording() -> bool` +Check if dialog is recording type. + +##### `is_transfer() -> bool` +Check if dialog is transfer type. + +##### `is_incomplete() -> bool` +Check if dialog is incomplete type. + +##### `is_audio() -> bool` +Check if dialog has audio content. + +##### `is_video(content_type: Optional[str] = None) -> bool` +Check if dialog has video content. + +##### `is_email() -> bool` +Check if dialog is email type. + +##### `is_image() -> bool` +Check if dialog has image content. + +##### `is_pdf() -> bool` +Check if dialog has PDF content. + +##### `add_video_data(video_data, filename: Optional[str] = None, mimetype: Optional[str] = None, inline: bool = True, metadata: Optional[dict] = None) -> None` +Add video data to dialog. + +##### `extract_video_metadata(video_path: Optional[str] = None) -> dict` +Extract video metadata using FFmpeg. + +##### `generate_thumbnail(timestamp: float = 0.0, width: int = 320, height: int = 240, quality: int = 90) -> bytes` +Generate video thumbnail. + +##### `add_streaming_video_reference(reference_id: str, mimetype: str, metadata: Optional[dict] = None) -> None` +Add streaming video reference. + +##### `add_video_with_optimal_storage(video_data, filename: str, mimetype: Optional[str] = None, size_threshold_mb: int = 10) -> None` +Add video with optimal storage method. + +##### `transcode_video(target_format: str, codec: Optional[str] = None, bit_rate: Optional[int] = None, width: Optional[int] = None, height: Optional[int] = None) -> None` +Transcode video to different format. + +##### `add_image_data(image_path: str, mimetype: Optional[str] = None) -> None` +Add image data from file. + +##### `extract_image_metadata(image_data: bytes, mimetype: str) -> None` +Extract image metadata. + +##### `generate_thumbnail(max_size: Tuple[int, int] = (200, 200)) -> Optional[str]` +Generate image thumbnail. + +##### `is_external_data_changed() -> bool` +Check if external data has changed. + +##### `to_inline_data() -> None` +Convert external data to inline data. + +##### `set_session_id(session_id: str) -> None` +Set session identifier. + +##### `get_session_id() -> Optional[str]` +Get session identifier. + +##### `set_content_hash(content_hash: str) -> None` +Set content hash. + +##### `get_content_hash() -> Optional[str]` +Get content hash. + +##### `calculate_content_hash(algorithm: str = "sha256") -> str` +Calculate content hash. + +##### `verify_content_hash(expected_hash: str, algorithm: str = "sha256") -> bool` +Verify content hash. + +### CivicAddress Class + +Represents civic address information according to GEOPRIV specification. + +#### Constructor + +```python +CivicAddress( + country: Optional[str] = None, + a1: Optional[str] = None, + a2: Optional[str] = None, + a3: Optional[str] = None, + a4: Optional[str] = None, + a5: Optional[str] = None, + a6: Optional[str] = None, + prd: Optional[str] = None, + pod: Optional[str] = None, + sts: Optional[str] = None, + hno: Optional[str] = None, + hns: Optional[str] = None, + lmk: Optional[str] = None, + loc: Optional[str] = None, + flr: Optional[str] = None, + nam: Optional[str] = None, + pc: Optional[str] = None +) +``` + +**Parameters:** +- `country` (str, optional): Country code (ISO 3166-1 alpha-2) +- `a1` (str, optional): Administrative area 1 (state/province) +- `a2` (str, optional): Administrative area 2 (county/municipality) +- `a3` (str, optional): Administrative area 3 (city/town) +- `a4` (str, optional): Administrative area 4 (neighborhood/district) +- `a5` (str, optional): Administrative area 5 (postal code) +- `a6` (str, optional): Administrative area 6 (building/floor) +- `prd` (str, optional): Premier (department/suite number) +- `pod` (str, optional): Post office box identifier +- `sts` (str, optional): Street name +- `hno` (str, optional): House number +- `hns` (str, optional): House name +- `lmk` (str, optional): Landmark name +- `loc` (str, optional): Location name +- `flr` (str, optional): Floor +- `nam` (str, optional): Name of location +- `pc` (str, optional): Postal code + +#### Methods + +##### `to_dict() -> Dict[str, Optional[str]]` +Convert CivicAddress to dictionary. + +### PartyHistory Class + +Represents party history events in a vCon dialog. + +#### Constructor + +```python +PartyHistory(party: int, event: str, time: datetime) +``` + +**Parameters:** +- `party` (int): Index of the party +- `event` (str): Event type ("join", "drop", "hold", "unhold", "mute", "unmute") +- `time` (datetime): Time of the event + +#### Methods + +##### `to_dict() -> Dict[str, Any]` +Convert PartyHistory to dictionary. + +### Attachment Class + +Represents an attachment in a vCon. + +#### Constructor + +```python +Attachment(type: str, body: Any, encoding: str = "none") +``` + +**Parameters:** +- `type` (str): Type of attachment +- `body` (Any): Content of attachment +- `encoding` (str): Encoding format ("base64", "base64url", "none") + +#### Methods + +##### `to_dict() -> Dict[str, Any]` +Convert Attachment to dictionary. + +##### `from_image(image_path: str, type: str = "image") -> 'Attachment'` +Create attachment from image file. + +## Constants + +### Property Handling Modes + +```python +PROPERTY_HANDLING_DEFAULT = "default" # Keep non-standard properties +PROPERTY_HANDLING_STRICT = "strict" # Remove non-standard properties +PROPERTY_HANDLING_META = "meta" # Move non-standard properties to meta +``` + +### Dialog Types + +```python +VALID_TYPES = ["recording", "text", "transfer", "incomplete", "audio", "video"] +``` + +### Disposition Values + +```python +VALID_DISPOSITIONS = [ + "no-answer", "congestion", "failed", "busy", + "hung-up", "voicemail-no-message" +] +``` + +### Party History Events + +```python +VALID_EVENTS = ["join", "drop", "hold", "unhold", "mute", "unmute"] +``` + +### Attachment Encodings + +```python +VALID_ENCODINGS = ["base64", "base64url", "none"] +``` + +### Supported MIME Types + +```python +MIME_TYPES = [ + "text/plain", + "audio/x-wav", "audio/wav", "audio/wave", "audio/mpeg", "audio/mp3", + "audio/x-mp3", "audio/x-mp4", "audio/ogg", "audio/webm", "audio/x-m4a", "audio/aac", + "video/x-mp4", "video/ogg", "video/mp4", "video/quicktime", "video/webm", + "video/x-msvideo", "video/x-matroska", "video/mpeg", "video/x-flv", "video/3gpp", "video/x-m4v", + "multipart/mixed", "message/rfc822", + "image/jpeg", "image/tiff", "application/pdf", "application/json" +] +``` + +## Examples + +### Basic vCon Creation + +```python +from vcon import Vcon +from vcon.party import Party +from vcon.dialog import Dialog +from datetime import datetime + +# Create new vCon +vcon = Vcon.build_new() + +# Add parties +caller = Party(tel="+1234567890", name="Alice", role="caller") +agent = Party(tel="+1987654321", name="Bob", role="agent") +vcon.add_party(caller) +vcon.add_party(agent) + +# Add dialog +dialog = Dialog( + type="text", + start=datetime.now(), + parties=[0, 1], + originator=0, + body="Hello, I need help with my account." +) +vcon.add_dialog(dialog) + +# Save to file +vcon.save_to_file("conversation.vcon.json") +``` + +### Loading and Validation + +```python +# Load vCon +vcon = Vcon.load("conversation.vcon.json") + +# Validate +is_valid, errors = vcon.is_valid() +if not is_valid: + print("Validation errors:", errors) + +# Access data +print(f"UUID: {vcon.uuid}") +print(f"Parties: {len(vcon.parties)}") +print(f"Dialogs: {len(vcon.dialog)}") +``` + +### Digital Signatures + +```python +# Generate key pair +private_key, public_key = Vcon.generate_key_pair() + +# Sign vCon +vcon.sign(private_key) + +# Verify signature +is_valid = vcon.verify(public_key) +print(f"Signature valid: {is_valid}") +``` + +### Extensions and Must-Support + +```python +# Add extensions +vcon.add_extension("video") +vcon.add_extension("encryption") + +# Add must-support +vcon.add_must_support("encryption") + +print(f"Extensions: {vcon.get_extensions()}") +print(f"Must support: {vcon.get_must_support()}") +``` + +### Analysis and Attachments + +```python +# Add analysis +vcon.add_analysis( + type="sentiment", + dialog=[0, 1], + vendor="SentimentAnalyzer", + body={"sentiment": "positive", "confidence": 0.85}, + encoding="json" +) + +# Add attachment +vcon.add_attachment( + type="transcript", + body="Full conversation transcript...", + encoding="none" +) + +# Add tags +vcon.add_tag("customer_id", "12345") +vcon.add_tag("priority", "high") +``` + +### Video Content + +```python +# Add video dialog +video_dialog = Dialog( + type="video", + start=datetime.now(), + parties=[0, 1], + mimetype="video/mp4", + resolution="1920x1080", + frame_rate=30.0, + codec="H.264" +) + +# Add video data +video_dialog.add_video_data( + video_data=binary_video_data, + filename="recording.mp4", + mimetype="video/mp4", + inline=True +) + +# Extract metadata +metadata = video_dialog.extract_video_metadata() + +# Generate thumbnail +thumbnail = video_dialog.generate_thumbnail(timestamp=10.0) + +vcon.add_dialog(video_dialog) +``` + +### Civic Address + +```python +from vcon.civic_address import CivicAddress + +# Create civic address +address = CivicAddress( + country="US", + a1="CA", + a3="San Francisco", + sts="Market Street", + hno="123", + pc="94102" +) + +# Add to party +party = Party( + name="Jane", + tel="+1555123456", + civicaddress=address +) +``` + +### Party History + +```python +from vcon.party import PartyHistory + +# Create party history +history = [ + PartyHistory(0, "join", datetime.now()), + PartyHistory(1, "join", datetime.now()), + PartyHistory(0, "hold", datetime.now()), + PartyHistory(0, "unhold", datetime.now()), + PartyHistory(1, "drop", datetime.now()) +] + +# Add to dialog +dialog = Dialog( + type="recording", + start=datetime.now(), + parties=[0, 1], + party_history=history +) +``` + +### HTTP Operations + +```python +# Post vCon to server +response = vcon.post_to_url( + "https://api.example.com/vcon", + headers={ + "Authorization": "Bearer your-token", + "Content-Type": "application/json" + } +) + +if response.status_code == 200: + print("Successfully posted vCon") +else: + print(f"Error: {response.status_code}") +``` + +### Property Handling + +```python +# Strict mode - remove non-standard properties +vcon = Vcon.load("file.json", property_handling="strict") + +# Meta mode - move non-standard properties to meta +vcon = Vcon.load("file.json", property_handling="meta") + +# Default mode - keep all properties +vcon = Vcon.load("file.json", property_handling="default") +``` + +This API reference covers all the main functionality of the vCon library. For more detailed examples and use cases, see the [Quickstart Guide](QUICKSTART.md) and the [samples directory](samples/). diff --git a/LLM_GUIDE.md b/LLM_GUIDE.md index 26380d9..87be55a 100644 --- a/LLM_GUIDE.md +++ b/LLM_GUIDE.md @@ -4,22 +4,41 @@ This guide provides a comprehensive overview of the vCon (Virtual Conversation) ## Overview -The vCon library is a Python tool for structuring, managing, and manipulating conversation data in a standardized format called vCon (Virtual Conversation). It enables the creation, validation, and manipulation of digital representations of conversations with rich metadata. +The vCon library is a Python implementation of the vCon 0.3.0 specification for structuring, managing, and manipulating conversation data in a standardized format. It enables the creation, validation, and manipulation of digital representations of conversations with rich metadata, supporting all modern conversation features including multimedia content, security, and extensibility. ### Key Concepts - **vCon Container**: The primary object that holds all conversation data -- **Parties**: Participants in a conversation (callers, agents, bots) -- **Dialogs**: Individual messages or segments of the conversation +- **Parties**: Participants in a conversation (callers, agents, bots) with contact information +- **Dialogs**: Individual messages or segments of the conversation (text, audio, video, etc.) - **Attachments**: Additional files or data associated with the conversation - **Analysis**: Results from processing the conversation (sentiment analysis, transcription, etc.) +- **Extensions**: Optional features that extend the base vCon functionality +- **Digital Signatures**: Cryptographic verification of vCon integrity +- **Civic Addresses**: Location information for parties using GEOPRIV standard +- **Party History**: Event tracking for multi-party conversations ## Installation ```bash +# Basic installation pip install vcon + +# With image processing support (Pillow, PyPDF) +pip install vcon[image] + +# From source +git clone https://github.com/vcon-dev/vcon-lib.git +cd vcon-lib +pip install -e . ``` +## Requirements + +- Python 3.12+ +- Core dependencies: authlib, uuid6, requests, pydash, python-dateutil +- Optional: mutagen (audio metadata), ffmpeg (video processing), Pillow (image processing), PyPDF (PDF processing) + ## Core Classes and Usage Patterns ### 1. Vcon Class @@ -104,16 +123,28 @@ party_index = vcon.find_party_index("name", "Alice Smith") # Returns index (0-b #### Party Attributes -- `tel`: Telephone number -- `name`: Display name -- `role`: Role in conversation (e.g., "caller", "agent") -- `mailto`: Email address -- `uuid`: Unique identifier -- `stir`: STIR verification +**Core Contact Information:** +- `tel`: Telephone number (e.g., "+1234567890") +- `name`: Display name (e.g., "Alice Smith") +- `role`: Role in conversation ("caller", "agent", "bot", etc.) +- `mailto`: Email address (e.g., "alice@example.com") + +**Advanced Contact Methods (vCon 0.3.0):** +- `sip`: SIP URI for VoIP communication (e.g., "sip:alice@example.com") +- `did`: Decentralized Identifier for blockchain-based identity +- `jCard`: vCard format contact information (RFC 7095) +- `timezone`: Party's timezone (e.g., "America/New_York") + +**Location and Validation:** +- `civicaddress`: Civic address using CivicAddress class (GEOPRIV format) +- `gmlpos`: GML position coordinates - `validation`: Validation status -- `gmlpos`: Geographic position -- `civicaddress`: Civic address (using CivicAddress class) -- `meta`: Additional metadata +- `stir`: STIR verification for secure telephony + +**Metadata:** +- `uuid`: Unique identifier for the party +- `contact_list`: Reference to contact list +- `meta`: Additional metadata dictionary - Custom attributes can be added via kwargs ### 3. Dialog Class @@ -191,20 +222,38 @@ is_video = dialog.is_video() is_email = dialog.is_email() ``` -#### Supported MIME Types +#### Dialog Types and MIME Types + +**Valid Dialog Types:** +- `"text"`: Text-based communication (chat, SMS, email) +- `"recording"`: Audio/video recording +- `"transfer"`: Call transfer operation +- `"incomplete"`: Failed or incomplete conversation setup +- `"audio"`: Audio content +- `"video"`: Video content +**Supported MIME Types:** + +**Text:** - `text/plain` + +**Audio:** - `audio/x-wav`, `audio/wav`, `audio/wave` -- `audio/mpeg`, `audio/mp3` -- `audio/ogg` -- `audio/webm` -- `audio/x-m4a` -- `audio/aac` -- `video/x-mp4` -- `video/ogg` +- `audio/mpeg`, `audio/mp3`, `audio/x-mp3` +- `audio/x-mp4`, `audio/ogg`, `audio/webm` +- `audio/x-m4a`, `audio/aac` + +**Video:** +- `video/x-mp4`, `video/mp4`, `video/ogg` +- `video/quicktime`, `video/webm` +- `video/x-msvideo`, `video/x-matroska` +- `video/mpeg`, `video/x-flv`, `video/3gpp`, `video/x-m4v` + +**Other:** - `multipart/mixed` - `message/rfc822` (for email) - `application/json` (for signaling data) +- `image/jpeg`, `image/tiff`, `application/pdf` ### 4. Working with Tags @@ -263,7 +312,126 @@ vcon.add_analysis( analysis = vcon.find_analysis_by_type("sentiment") ``` -## 7. Security and Validation +### 7. Extensions and Must-Support (vCon 0.3.0) + +Extensions allow vCons to declare optional features they use, while must-support indicates required features. + +```python +# Add extensions used in this vCon +vcon.add_extension("video") +vcon.add_extension("encryption") +vcon.add_extension("sentiment_analysis") + +# Add extensions that must be supported by consumers +vcon.add_must_support("encryption") +vcon.add_must_support("video") + +# Get extensions +extensions = vcon.get_extensions() # ['video', 'encryption', 'sentiment_analysis'] +must_support = vcon.get_must_support() # ['encryption', 'video'] + +# Remove extensions +vcon.remove_extension("sentiment_analysis") +vcon.remove_must_support("video") +``` + +### 8. Civic Address Support (vCon 0.3.0) + +Civic addresses provide location information for parties using the GEOPRIV standard. + +```python +from vcon.civic_address import CivicAddress + +# Create civic address +address = CivicAddress( + country="US", + a1="CA", # State + a3="San Francisco", # City + sts="Market Street", # Street + hno="123", # House number + pc="94102" # Postal code +) + +# Add to party +party = Party( + name="Jane Doe", + tel="+1555123456", + civicaddress=address +) + +# Convert to dictionary +address_dict = address.to_dict() +``` + +### 9. Party History Events (vCon 0.3.0) + +Track when parties join, leave, or change state during conversations. + +```python +from vcon.party import PartyHistory +from datetime import datetime + +# Create party history events +history = [ + PartyHistory(0, "join", datetime.now()), # Party 0 joins + PartyHistory(1, "join", datetime.now()), # Party 1 joins + PartyHistory(0, "hold", datetime.now()), # Party 0 on hold + PartyHistory(0, "unhold", datetime.now()), # Party 0 off hold + PartyHistory(1, "drop", datetime.now()) # Party 1 drops +] + +# Add to dialog +dialog = Dialog( + type="recording", + start=datetime.now(), + parties=[0, 1], + party_history=history +) + +# Valid event types: "join", "drop", "hold", "unhold", "mute", "unmute" +``` + +### 10. Advanced Dialog Features (vCon 0.3.0) + +New dialog fields for enhanced functionality. + +```python +# Dialog with session tracking and content hashing +dialog = Dialog( + type="text", + start=datetime.now(), + parties=[0, 1], + originator=0, + body="Hello, this is a test message!", + session_id="session-12345", + content_hash="c8d3d67f662a787e96e74ccb0a77803138c0f13495a186ccbde495c57c385608", + application="chat-app", + message_id="" +) + +# Video dialog with metadata +video_dialog = Dialog( + type="video", + start=datetime.now(), + parties=[0, 1], + mimetype="video/mp4", + resolution="1920x1080", + frame_rate=30.0, + codec="H.264", + bitrate=5000000, + filename="recording.mp4" +) + +# Incomplete dialog with disposition +incomplete_dialog = Dialog( + type="incomplete", + start=datetime.now(), + parties=[0], + disposition="no-answer" # Valid: no-answer, congestion, failed, busy, hung-up, voicemail-no-message +) +``` + +## 11. Security and Validation ### Signing and Verification @@ -388,6 +556,95 @@ if dialog.is_inline_data(): print("Dialog contains embedded content") ``` +### 4. Video Content Handling + +```python +# Add video data with metadata +video_dialog = Dialog( + type="video", + start=datetime.now(), + parties=[0, 1], + mimetype="video/mp4", + resolution="1920x1080", + frame_rate=30.0, + codec="H.264" +) + +# Add video data (inline or external) +video_dialog.add_video_data( + video_data=binary_video_data, # or URL string + filename="recording.mp4", + mimetype="video/mp4", + inline=True, # False for external reference + metadata={"duration": 120, "quality": "high"} +) + +# Extract video metadata using FFmpeg +metadata = video_dialog.extract_video_metadata() + +# Generate thumbnail +thumbnail_data = video_dialog.generate_thumbnail( + timestamp=10.0, # Time in seconds + width=320, + height=240, + quality=90 +) + +# Transcode video to different format +video_dialog.transcode_video( + target_format="webm", + codec="vp9", + bit_rate=2000000, + width=1280, + height=720 +) +``` + +### 5. Image Content Handling + +```python +# Add image data from file +image_dialog = Dialog( + type="text", # Can be any type + start=datetime.now(), + parties=[0, 1] +) + +# Add image from file +image_dialog.add_image_data( + image_path="screenshot.png", + mimetype="image/jpeg" # Optional, auto-detected if not provided +) + +# Generate thumbnail +thumbnail_b64 = image_dialog.generate_thumbnail(max_size=(200, 200)) + +# Check if dialog has image content +if image_dialog.is_image(): + print("Dialog contains image content") + +# Check for PDF content +if image_dialog.is_pdf(): + print("Dialog contains PDF content") +``` + +### 6. Content Hashing and Integrity + +```python +# Calculate content hash +content_hash = dialog.calculate_content_hash("sha256") + +# Set content hash for external files +dialog.set_content_hash(content_hash) + +# Verify content integrity +is_valid = dialog.verify_content_hash(expected_hash, "sha256") + +# Check if external data has changed +if dialog.is_external_data_changed(): + print("External content has been modified") +``` + ## Error Handling ```python @@ -419,13 +676,309 @@ vcon = Vcon(vcon_dict, property_handling="strict") vcon = Vcon(vcon_dict, property_handling="meta") ``` +## LLM-Specific Patterns and Best Practices + +### 1. Code Generation Templates + +When generating vCon code, use these templates as starting points: + +#### Basic Conversation Template +```python +from vcon import Vcon +from vcon.party import Party +from vcon.dialog import Dialog +from datetime import datetime + +def create_basic_conversation(): + # Create vCon + vcon = Vcon.build_new() + + # Add parties + caller = Party(tel="+1234567890", name="Caller", role="caller") + agent = Party(tel="+1987654321", name="Agent", role="agent") + vcon.add_party(caller) + vcon.add_party(agent) + + # Add conversation + vcon.add_dialog(Dialog( + type="text", + start=datetime.now().isoformat(), + parties=[0, 1], + originator=0, + body="Hello, I need help." + )) + + return vcon +``` + +#### Multimedia Conversation Template +```python +def create_multimedia_conversation(): + vcon = Vcon.build_new() + + # Add parties with enhanced contact info + caller = Party( + tel="+1234567890", + name="Alice", + role="caller", + mailto="alice@example.com", + timezone="America/New_York" + ) + agent = Party( + tel="+1987654321", + name="Bob", + role="agent", + sip="sip:bob@company.com" + ) + vcon.add_party(caller) + vcon.add_party(agent) + + # Add text dialog + vcon.add_dialog(Dialog( + type="text", + start=datetime.now().isoformat(), + parties=[0, 1], + originator=0, + body="Hello, I need help with my account." + )) + + # Add audio dialog + vcon.add_dialog(Dialog( + type="recording", + start=datetime.now().isoformat(), + parties=[0, 1], + mimetype="audio/mp3", + filename="conversation.mp3" + )) + + # Add analysis + vcon.add_analysis( + type="sentiment", + dialog=[0, 1], + vendor="SentimentAnalyzer", + body={"sentiment": "positive", "confidence": 0.85}, + encoding="json" + ) + + return vcon +``` + +### 2. Common LLM Tasks + +#### Converting Chat History to vCon +```python +def chat_to_vcon(chat_messages, participants): + vcon = Vcon.build_new() + + # Add participants as parties + party_map = {} + for i, participant in enumerate(participants): + party = Party( + name=participant.get("name", f"User {i}"), + role=participant.get("role", "participant") + ) + vcon.add_party(party) + party_map[participant["id"]] = i + + # Add messages as dialogs + for message in chat_messages: + vcon.add_dialog(Dialog( + type="text", + start=message["timestamp"], + parties=[party_map[message["sender_id"]]], + originator=party_map[message["sender_id"]], + body=message["content"] + )) + + return vcon +``` + +#### Adding AI Analysis to vCon +```python +def add_ai_analysis(vcon, analysis_type, results, dialog_indices=None): + if dialog_indices is None: + dialog_indices = list(range(len(vcon.dialog))) + + vcon.add_analysis( + type=analysis_type, + dialog=dialog_indices, + vendor="AI-Analyzer", + body=results, + encoding="json" + ) + + # Add extension if using AI features + vcon.add_extension("ai_analysis") +``` + +#### Extracting Conversation Data +```python +def extract_conversation_data(vcon): + data = { + "uuid": vcon.uuid, + "created_at": vcon.created_at, + "parties": [], + "dialogs": [], + "analysis": [] + } + + # Extract parties + for party in vcon.parties: + data["parties"].append({ + "name": getattr(party, "name", None), + "role": getattr(party, "role", None), + "tel": getattr(party, "tel", None) + }) + + # Extract dialogs + for dialog in vcon.dialog: + data["dialogs"].append({ + "type": dialog.get("type"), + "start": dialog.get("start"), + "body": dialog.get("body", "")[:100] + "..." if len(dialog.get("body", "")) > 100 else dialog.get("body", ""), + "parties": dialog.get("parties", []) + }) + + # Extract analysis + for analysis in vcon.analysis: + data["analysis"].append({ + "type": analysis.get("type"), + "vendor": analysis.get("vendor"), + "dialog_count": len(analysis.get("dialog", [])) + }) + + return data +``` + +### 3. Error Handling Patterns + +```python +def safe_vcon_operation(operation_func, *args, **kwargs): + """Safely execute vCon operations with proper error handling.""" + try: + return operation_func(*args, **kwargs) + except ValueError as e: + return {"error": f"Validation error: {str(e)}", "success": False} + except FileNotFoundError as e: + return {"error": f"File not found: {str(e)}", "success": False} + except Exception as e: + return {"error": f"Unexpected error: {str(e)}", "success": False} + +# Usage +result = safe_vcon_operation(Vcon.load, "conversation.json") +if not result.get("success", True): + print(f"Error: {result['error']}") +``` + +### 4. Validation Patterns + +```python +def validate_and_fix_vcon(vcon): + """Validate vCon and attempt to fix common issues.""" + is_valid, errors = vcon.is_valid() + + if is_valid: + return {"valid": True, "errors": []} + + fixes_applied = [] + + # Fix common issues + for error in errors: + if "missing uuid" in error.lower(): + # UUID is auto-generated, this shouldn't happen + pass + elif "invalid dialog type" in error.lower(): + # Try to fix invalid dialog types + for dialog in vcon.dialog: + if dialog.get("type") not in ["text", "recording", "transfer", "incomplete", "audio", "video"]: + dialog["type"] = "text" # Default to text + fixes_applied.append(f"Fixed invalid dialog type: {dialog.get('type')}") + + # Re-validate after fixes + is_valid, remaining_errors = vcon.is_valid() + + return { + "valid": is_valid, + "errors": remaining_errors, + "fixes_applied": fixes_applied + } +``` + +### 5. Integration Patterns + +#### REST API Integration +```python +def vcon_to_api_payload(vcon): + """Convert vCon to API payload format.""" + return { + "vcon": vcon.to_dict(), + "metadata": { + "version": vcon.vcon, + "created_at": vcon.created_at, + "party_count": len(vcon.parties), + "dialog_count": len(vcon.dialog) + } + } + +def api_payload_to_vcon(payload): + """Convert API payload to vCon.""" + return Vcon(payload["vcon"]) +``` + +#### Database Integration +```python +def vcon_to_database_record(vcon): + """Convert vCon to database record format.""" + return { + "id": vcon.uuid, + "version": vcon.vcon, + "created_at": vcon.created_at, + "updated_at": vcon.updated_at, + "data": vcon.to_json(), + "party_count": len(vcon.parties), + "dialog_count": len(vcon.dialog), + "has_attachments": len(vcon.attachments) > 0, + "has_analysis": len(vcon.analysis) > 0 + } +``` + +### 6. Performance Considerations + +```python +def optimize_vcon_for_storage(vcon): + """Optimize vCon for storage by converting large content to external references.""" + for i, dialog in enumerate(vcon.dialog): + if dialog.get("body") and len(dialog["body"]) > 1000000: # 1MB threshold + # In real implementation, upload to storage and get URL + external_url = f"https://storage.example.com/dialog_{i}_content" + dialog["url"] = external_url + dialog["content_hash"] = dialog.calculate_content_hash() + del dialog["body"] + dialog["encoding"] = None + +def optimize_vcon_for_processing(vcon): + """Optimize vCon for processing by loading external content.""" + for dialog in vcon.dialog: + if dialog.is_external_data(): + try: + dialog.to_inline_data() + except Exception as e: + print(f"Failed to load external content: {e}") +``` + ## Conclusion The vCon library provides a comprehensive framework for working with conversation data. When generating code: -1. Start by creating a vCon container with `Vcon.build_new()` -2. Add parties using the `Party` class and `vcon.add_party()` -3. Add dialog entries using the `Dialog` class and `vcon.add_dialog()` -4. Add metadata with `vcon.add_tag()`, attachments with `vcon.add_attachment()`, and analysis with `vcon.add_analysis()` -5. Validate the vCon with `vcon.is_valid()` -6. Save with `vcon.save_to_file()` or export with `vcon.to_json()` \ No newline at end of file +1. **Start Simple**: Begin with `Vcon.build_new()` and basic Party/Dialog objects +2. **Add Rich Metadata**: Use tags, attachments, and analysis for comprehensive data +3. **Handle Multimedia**: Leverage video/image processing capabilities when needed +4. **Ensure Security**: Use digital signatures for integrity verification +5. **Validate Always**: Check vCon validity before saving or transmitting +6. **Handle Errors Gracefully**: Implement proper error handling for robust applications +7. **Consider Performance**: Optimize for storage or processing based on use case +8. **Use Extensions**: Declare optional features and must-support requirements +9. **Track Events**: Use party history for complex multi-party conversations +10. **Integrate Seamlessly**: Follow patterns for API and database integration + +The vCon 0.3.0 specification provides a robust foundation for modern conversation data management with support for multimedia content, security, and extensibility. \ No newline at end of file