Adil/fix salman docs (#75)

* added the first set of docs for our technical docs

* more docuemtnation changes

* added support for prompt processing and updated life of a request

* updated docs to including getting help sections and updated life of a request

* committing local changes for getting started guide, sample applications, and full reference spec for prompt-config

* updated configuration reference, added sample app skeleton, updated favico

* fixed the configuration refernce file, and made minor changes to the intent detection. commit v1 for now

* Updated docs with use cases and example code, updated what is arch, and made minor changes throughout

* fixed imaged and minor doc fixes

* add sphinx_book_theme

* updated README, and make some minor fixes to documetnation

* fixed README.md

* fixed image width

---------

Co-authored-by: Salman Paracha <salmanparacha@MacBook-Pro-261.local>
Co-authored-by: Adil Hafeez <adil@katanemo.com>
This commit is contained in:
Salman Paracha 2024-09-24 13:54:17 -07:00 committed by GitHub
parent 2d31aeaa36
commit 13dff3089d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
33 changed files with 931 additions and 287 deletions

View file

@ -0,0 +1,72 @@
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/agent/device_reboot', methods=['POST'])
def reboot_devices():
"""
Endpoint to reboot devices based on device IDs or a device group.
"""
data = request.get_json()
# Extract parameters based on the prompt targets definition
device_ids = data.get('device_ids')
device_group = data.get('device_group')
# Validate that at least one parameter is provided
if not device_ids and not device_group:
return jsonify({'error': "At least one of 'device_ids' or 'device_group' must be provided."}), 400
devices_to_reboot = []
# Process 'device_ids' if provided
if device_ids:
if not isinstance(device_ids, list):
return jsonify({'error': "'device_ids' must be a list."}), 400
devices_to_reboot.extend(device_ids)
# Process 'device_group' if provided
if device_group:
if not isinstance(device_group, str):
return jsonify({'error': "'device_group' must be a string."}), 400
# Simulate retrieving device IDs from the device group
# In a real application, replace this with actual data retrieval
group_devices = get_devices_by_group(device_group)
if not group_devices:
return jsonify({'error': f"No devices found in group '{device_group}'."}), 404
devices_to_reboot.extend(group_devices)
# Remove duplicates in case of overlap between device_ids and device_group
devices_to_reboot = list(set(devices_to_reboot))
# Simulate rebooting devices
reboot_results = []
for device_id in devices_to_reboot:
# Placeholder for actual reboot logic
result = {
'device_id': device_id,
'status': 'Reboot initiated'
}
reboot_results.append(result)
response = {
'reboot_results': reboot_results
}
return jsonify(response), 200
def get_devices_by_group(group_name):
"""
Simulate retrieving device IDs based on a device group name.
In a real application, this would query a database or external service.
"""
# Placeholder data for demonstration purposes
device_groups = {
'Sales': ['1001', '1002', '1003'],
'Engineering': ['2001', '2002', '2003'],
'Data Center': ['3001', '3002', '3003']
}
return device_groups.get(group_name, [])
if __name__ == '__main__':
app.run(debug=True)

View file

@ -1,78 +1,96 @@
from flask import Flask, request, jsonify
from datetime import datetime
import uuid
from langchain.memory import ConversationBufferMemory
from langchain.schema import AIMessage, HumanMessage
from langchain import OpenAI
app = Flask(__name__)
# Global dictionary to keep track of user conversations
user_conversations = {}
# Global dictionary to keep track of user memories
user_memories = {}
def get_user_conversation(user_id):
"""
Retrieve the user's conversation history.
If the user does not exist, initialize their conversation data.
Retrieve the user's conversation memory using LangChain.
If the user does not exist, initialize their conversation memory.
"""
if user_id not in user_conversations:
user_conversations[user_id] = {
'messages': []
}
return user_conversations[user_id]
if user_id not in user_memories:
user_memories[user_id] = ConversationBufferMemory(return_messages=True)
return user_memories[user_id]
def update_user_conversation(user_id, client_messages, intent_changed):
"""
Update the user's conversation history with new messages.
Update the user's conversation memory with new messages using LangChain.
Each message is augmented with a UUID, timestamp, and intent change marker.
Only new messages are added to avoid duplication.
"""
user_data = get_user_conversation(user_id)
# Existing messages in the user's conversation
stored_messages = user_data['messages']
memory = get_user_conversation(user_id)
stored_messages = memory.chat_memory.messages
# Determine the number of stored messages
num_stored_messages = len(stored_messages)
# Check for out-of-sync messages
if num_stored_messages > len(client_messages):
return jsonify({'error': 'Client messages are out of sync with server'}), 400
# Determine new messages by slicing the client messages
new_messages = client_messages[num_stored_messages:]
# Process each new message
for index, message in enumerate(new_messages):
message_entry = {
role = message.get('role')
content = message.get('content')
metadata = {
'uuid': str(uuid.uuid4()),
'timestamp': datetime.utcnow().isoformat(),
'role': message.get('role'),
'content': message.get('content'),
'intent_changed': False # Default value
}
# Mark the intent change on the last message if detected
if intent_changed and index == len(new_messages) - 1:
message_entry['intent_changed'] = True
user_data['messages'].append(message_entry)
metadata['intent_changed'] = True
return user_data
# Create a new message with metadata
if role == 'user':
memory.chat_memory.add_message(
HumanMessage(content=content, additional_kwargs={'metadata': metadata})
)
elif role == 'assistant':
memory.chat_memory.add_message(
AIMessage(content=content, additional_kwargs={'metadata': metadata})
)
else:
# Handle other roles if necessary
pass
return memory
def get_messages_since_last_intent(messages):
"""
Retrieve messages from the last intent change onwards.
Retrieve messages from the last intent change onwards using LangChain.
"""
messages_since_intent = []
for message in reversed(messages):
# Insert message at the beginning to maintain correct order
messages_since_intent.insert(0, message)
if message.get('intent_changed'):
metadata = message.additional_kwargs.get('metadata', {})
# Break if intent_changed is True
if metadata.get('intent_changed', False) == True:
break
return messages_since_intent
def forward_to_llm(messages):
"""
Simulate forwarding messages to an upstream LLM.
Replace this with the actual API call to the LLM.
Forward messages to an upstream LLM using LangChain.
"""
# For demonstration purposes, we'll return a placeholder response
return "LLM response based on provided messages."
# Convert messages to a conversation string
conversation = ""
for message in messages:
role = 'User' if isinstance(message, HumanMessage) else 'Assistant'
content = message.content
conversation += f"{role}: {content}\n"
# Use LangChain's LLM to get a response. This call is proxied through Arch for end-to-end observability and traffic management
llm = OpenAI()
# Create a prompt that includes the conversation
prompt = f"{conversation}Assistant:"
response = llm(prompt)
return response
@app.route('/process_rag', methods=['POST'])
def process_rag():
@ -98,22 +116,37 @@ def process_rag():
return jsonify({'error': 'Invalid value for x-arch-prompt-intent-change header'}), 400
# Update user conversation based on intent change
user_data = update_user_conversation(user_id, client_messages, intent_changed)
memory = update_user_conversation(user_id, client_messages, intent_changed)
# Retrieve messages since last intent change for LLM
messages_for_llm = get_messages_since_last_intent(user_data['messages'])
messages_for_llm = get_messages_since_last_intent(memory.chat_memory.messages)
# Forward messages to upstream LLM
llm_response = forward_to_llm(messages_for_llm)
# Prepare the messages to return
messages_to_return = []
for message in memory.chat_memory.messages:
role = 'user' if isinstance(message, HumanMessage) else 'assistant'
content = message.content
metadata = message.additional_kwargs.get('metadata', {})
message_entry = {
'uuid': metadata.get('uuid'),
'timestamp': metadata.get('timestamp'),
'role': role,
'content': content,
'intent_changed': metadata.get('intent_changed', False)
}
messages_to_return.append(message_entry)
# Prepare the response
response = {
'user_id': user_id,
'messages': user_data['messages'],
'messages': messages_to_return,
'llm_response': llm_response
}
return jsonify(response), 200
if __name__ == '__main__':
app.run(debug=True)
app.run(debug=True)

View file

@ -0,0 +1,41 @@
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/agent/device_summary', methods=['POST'])
def get_device_summary():
"""
Endpoint to retrieve device statistics based on device IDs and an optional time range.
"""
data = request.get_json()
# Validate 'device_ids' parameter
device_ids = data.get('device_ids')
if not device_ids or not isinstance(device_ids, list):
return jsonify({'error': "'device_ids' parameter is required and must be a list"}), 400
# Validate 'time_range' parameter (optional, defaults to 7)
time_range = data.get('time_range', 7)
if not isinstance(time_range, int):
return jsonify({'error': "'time_range' must be an integer"}), 400
# Simulate retrieving statistics for the given device IDs and time range
# In a real application, you would query your database or external service here
statistics = []
for device_id in device_ids:
# Placeholder for actual data retrieval
stats = {
'device_id': device_id,
'time_range': f'Last {time_range} days',
'data': f'Statistics data for device {device_id} over the last {time_range} days.'
}
statistics.append(stats)
response = {
'statistics': statistics
}
return jsonify(response), 200
if __name__ == '__main__':
app.run(debug=True)