refactor demos (#398)
2
.github/workflows/e2e_archgw.yml
vendored
|
|
@ -7,7 +7,7 @@ on:
|
|||
pull_request:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
e2e_archgw_tests:
|
||||
runs-on: ubuntu-latest-m
|
||||
defaults:
|
||||
run:
|
||||
|
|
|
|||
2
.github/workflows/e2e_model_server.yml
vendored
|
|
@ -7,7 +7,7 @@ on:
|
|||
pull_request:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
e2e_model_server_tests:
|
||||
runs-on: ubuntu-latest-m
|
||||
defaults:
|
||||
run:
|
||||
|
|
|
|||
6
.github/workflows/e2e_test_demos.yml
vendored
|
|
@ -7,7 +7,7 @@ on:
|
|||
pull_request:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
e2e_demo_tests:
|
||||
runs-on: ubuntu-latest-m
|
||||
|
||||
steps:
|
||||
|
|
@ -37,7 +37,7 @@ jobs:
|
|||
source venv/bin/activate
|
||||
cd model_server/ && echo "installing model server" && poetry install
|
||||
cd ../arch/tools && echo "installing archgw cli" && poetry install
|
||||
cd ../../demos/test_runner && echo "installing test dependencies" && poetry install
|
||||
cd ../../demos/shared/test_runner && echo "installing test dependencies" && poetry install
|
||||
|
||||
- name: run demo tests
|
||||
env:
|
||||
|
|
@ -45,4 +45,4 @@ jobs:
|
|||
MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
|
||||
run: |
|
||||
source venv/bin/activate
|
||||
cd demos/test_runner && sh run_demo_tests.sh
|
||||
cd demos/shared/test_runner && sh run_demo_tests.sh
|
||||
|
|
|
|||
2
.github/workflows/e2e_tests.yml
vendored
|
|
@ -7,7 +7,7 @@ on:
|
|||
pull_request:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
e2e_tests:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
|
|
|||
|
|
@ -38,9 +38,8 @@ Arch is engineered with purpose-built LLMs to handle critical but undifferentiat
|
|||
To get in touch with us, please join our [discord server](https://discord.gg/pGZf2gcwEc). We will be monitoring that actively and offering support there.
|
||||
|
||||
## Demos
|
||||
* [Weather Forecast](demos/weather_forecast/README.md) - Walk through of the core function calling capabilities of arch gateway using weather forecasting service
|
||||
* [Insurance Agent](demos/insurance_agent/README.md) - Build a full insurance agent with Arch
|
||||
* [Network Agent](demos/network_agent/README.md) - Build a networking co-pilot/agent agent with Arch
|
||||
* [Weather Forecast](demos/samples_python/weather_forecast/README.md) - Walk through of the core function calling capabilities of arch gateway using weather forecasting service
|
||||
* [Network Agent](demos/samples_python/network_switch_operator_agent/README.md) - Build a networking co-pilot/agent agent with Arch
|
||||
|
||||
## Quickstart
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ services:
|
|||
- "12000:12000"
|
||||
- "19901:9901"
|
||||
volumes:
|
||||
- ${ARCH_CONFIG_FILE:-../demos/weather_forecast/arch_config.yaml}:/app/arch_config.yaml
|
||||
- ${ARCH_CONFIG_FILE:-../demos/samples_python/weather_forecast/arch_config.yaml}:/app/arch_config.yaml
|
||||
- /etc/ssl/cert.pem:/etc/ssl/cert.pem
|
||||
- ./envoy.template.yaml:/app/envoy.template.yaml
|
||||
- ./arch_config_schema.yaml:/app/arch_config_schema.yaml
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
FROM python:3 AS base
|
||||
|
||||
FROM base AS builder
|
||||
|
||||
WORKDIR /src
|
||||
|
||||
COPY requirements.txt /src/
|
||||
RUN pip install --prefix=/runtime --force-reinstall -r requirements.txt
|
||||
|
||||
COPY . /src
|
||||
|
||||
FROM python:3-slim AS output
|
||||
|
||||
COPY --from=builder /runtime /usr/local
|
||||
|
||||
COPY . /app
|
||||
WORKDIR /app
|
||||
|
||||
CMD ["uvicorn", "insurance_agent_main:app", "--host", "0.0.0.0", "--port", "80", "--log-level", "info"]
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
# Insurance Agent Demo
|
||||
|
||||
This demo showcases how the **Arch** can be used to manage insurance-related tasks such as policy inquiries, initiating policies, and updating claims or deductibles. In this demo, the assistant provides factual information related to insurance policies (e.g., car, boat, house, motorcycle).
|
||||
|
||||
The system can perform a variety of tasks, such as answering insurance-related questions, retrieving policy coverage details, initiating policies, and updating claims or deductibles.
|
||||
|
||||
## Available Functions:
|
||||
|
||||
- **Policy Q/A**: Handles general Q&A related to insurance policies.
|
||||
- **Endpoint**: `/policy/qa`
|
||||
- This function answers general inquiries related to insurance, such as coverage details or policy types. It is the default target for insurance-related queries.
|
||||
|
||||
- **Get Policy Coverage**: Retrieves the coverage details for a given policy type (car, boat, house, motorcycle).
|
||||
- **Endpoint**: `/policy/coverage`
|
||||
- Parameters:
|
||||
- `policy_type` (required): The type of policy. Available options: `car`, `boat`, `house`, `motorcycle`. Defaults to `car`.
|
||||
|
||||
- **Initiate Policy**: Starts a policy coverage for car, boat, motorcycle, or house.
|
||||
- **Endpoint**: `/policy/initiate`
|
||||
- Parameters:
|
||||
- `policy_type` (required): The type of policy. Available options: `car`, `boat`, `house`, `motorcycle`. Defaults to `car`.
|
||||
- `deductible` (required): The deductible amount set for the policy.
|
||||
|
||||
- **Update Claim**: Updates the notes on a specific insurance claim.
|
||||
- **Endpoint**: `/policy/claim`
|
||||
- Parameters:
|
||||
- `claim_id` (required): The claim number.
|
||||
- `notes` (optional): Notes about the claim number for the adjustor to see.
|
||||
|
||||
- **Update Deductible**: Updates the deductible amount for a specific policy coverage.
|
||||
- **Endpoint**: `/policy/deductible`
|
||||
- Parameters:
|
||||
- `policy_id` (required): The ID of the policy.
|
||||
- `deductible` (required): The deductible amount to be set for the policy.
|
||||
|
||||
**Arch** is designed to intelligently routes prompts to the appropriate functions based on the target, allowing for seamless interaction with various insurance-related services.
|
||||
|
||||
# Starting the demo
|
||||
1. Please make sure the [pre-requisites](https://github.com/katanemo/arch/?tab=readme-ov-file#prerequisites) are installed correctly
|
||||
2. Start Arch
|
||||
```sh
|
||||
sh run_demo.sh
|
||||
```
|
||||
3. Navigate to http://localhost:18080/
|
||||
4. Tell me what can you do for me?"
|
||||
|
||||
# Observability
|
||||
Arch gateway publishes stats endpoint at http://localhost:19901/stats. In this demo we are using prometheus to pull stats from arch and we are using grafana to visalize the stats in dashboard. To see grafana dashboard follow instructions below,
|
||||
|
||||
1. Start grafana and prometheus using following command
|
||||
```yaml
|
||||
docker compose --profile monitoring up
|
||||
```
|
||||
1. Navigate to http://localhost:3000/ to open grafana UI (use admin/grafana as credentials)
|
||||
1. From grafana left nav click on dashboards and select "Intelligent Gateway Overview" to view arch gateway stats
|
||||
|
||||
Here is sample interaction,
|
||||
<img width="575" alt="image" src="https://github.com/user-attachments/assets/25d40f46-616e-41ea-be8e-1623055c84ec">
|
||||
|
|
@ -1,105 +0,0 @@
|
|||
version: v0.1
|
||||
listener:
|
||||
address: 127.0.0.1
|
||||
port: 8080 #If you configure port 443, you'll need to update the listener with tls_certificates
|
||||
message_format: huggingface
|
||||
|
||||
system_prompt: |
|
||||
You are an insurance assistant that just offers guidance related to car, boat, rental and home insurnace only. Please be pricese and summarize based on the context provided.
|
||||
|
||||
llm_providers:
|
||||
- name: OpenAI
|
||||
provider_interface: openai
|
||||
access_key: $OPENAI_API_KEY
|
||||
model: gpt-4o
|
||||
default: true
|
||||
|
||||
# Arch creates a round-robin load balancing between different endpoints, managed via the cluster subsystem.
|
||||
endpoints:
|
||||
app_server:
|
||||
# value could be ip address or a hostname with port
|
||||
# this could also be a list of endpoints for load balancing
|
||||
# for example endpoint: [ ip1:port, ip2:port ]
|
||||
endpoint: host.docker.internal:18083
|
||||
# max time to wait for a connection to be established
|
||||
connect_timeout: 0.05s
|
||||
|
||||
prompt_targets:
|
||||
- name: policy_qa
|
||||
endpoint:
|
||||
name: app_server
|
||||
path: /policy/qa
|
||||
http_method: POST
|
||||
description: Handle general Q/A related to insurance.
|
||||
default: true
|
||||
|
||||
- name: get_policy_coverage
|
||||
description: Retrieve the coverage details for an insurance policy.
|
||||
endpoint:
|
||||
name: app_server
|
||||
path: /policy/coverage
|
||||
http_method: POST
|
||||
parameters:
|
||||
- name: policy_type
|
||||
type: str
|
||||
description: The type of policy
|
||||
default: car
|
||||
required: true
|
||||
|
||||
- name: initiate_policy
|
||||
endpoint:
|
||||
name: app_server
|
||||
path: /policy/initiate
|
||||
http_method: POST
|
||||
description: Start a policy coverage for an insurance policy
|
||||
parameters:
|
||||
- name: policy_type
|
||||
type: str
|
||||
description: The type of policy
|
||||
default: car
|
||||
required: true
|
||||
- name: deductible
|
||||
type: float
|
||||
description: the deductible amount set of the policy
|
||||
required: true
|
||||
|
||||
- name: update_claim
|
||||
endpoint:
|
||||
name: app_server
|
||||
path: /policy/claim
|
||||
http_method: POST
|
||||
description: Update the notes on the claim
|
||||
parameters:
|
||||
- name: claim_id
|
||||
type: str
|
||||
description: the claim number
|
||||
required: true
|
||||
- name: notes
|
||||
type: str
|
||||
description: notes about the cliam number for your adjustor to see
|
||||
required: false
|
||||
|
||||
- name: update_deductible
|
||||
endpoint:
|
||||
name: app_server
|
||||
path: /policy/deductible
|
||||
http_method: POST
|
||||
description: Update the deductible amount for a specific insurance policy coverage.
|
||||
parameters:
|
||||
- name: policy_id
|
||||
type: str
|
||||
description: The id of the insurance policy
|
||||
required: true
|
||||
- name: deductible
|
||||
type: float
|
||||
description: the deductible amount set of the policy
|
||||
required: true
|
||||
|
||||
ratelimits:
|
||||
- model: gpt-4
|
||||
selector:
|
||||
key: selector-key
|
||||
value: selector-value
|
||||
limit:
|
||||
tokens: 1
|
||||
unit: minute
|
||||
|
|
@ -1,140 +0,0 @@
|
|||
from fastapi import FastAPI, HTTPException
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class Conversation(BaseModel):
|
||||
arch_messages: list
|
||||
|
||||
|
||||
class PolicyCoverageRequest(BaseModel):
|
||||
policy_type: str = Field(
|
||||
...,
|
||||
description="The type of a policy held by the customer For, e.g. car, boat, house, motorcycle)",
|
||||
)
|
||||
|
||||
|
||||
class PolicyInitiateRequest(PolicyCoverageRequest):
|
||||
deductible: float = Field(
|
||||
..., description="The deductible amount set of the policy"
|
||||
)
|
||||
|
||||
|
||||
class ClaimUpdate(BaseModel):
|
||||
claim_id: str
|
||||
notes: str # Status or details of the claim
|
||||
|
||||
|
||||
class DeductibleUpdate(BaseModel):
|
||||
policy_id: str
|
||||
deductible: float
|
||||
|
||||
|
||||
class CoverageResponse(BaseModel):
|
||||
policy_type: str
|
||||
coverage: str # Description of coverage
|
||||
premium: float # The premium cost
|
||||
|
||||
|
||||
# Get information about policy coverage
|
||||
@app.post("/policy/coverage", response_model=CoverageResponse)
|
||||
async def get_policy_coverage(req: PolicyCoverageRequest):
|
||||
"""
|
||||
Retrieve the coverage details for a given policy type (car, boat, house, motorcycle).
|
||||
"""
|
||||
policy_coverage = {
|
||||
"car": {
|
||||
"coverage": "Full car coverage with collision, liability",
|
||||
"premium": 500.0,
|
||||
},
|
||||
"boat": {
|
||||
"coverage": "Full boat coverage including theft and storm damage",
|
||||
"premium": 700.0,
|
||||
},
|
||||
"house": {
|
||||
"coverage": "Full house coverage including fire, theft, flood",
|
||||
"premium": 1000.0,
|
||||
},
|
||||
"motorcycle": {
|
||||
"coverage": "Full motorcycle coverage with liability",
|
||||
"premium": 400.0,
|
||||
},
|
||||
}
|
||||
|
||||
if req.policy_type not in policy_coverage:
|
||||
raise HTTPException(status_code=404, detail="Policy type not found")
|
||||
|
||||
return CoverageResponse(
|
||||
policy_type=req.policy_type,
|
||||
coverage=policy_coverage[req.policy_type]["coverage"],
|
||||
premium=policy_coverage[req.policy_type]["premium"],
|
||||
)
|
||||
|
||||
|
||||
# Initiate policy coverage
|
||||
@app.post("/policy/initiate")
|
||||
async def initiate_policy(policy_request: PolicyInitiateRequest):
|
||||
"""
|
||||
Initiate policy coverage for a car, boat, house, or motorcycle.
|
||||
"""
|
||||
if policy_request.policy_type not in ["car", "boat", "house", "motorcycle"]:
|
||||
raise HTTPException(status_code=400, detail="Invalid policy type")
|
||||
|
||||
return {
|
||||
"message": f"Policy initiated for {policy_request.policy_type}",
|
||||
"deductible": policy_request.deductible,
|
||||
}
|
||||
|
||||
|
||||
# Update claim details
|
||||
@app.post("/policy/claim")
|
||||
async def update_claim(req: ClaimUpdate):
|
||||
"""
|
||||
Update the status or details of a claim.
|
||||
"""
|
||||
# For simplicity, this is a mock update response
|
||||
return {
|
||||
"message": f"Claim {claim_update.claim_id} for policy {claim_update.claim_id} has been updated",
|
||||
"update": claim_update.notes,
|
||||
}
|
||||
|
||||
|
||||
# Update deductible amount
|
||||
@app.post("/policy/deductible")
|
||||
async def update_deductible(deductible_update: DeductibleUpdate):
|
||||
"""
|
||||
Update the deductible amount for a specific policy.
|
||||
"""
|
||||
# For simplicity, this is a mock update response
|
||||
return {
|
||||
"message": f"Deductible for policy {deductible_update.policy_id} has been updated",
|
||||
"new_deductible": deductible_update.deductible,
|
||||
}
|
||||
|
||||
|
||||
# Post method for policy Q/A
|
||||
@app.post("/policy/qa")
|
||||
async def policy_qa(conversation: Conversation):
|
||||
"""
|
||||
This method handles Q/A related to general issues in insurance.
|
||||
It forwards the conversation to the OpenAI client via a local proxy and returns the response.
|
||||
"""
|
||||
return {
|
||||
"choices": [
|
||||
{
|
||||
"message": {
|
||||
"role": "assistant",
|
||||
"content": "I am a helpful insurance agent, and can only help with insurance things",
|
||||
},
|
||||
"finish_reason": "completed",
|
||||
"index": 0,
|
||||
}
|
||||
],
|
||||
"model": "insurance_agent",
|
||||
"usage": {"completion_tokens": 0},
|
||||
}
|
||||
|
||||
|
||||
# Run the app using:
|
||||
# uvicorn main:app --reload
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
fastapi
|
||||
uvicorn
|
||||
pydantic
|
||||
openai
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
apiVersion: 1
|
||||
|
||||
providers:
|
||||
- name: "Dashboard provider"
|
||||
orgId: 1
|
||||
type: file
|
||||
disableDeletion: false
|
||||
updateIntervalSeconds: 10
|
||||
allowUiUpdates: false
|
||||
options:
|
||||
path: /var/lib/grafana/dashboards
|
||||
foldersFromFilesStructure: true
|
||||
|
|
@ -1,355 +0,0 @@
|
|||
{
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
"builtIn": 1,
|
||||
"datasource": {
|
||||
"type": "grafana",
|
||||
"uid": "-- Grafana --"
|
||||
},
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations & Alerts",
|
||||
"type": "dashboard"
|
||||
}
|
||||
]
|
||||
},
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 1,
|
||||
"links": [],
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "PBFA97CFB590B2093"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisBorderShow": false,
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 0,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"insertNulls": false,
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "auto",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 2,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "PBFA97CFB590B2093"
|
||||
},
|
||||
"disableTextWrap": false,
|
||||
"editorMode": "code",
|
||||
"expr": "avg(rate(envoy_cluster_internal_upstream_rq_time_sum[1m]) / rate(envoy_cluster_internal_upstream_rq_time_count[1m])) by (envoy_cluster_name)",
|
||||
"fullMetaSearch": false,
|
||||
"hide": false,
|
||||
"includeNullMetadata": true,
|
||||
"instant": false,
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
"refId": "A",
|
||||
"useBackend": false
|
||||
}
|
||||
],
|
||||
"title": "request latency - internal (ms)",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "PBFA97CFB590B2093"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisBorderShow": false,
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 0,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"insertNulls": false,
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "auto",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 0
|
||||
},
|
||||
"id": 1,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "PBFA97CFB590B2093"
|
||||
},
|
||||
"disableTextWrap": false,
|
||||
"editorMode": "code",
|
||||
"expr": "avg(rate(envoy_cluster_external_upstream_rq_time_sum[1m]) / rate(envoy_cluster_external_upstream_rq_time_count[1m])) by (envoy_cluster_name)",
|
||||
"fullMetaSearch": false,
|
||||
"hide": false,
|
||||
"includeNullMetadata": true,
|
||||
"instant": false,
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
"refId": "A",
|
||||
"useBackend": false
|
||||
}
|
||||
],
|
||||
"title": "request latency - external (ms)",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "PBFA97CFB590B2093"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisBorderShow": false,
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 0,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"insertNulls": false,
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "auto",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 8
|
||||
},
|
||||
"id": 3,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "PBFA97CFB590B2093"
|
||||
},
|
||||
"disableTextWrap": false,
|
||||
"editorMode": "code",
|
||||
"expr": "avg(rate(envoy_cluster_internal_upstream_rq_completed[1m])) by (envoy_cluster_name)",
|
||||
"fullMetaSearch": false,
|
||||
"includeNullMetadata": true,
|
||||
"instant": false,
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
"refId": "A",
|
||||
"useBackend": false
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "PBFA97CFB590B2093"
|
||||
},
|
||||
"disableTextWrap": false,
|
||||
"editorMode": "code",
|
||||
"expr": "avg(rate(envoy_cluster_external_upstream_rq_completed[1m])) by (envoy_cluster_name)",
|
||||
"fullMetaSearch": false,
|
||||
"hide": false,
|
||||
"includeNullMetadata": true,
|
||||
"instant": false,
|
||||
"legendFormat": "__auto",
|
||||
"range": true,
|
||||
"refId": "B",
|
||||
"useBackend": false
|
||||
}
|
||||
],
|
||||
"title": "Upstream request count",
|
||||
"type": "timeseries"
|
||||
}
|
||||
],
|
||||
"schemaVersion": 39,
|
||||
"tags": [],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"time": {
|
||||
"from": "now-15m",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "browser",
|
||||
"title": "Intelligent Gateway Overview",
|
||||
"uid": "adt6uhx5lk8aob",
|
||||
"version": 3,
|
||||
"weekStart": ""
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
apiVersion: 1
|
||||
|
||||
datasources:
|
||||
- name: Prometheus
|
||||
type: prometheus
|
||||
url: http://prometheus:9090
|
||||
isDefault: true
|
||||
access: proxy
|
||||
editable: true
|
||||
|
|
@ -1,253 +0,0 @@
|
|||
import logging
|
||||
import random
|
||||
import re
|
||||
import sqlite3
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
import pandas as pd
|
||||
from dateparser import parse
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def loadsql():
|
||||
# Example Usage
|
||||
conn = sqlite3.connect(":memory:")
|
||||
|
||||
# create and load the devices table
|
||||
device_data = generate_device_data(conn)
|
||||
|
||||
# create and load the interface_stats table
|
||||
generate_interface_stats_data(conn, device_data)
|
||||
|
||||
# create and load the flow table
|
||||
generate_flow_data(conn, device_data)
|
||||
|
||||
return conn
|
||||
|
||||
|
||||
# Function to convert natural language time expressions to "X {time} ago" format
|
||||
def convert_to_ago_format(expression):
|
||||
# Define patterns for different time units
|
||||
time_units = {
|
||||
r"seconds": "seconds",
|
||||
r"minutes": "minutes",
|
||||
r"mins": "mins",
|
||||
r"hrs": "hrs",
|
||||
r"hours": "hours",
|
||||
r"hour": "hour",
|
||||
r"hr": "hour",
|
||||
r"days": "days",
|
||||
r"day": "day",
|
||||
r"weeks": "weeks",
|
||||
r"week": "week",
|
||||
r"months": "months",
|
||||
r"month": "month",
|
||||
r"years": "years",
|
||||
r"yrs": "years",
|
||||
r"year": "year",
|
||||
r"yr": "year",
|
||||
}
|
||||
|
||||
# Iterate over each time unit and create regex for each phrase format
|
||||
for pattern, unit in time_units.items():
|
||||
# Handle "for the past X {unit}"
|
||||
match = re.search(rf"(\d+) {pattern}", expression)
|
||||
if match:
|
||||
quantity = match.group(1)
|
||||
return f"{quantity} {unit} ago"
|
||||
|
||||
# If the format is not recognized, return None or raise an error
|
||||
return None
|
||||
|
||||
|
||||
# Function to generate random MAC addresses
|
||||
def random_mac():
|
||||
return "AA:BB:CC:DD:EE:" + ":".join(
|
||||
[f"{random.randint(0, 255):02X}" for _ in range(2)]
|
||||
)
|
||||
|
||||
|
||||
# Function to generate random IP addresses
|
||||
def random_ip():
|
||||
return f"""{random.randint(1, 255)}
|
||||
.{random.randint(1, 255)}
|
||||
.{random.randint(1, 255)}
|
||||
.{random.randint(1, 255)}"""
|
||||
|
||||
|
||||
# Generate synthetic data for the device table
|
||||
def generate_device_data(
|
||||
conn,
|
||||
n=1000,
|
||||
):
|
||||
device_data = {
|
||||
"switchip": [random_ip() for _ in range(n)],
|
||||
"hwsku": [f"HW{i+1}" for i in range(n)],
|
||||
"hostname": [f"switch{i+1}" for i in range(n)],
|
||||
"osversion": [f"v{i+1}" for i in range(n)],
|
||||
"layer": ["L2" if i % 2 == 0 else "L3" for i in range(n)],
|
||||
"region": [random.choice(["US", "EU", "ASIA"]) for _ in range(n)],
|
||||
"uptime": [
|
||||
f"""{random.randint(0, 10)} days {random.randint(0, 23)}
|
||||
:{random.randint(0, 59)}:{random.randint(0, 59)}"""
|
||||
for _ in range(n)
|
||||
],
|
||||
"device_mac_address": [random_mac() for _ in range(n)],
|
||||
}
|
||||
df = pd.DataFrame(device_data)
|
||||
df.to_sql("device", conn, index=False)
|
||||
return df
|
||||
|
||||
|
||||
# Generate synthetic data for the interfacestats table
|
||||
def generate_interface_stats_data(conn, device_df, n=1000):
|
||||
interface_stats_data = []
|
||||
for _ in range(n):
|
||||
device_mac = random.choice(device_df["device_mac_address"])
|
||||
ifname = random.choice(["eth0", "eth1", "eth2", "eth3"])
|
||||
time = datetime.now(timezone.utc) - timedelta(
|
||||
minutes=random.randint(0, 1440 * 5)
|
||||
) # random timestamps in the past 5 day
|
||||
in_discards = random.randint(0, 1000)
|
||||
in_errors = random.randint(0, 500)
|
||||
out_discards = random.randint(0, 800)
|
||||
out_errors = random.randint(0, 400)
|
||||
in_octets = random.randint(1000, 100000)
|
||||
out_octets = random.randint(1000, 100000)
|
||||
|
||||
interface_stats_data.append(
|
||||
{
|
||||
"device_mac_address": device_mac,
|
||||
"ifname": ifname,
|
||||
"time": time,
|
||||
"in_discards": in_discards,
|
||||
"in_errors": in_errors,
|
||||
"out_discards": out_discards,
|
||||
"out_errors": out_errors,
|
||||
"in_octets": in_octets,
|
||||
"out_octets": out_octets,
|
||||
}
|
||||
)
|
||||
df = pd.DataFrame(interface_stats_data)
|
||||
df.to_sql("interfacestats", conn, index=False)
|
||||
|
||||
|
||||
# Generate synthetic data for the ts_flow table
|
||||
def generate_flow_data(conn, device_df, n=1000):
|
||||
flow_data = []
|
||||
for _ in range(n):
|
||||
sampler_address = random.choice(device_df["switchip"])
|
||||
proto = random.choice(["TCP", "UDP"])
|
||||
src_addr = random_ip()
|
||||
dst_addr = random_ip()
|
||||
src_port = random.randint(1024, 65535)
|
||||
dst_port = random.randint(1024, 65535)
|
||||
in_if = random.randint(1, 10)
|
||||
out_if = random.randint(1, 10)
|
||||
flow_start = int(
|
||||
(datetime.now() - timedelta(days=random.randint(1, 30))).timestamp()
|
||||
)
|
||||
flow_end = int(
|
||||
(datetime.now() - timedelta(days=random.randint(1, 30))).timestamp()
|
||||
)
|
||||
bytes_transferred = random.randint(1000, 100000)
|
||||
packets = random.randint(1, 1000)
|
||||
flow_time = datetime.now(timezone.utc) - timedelta(
|
||||
minutes=random.randint(0, 1440 * 5)
|
||||
) # random flow time
|
||||
|
||||
flow_data.append(
|
||||
{
|
||||
"sampler_address": sampler_address,
|
||||
"proto": proto,
|
||||
"src_addr": src_addr,
|
||||
"dst_addr": dst_addr,
|
||||
"src_port": src_port,
|
||||
"dst_port": dst_port,
|
||||
"in_if": in_if,
|
||||
"out_if": out_if,
|
||||
"flow_start": flow_start,
|
||||
"flow_end": flow_end,
|
||||
"bytes": bytes_transferred,
|
||||
"packets": packets,
|
||||
"time": flow_time,
|
||||
}
|
||||
)
|
||||
df = pd.DataFrame(flow_data)
|
||||
df.to_sql("ts_flow", conn, index=False)
|
||||
|
||||
|
||||
def load_params(req):
|
||||
# Step 1: Convert the from_time natural language string to a timestamp if provided
|
||||
if req.from_time:
|
||||
# Use `dateparser` to parse natural language timeframes
|
||||
logger.info("%s\n\nCaptured from time: %s\n\n", "* " * 50, req.from_time)
|
||||
parsed_time = parse(req.from_time, settings={"RELATIVE_BASE": datetime.now()})
|
||||
if not parsed_time:
|
||||
conv_time = convert_to_ago_format(req.from_time)
|
||||
if conv_time:
|
||||
parsed_time = parse(
|
||||
conv_time, settings={"RELATIVE_BASE": datetime.now()}
|
||||
)
|
||||
else:
|
||||
return {
|
||||
"error": """Invalid from_time format. Please provide a valid time description
|
||||
such as 'past 7 days' or 'since last month'."""
|
||||
}
|
||||
logger.info("\n\nConverted from time: %s\n\n%s\n\n", parsed_time, "* " * 50)
|
||||
from_time = parsed_time
|
||||
logger.info("Using parsed from_time: %f", from_time)
|
||||
else:
|
||||
# If no from_time is provided, use a default value (e.g., the past 7 days)
|
||||
from_time = datetime.now() - timedelta(days=7)
|
||||
logger.info("Using default from_time: %f", from_time)
|
||||
|
||||
# Step 2: Build the dynamic SQL query based on the optional filters
|
||||
filters = []
|
||||
params = {"from_time": from_time}
|
||||
|
||||
if req.ifname:
|
||||
filters.append("i.ifname = :ifname")
|
||||
params["ifname"] = req.ifname
|
||||
|
||||
if req.region:
|
||||
filters.append("d.region = :region")
|
||||
params["region"] = req.region
|
||||
|
||||
if req.min_in_errors is not None:
|
||||
filters.append("i.in_errors >= :min_in_errors")
|
||||
params["min_in_errors"] = req.min_in_errors
|
||||
|
||||
if req.max_in_errors is not None:
|
||||
filters.append("i.in_errors <= :max_in_errors")
|
||||
params["max_in_errors"] = req.max_in_errors
|
||||
|
||||
if req.min_out_errors is not None:
|
||||
filters.append("i.out_errors >= :min_out_errors")
|
||||
params["min_out_errors"] = req.min_out_errors
|
||||
|
||||
if req.max_out_errors is not None:
|
||||
filters.append("i.out_errors <= :max_out_errors")
|
||||
params["max_out_errors"] = req.max_out_errors
|
||||
|
||||
if req.min_in_discards is not None:
|
||||
filters.append("i.in_discards >= :min_in_discards")
|
||||
params["min_in_discards"] = req.min_in_discards
|
||||
|
||||
if req.max_in_discards is not None:
|
||||
filters.append("i.in_discards <= :max_in_discards")
|
||||
params["max_in_discards"] = req.max_in_discards
|
||||
|
||||
if req.min_out_discards is not None:
|
||||
filters.append("i.out_discards >= :min_out_discards")
|
||||
params["min_out_discards"] = req.min_out_discards
|
||||
|
||||
if req.max_out_discards is not None:
|
||||
filters.append("i.out_discards <= :max_out_discards")
|
||||
params["max_out_discards"] = req.max_out_discards
|
||||
|
||||
return params, filters
|
||||
18
demos/samples_java/weather_forcecast_service/Dockerfile
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# Stage 1: Build the application using Maven
|
||||
FROM maven:3.8.7-openjdk-18-slim AS build
|
||||
WORKDIR /app
|
||||
# Copy pom.xml and download dependencies first (caching)
|
||||
COPY pom.xml .
|
||||
RUN mvn dependency:go-offline
|
||||
# Copy the source code and build the application
|
||||
COPY src ./src
|
||||
RUN mvn clean package -DskipTests
|
||||
|
||||
# Stage 2: Run the application using a slim JDK image
|
||||
FROM openjdk:17-jdk-slim
|
||||
WORKDIR /app
|
||||
# Copy the built jar from the previous stage
|
||||
COPY --from=build /app/target/weather-forecast-service-0.0.1-SNAPSHOT.jar app.jar
|
||||
# Expose the port on which the app runs (default Spring Boot is 8080)
|
||||
EXPOSE 8081
|
||||
ENTRYPOINT ["java", "-jar", "app.jar"]
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
version: v0.1
|
||||
listener:
|
||||
address: 127.0.0.1
|
||||
port: 10000 #If you configure port 443, you'll need to update the listener with tls_certificates
|
||||
message_format: huggingface
|
||||
|
||||
# Centralized way to manage LLMs, manage keys, retry logic, failover and limits in a central way
|
||||
llm_providers:
|
||||
- name: OpenAI
|
||||
provider_interface: openai
|
||||
access_key: $OPENAI_API_KEY
|
||||
model: gpt-4o-mini
|
||||
default: true
|
||||
|
||||
# Arch creates a round-robin load balancing between different endpoints, managed via the cluster subsystem.
|
||||
endpoints:
|
||||
weather_forecast_service:
|
||||
# value could be ip address or a hostname with port
|
||||
# this could also be a list of endpoints for load balancing
|
||||
# for example endpoint: [ ip1:port, ip2:port ]
|
||||
endpoint: host.docker.internal:18081
|
||||
# max time to wait for a connection to be established
|
||||
connect_timeout: 0.005s
|
||||
|
||||
# default system prompt used by all prompt targets
|
||||
system_prompt: |
|
||||
You are a helpful weather assistant.
|
||||
|
||||
prompt_targets:
|
||||
- name: weather_forecast
|
||||
description: get the weather forecast
|
||||
parameters:
|
||||
- name: location
|
||||
description: the location for which to get the weather forecast
|
||||
required: true
|
||||
type: string
|
||||
format: City, State
|
||||
- name: days
|
||||
description: the number of days for the forecast
|
||||
required: true
|
||||
type: int
|
||||
endpoint:
|
||||
name: weather_forecast_service
|
||||
path: /weather
|
||||
http_method: POST
|
||||
|
|
@ -1,18 +1,14 @@
|
|||
services:
|
||||
api_server:
|
||||
weather_forecast_service:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "18083:80"
|
||||
healthcheck:
|
||||
test: ["CMD", "curl" ,"http://localhost:80/healthz"]
|
||||
interval: 5s
|
||||
retries: 20
|
||||
- "18081:8081"
|
||||
|
||||
chatbot_ui:
|
||||
build:
|
||||
context: ../shared/chatbot_ui
|
||||
context: ../../shared/chatbot_ui
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "18080:8080"
|
||||
40
demos/samples_java/weather_forcecast_service/pom.xml
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
|
||||
https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>weather</groupId>
|
||||
<artifactId>weather-forecast-service</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.7.10</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<!-- Spring Boot Starter Web -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- Spring Boot Maven Plugin -->
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
// File: src/main/java/com/example/weather/WeatherForecastApplication.java
|
||||
package weather;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class WeatherForecastApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(WeatherForecastApplication.class, args);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
package weather.controller;
|
||||
|
||||
import weather.model.DayForecast;
|
||||
import weather.model.WeatherForecastResponse;
|
||||
import weather.model.WeatherRequest;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
@RestController
|
||||
public class WeatherController {
|
||||
|
||||
private Random random = new Random();
|
||||
|
||||
@PostMapping("/weather")
|
||||
public WeatherForecastResponse getRandomWeatherForecast(@RequestBody WeatherRequest req) {
|
||||
WeatherForecastResponse response = new WeatherForecastResponse();
|
||||
response.setLocation(req.getLocation());
|
||||
response.setUnits(req.getUnits());
|
||||
|
||||
List<DayForecast> forecasts = new ArrayList<>();
|
||||
for (int i = 0; i < req.getDays(); i++) {
|
||||
// Generate a random min temperature between 50 and 89 (inclusive)
|
||||
int minTemp = random.nextInt(90 - 50) + 50;
|
||||
// Generate a max temperature between (minTemp + 5) and (minTemp + 19)
|
||||
int maxTemp = random.nextInt(15) + (minTemp + 5);
|
||||
|
||||
double finalMinTemp = minTemp;
|
||||
double finalMaxTemp = maxTemp;
|
||||
|
||||
// Convert to Celsius if necessary
|
||||
if (req.getUnits().equalsIgnoreCase("celsius") || req.getUnits().equalsIgnoreCase("c")) {
|
||||
finalMinTemp = (minTemp - 32) * 5.0 / 9.0;
|
||||
finalMaxTemp = (maxTemp - 32) * 5.0 / 9.0;
|
||||
}
|
||||
|
||||
DayForecast dayForecast = new DayForecast();
|
||||
dayForecast.setDate(LocalDate.now().plusDays(i).toString());
|
||||
dayForecast.setMin(finalMinTemp);
|
||||
dayForecast.setMax(finalMaxTemp);
|
||||
dayForecast.setUnits(req.getUnits());
|
||||
|
||||
forecasts.add(dayForecast);
|
||||
}
|
||||
response.setDailyForecast(forecasts);
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package weather.model;
|
||||
|
||||
public class DayForecast {
|
||||
private String date;
|
||||
private String units;
|
||||
private double min;
|
||||
private double max;
|
||||
|
||||
public DayForecast() {}
|
||||
|
||||
// Getters and setters
|
||||
public String getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public void setDate(String date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public String getUnits() {
|
||||
return units;
|
||||
}
|
||||
|
||||
public void setUnits(String units) {
|
||||
this.units = units;
|
||||
}
|
||||
|
||||
public double getMin() {
|
||||
return min;
|
||||
}
|
||||
public void setMin(double min) {
|
||||
this.min = min;
|
||||
}
|
||||
public double getMax() {
|
||||
return max;
|
||||
}
|
||||
public void setMax(double max) {
|
||||
this.max = max;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package weather.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class WeatherForecastResponse {
|
||||
private String location;
|
||||
private String units;
|
||||
private List<DayForecast> forecast;
|
||||
|
||||
// Default Constructor
|
||||
public WeatherForecastResponse() {}
|
||||
|
||||
// Getters and Setters
|
||||
public String getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
public void setLocation(String location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public String getUnits() {
|
||||
return units;
|
||||
}
|
||||
|
||||
public void setUnits(String units) {
|
||||
this.units = units;
|
||||
}
|
||||
|
||||
public List<DayForecast> getDailyForecast() {
|
||||
return forecast;
|
||||
}
|
||||
|
||||
public void setDailyForecast(List<DayForecast> forecast) {
|
||||
this.forecast = forecast;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package weather.model;
|
||||
|
||||
public class WeatherRequest {
|
||||
private String location;
|
||||
private int days = 7;
|
||||
private String units = "Farenheit";
|
||||
|
||||
public WeatherRequest() {}
|
||||
|
||||
// Getters and setters
|
||||
public String getLocation() {
|
||||
return location;
|
||||
}
|
||||
public void setLocation(String location) {
|
||||
this.location = location;
|
||||
}
|
||||
public int getDays() {
|
||||
return days;
|
||||
}
|
||||
public void setDays(int days) {
|
||||
this.days = days;
|
||||
}
|
||||
public String getUnits() {
|
||||
return units;
|
||||
}
|
||||
public void setUnits(String units) {
|
||||
this.units = units;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
server.port=8081
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
services:
|
||||
chatbot_ui:
|
||||
build:
|
||||
context: ../shared/chatbot_ui
|
||||
context: ../../shared/chatbot_ui
|
||||
ports:
|
||||
- "18080:8080"
|
||||
environment:
|
||||
|
|
@ -14,7 +14,7 @@ services:
|
|||
|
||||
jaeger:
|
||||
build:
|
||||
context: ../shared/jaeger
|
||||
context: ../../shared/jaeger
|
||||
ports:
|
||||
- "16686:16686"
|
||||
- "4317:4317"
|
||||
|
|
@ -8,7 +8,6 @@ services:
|
|||
- CHAT_COMPLETION_ENDPOINT=http://host.docker.internal:10000/v1
|
||||
volumes:
|
||||
- ./arch_config.yaml:/app/arch_config.yaml
|
||||
- ../shared/chatbot_ui/common.py:/app/common.py
|
||||
ports:
|
||||
- "18080:80"
|
||||
healthcheck:
|
||||
|
|
@ -18,7 +17,7 @@ services:
|
|||
|
||||
chatbot_ui:
|
||||
build:
|
||||
context: ../shared/chatbot_ui
|
||||
context: ../../shared/chatbot_ui
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "18080:8080"
|
||||
|
Before Width: | Height: | Size: 549 KiB After Width: | Height: | Size: 549 KiB |
|
|
@ -12,7 +12,7 @@ services:
|
|||
|
||||
chatbot_ui:
|
||||
build:
|
||||
context: ../shared/chatbot_ui
|
||||
context: ../../shared/chatbot_ui
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "18080:8080"
|
||||
|
Before Width: | Height: | Size: 852 KiB After Width: | Height: | Size: 852 KiB |
|
|
@ -7,13 +7,13 @@ WORKDIR /src
|
|||
COPY requirements.txt /src/
|
||||
RUN pip install --prefix=/runtime --force-reinstall -r requirements.txt
|
||||
|
||||
COPY . /src
|
||||
COPY ../. /src
|
||||
|
||||
FROM python:3.12-slim AS output
|
||||
|
||||
COPY --from=builder /runtime /usr/local
|
||||
|
||||
COPY . /app
|
||||
COPY ../. /app
|
||||
WORKDIR /app
|
||||
|
||||
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80", "--log-level", "info"]
|
||||
|
|
@ -8,7 +8,7 @@ services:
|
|||
|
||||
chatbot_ui:
|
||||
build:
|
||||
context: ../shared/chatbot_ui
|
||||
context: ../../shared/chatbot_ui
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "18080:8080"
|
||||
|
Before Width: | Height: | Size: 636 KiB After Width: | Height: | Size: 636 KiB |
|
|
@ -24,6 +24,7 @@ start_demo() {
|
|||
|
||||
# Step 4: Start Network Agent
|
||||
echo "Starting Network Agent using Docker Compose..."
|
||||
cd build
|
||||
docker compose up -d # Run in detached mode
|
||||
}
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
services:
|
||||
chatbot_ui:
|
||||
build:
|
||||
context: ../shared/chatbot_ui
|
||||
context: ../../shared/chatbot_ui
|
||||
ports:
|
||||
- "18080:8080"
|
||||
environment:
|
||||
|
|
@ -14,7 +14,7 @@ services:
|
|||
|
||||
jaeger:
|
||||
build:
|
||||
context: ../shared/jaeger
|
||||
context: ../../shared/jaeger
|
||||
ports:
|
||||
- "16686:16686"
|
||||
- "4317:4317"
|
||||
|
Before Width: | Height: | Size: 673 KiB After Width: | Height: | Size: 673 KiB |
|
|
@ -11,7 +11,7 @@ services:
|
|||
|
||||
chatbot_ui:
|
||||
build:
|
||||
context: ../shared/chatbot_ui
|
||||
context: ../../shared/chatbot_ui
|
||||
ports:
|
||||
- "18080:8080"
|
||||
environment:
|
||||
|
|
@ -24,12 +24,12 @@ services:
|
|||
|
||||
otel-collector:
|
||||
build:
|
||||
context: ../shared/honeycomb/
|
||||
context: ../../shared/honeycomb/
|
||||
ports:
|
||||
- "4317:4317"
|
||||
- "4318:4318"
|
||||
volumes:
|
||||
- ../shared/honeycomb/otel-collector-config.yaml:/etc/otel-collector-config.yaml
|
||||
- ../../shared/honeycomb/otel-collector-config.yaml:/etc/otel-collector-config.yaml
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
|
|
@ -37,10 +37,10 @@ services:
|
|||
|
||||
prometheus:
|
||||
build:
|
||||
context: ../shared/prometheus
|
||||
context: ../../shared/prometheus
|
||||
|
||||
grafana:
|
||||
build:
|
||||
context: ../shared/grafana
|
||||
context: ../../shared/grafana
|
||||
ports:
|
||||
- "3000:3000"
|
||||
|
|
@ -11,7 +11,7 @@ services:
|
|||
|
||||
chatbot_ui:
|
||||
build:
|
||||
context: ../shared/chatbot_ui
|
||||
context: ../../shared/chatbot_ui
|
||||
ports:
|
||||
- "18080:8080"
|
||||
environment:
|
||||
|
|
@ -24,7 +24,7 @@ services:
|
|||
|
||||
jaeger:
|
||||
build:
|
||||
context: ../shared/jaeger
|
||||
context: ../../shared/jaeger
|
||||
ports:
|
||||
- "16686:16686"
|
||||
- "4317:4317"
|
||||
|
|
@ -32,10 +32,10 @@ services:
|
|||
|
||||
prometheus:
|
||||
build:
|
||||
context: ../shared/prometheus
|
||||
context: ../../shared/prometheus
|
||||
|
||||
grafana:
|
||||
build:
|
||||
context: ../shared/grafana
|
||||
context: ../../shared/grafana
|
||||
ports:
|
||||
- "3000:3000"
|
||||
|
|
@ -11,7 +11,7 @@ services:
|
|||
|
||||
chatbot_ui:
|
||||
build:
|
||||
context: ../shared/chatbot_ui
|
||||
context: ../../shared/chatbot_ui
|
||||
ports:
|
||||
- "18080:8080"
|
||||
environment:
|
||||
|
|
@ -24,12 +24,12 @@ services:
|
|||
|
||||
otel-collector:
|
||||
build:
|
||||
context: ../shared/logfire/
|
||||
context: ../../shared/logfire/
|
||||
ports:
|
||||
- "4317:4317"
|
||||
- "4318:4318"
|
||||
volumes:
|
||||
- ../shared/logfire/otel-collector-config.yaml:/etc/otel-collector-config.yaml
|
||||
- ../../shared/logfire/otel-collector-config.yaml:/etc/otel-collector-config.yaml
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
|
|
@ -37,10 +37,10 @@ services:
|
|||
|
||||
prometheus:
|
||||
build:
|
||||
context: ../shared/prometheus
|
||||
context: ../../shared/prometheus
|
||||
|
||||
grafana:
|
||||
build:
|
||||
context: ../shared/grafana
|
||||
context: ../../shared/grafana
|
||||
ports:
|
||||
- "3000:3000"
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
include:
|
||||
- ../shared/signoz/docker-compose-minimal.yaml
|
||||
- ../../shared/signoz/docker-compose-minimal.yaml
|
||||
|
||||
services:
|
||||
weather_forecast_service:
|
||||
|
|
@ -14,7 +14,7 @@ services:
|
|||
|
||||
chatbot_ui:
|
||||
build:
|
||||
context: ../shared/chatbot_ui
|
||||
context: ../../shared/chatbot_ui
|
||||
ports:
|
||||
- "18080:8080"
|
||||
environment:
|
||||
|
|
@ -27,10 +27,10 @@ services:
|
|||
|
||||
prometheus:
|
||||
build:
|
||||
context: ../shared/prometheus
|
||||
context: ../../shared/prometheus
|
||||
|
||||
grafana:
|
||||
build:
|
||||
context: ../shared/grafana
|
||||
context: ../../shared/grafana
|
||||
ports:
|
||||
- "3000:3000"
|
||||
|
|
@ -11,7 +11,7 @@ services:
|
|||
|
||||
chatbot_ui:
|
||||
build:
|
||||
context: ../shared/chatbot_ui
|
||||
context: ../../shared/chatbot_ui
|
||||
ports:
|
||||
- "18080:8080"
|
||||
environment:
|
||||
|
|
@ -19,23 +19,3 @@ services:
|
|||
- CHAT_COMPLETION_ENDPOINT=http://host.docker.internal:10000/v1
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
volumes:
|
||||
- ./arch_config.yaml:/app/arch_config.yaml
|
||||
|
||||
jaeger:
|
||||
build:
|
||||
context: ../shared/jaeger
|
||||
ports:
|
||||
- "16686:16686"
|
||||
- "4317:4317"
|
||||
- "4318:4318"
|
||||
|
||||
prometheus:
|
||||
build:
|
||||
context: ../shared/prometheus
|
||||
|
||||
grafana:
|
||||
build:
|
||||
context: ../shared/grafana
|
||||
ports:
|
||||
- "3000:3000"
|
||||
|
|
@ -7,13 +7,13 @@ do
|
|||
echo "******************************************"
|
||||
echo "Running tests for $demo ..."
|
||||
echo "****************************************"
|
||||
cd ../$demo
|
||||
cd ../../samples_python/$demo
|
||||
archgw up arch_config.yaml
|
||||
docker compose up -d
|
||||
cd ../test_runner
|
||||
TEST_DATA=../$demo/test_data.yaml poetry run pytest
|
||||
cd ../$demo
|
||||
cd ../../shared/test_runner
|
||||
TEST_DATA=../../samples_python/$demo/test_data.yaml poetry run pytest
|
||||
cd ../../samples_python/$demo
|
||||
archgw down
|
||||
docker compose down -v
|
||||
cd ../test_runner
|
||||
cd ../../shared/test_runner
|
||||
done
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
# LLM Routing
|
||||
This demo shows how you can arch gateway to manage keys and route to appropriate LLM.
|
||||
This demo shows how you can arch gateway to manage keys and route to upstream LLM.
|
||||
|
||||
# Starting the demo
|
||||
1. Please make sure the [pre-requisites](https://github.com/katanemo/arch/?tab=readme-ov-file#prerequisites) are installed correctly
|
||||
|
|
@ -2,7 +2,7 @@ services:
|
|||
|
||||
chatbot_ui:
|
||||
build:
|
||||
context: ../shared/chatbot_ui
|
||||
context: ../../shared/chatbot_ui
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "18080:8080"
|
||||
|
|
@ -15,7 +15,7 @@ services:
|
|||
|
||||
jaeger:
|
||||
build:
|
||||
context: ../shared/jaeger
|
||||
context: ../../shared/jaeger
|
||||
ports:
|
||||
- "16686:16686"
|
||||
- "4317:4317"
|
||||
|
|
@ -23,10 +23,10 @@ services:
|
|||
|
||||
prometheus:
|
||||
build:
|
||||
context: ../shared/prometheus
|
||||
context: ../../shared/prometheus
|
||||
|
||||
grafana:
|
||||
build:
|
||||
context: ../shared/grafana
|
||||
context: ../../shared/grafana
|
||||
ports:
|
||||
- "3000:3000"
|
||||
|
Before Width: | Height: | Size: 273 KiB After Width: | Height: | Size: 273 KiB |
|
Before Width: | Height: | Size: 284 KiB After Width: | Height: | Size: 284 KiB |
|
|
@ -1,7 +1,7 @@
|
|||
services:
|
||||
chatbot_ui:
|
||||
build:
|
||||
context: ../shared/chatbot_ui
|
||||
context: ../../shared/chatbot_ui
|
||||
ports:
|
||||
- "18080:8080"
|
||||
environment:
|
||||
|
|
@ -14,7 +14,7 @@ services:
|
|||
|
||||
jaeger:
|
||||
build:
|
||||
context: ../shared/jaeger
|
||||
context: ../../shared/jaeger
|
||||
ports:
|
||||
- "16686:16686"
|
||||
- "4317:4317"
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
services:
|
||||
chatbot_ui:
|
||||
build:
|
||||
context: ../shared/chatbot_ui
|
||||
context: ../../shared/chatbot_ui
|
||||
ports:
|
||||
- "18080:8080"
|
||||
environment:
|
||||
|
|
@ -14,12 +14,12 @@ services:
|
|||
|
||||
otel-collector:
|
||||
build:
|
||||
context: ../shared/honeycomb/
|
||||
context: ../../shared/honeycomb/
|
||||
ports:
|
||||
- "4317:4317"
|
||||
- "4318:4318"
|
||||
volumes:
|
||||
- ../shared/honeycomb/otel-collector-config.yaml:/etc/otel-collector-config.yaml
|
||||
- ../../shared/honeycomb/otel-collector-config.yaml:/etc/otel-collector-config.yaml
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
|
|
@ -22,7 +22,7 @@ start_demo() {
|
|||
echo "Starting Arch with arch_config.yaml..."
|
||||
archgw up arch_config.yaml
|
||||
|
||||
# Step 4: Start Network Agent
|
||||
# Step 4: Start developer services
|
||||
echo "Starting Network Agent using Docker Compose..."
|
||||
docker compose up -d # Run in detached mode
|
||||
}
|
||||
|
|
@ -80,7 +80,7 @@ Once the prompt targets are configured as above, handle parameters across multi-
|
|||
Demo App
|
||||
~~~~~~~~
|
||||
|
||||
For your convenience, we've built a `demo app <https://github.com/katanemo/archgw/main/demos/multi_turn_rag_agent>`_
|
||||
For your convenience, we've built a `demo app <https://github.com/katanemo/archgw/tree/main/demos/samples_python/multi_turn_rag_agent>`_
|
||||
that you can test and modify locally for multi-turn RAG scenarios.
|
||||
|
||||
.. figure:: includes/multi_turn/mutli-turn-example.png
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ services:
|
|||
- "12000:12000"
|
||||
- "19901:9901"
|
||||
volumes:
|
||||
- ../../demos/weather_forecast/arch_config.yaml:/app/arch_config.yaml
|
||||
- ../../demos/samples_python/weather_forecast/arch_config.yaml:/app/arch_config.yaml
|
||||
- /etc/ssl/cert.pem:/etc/ssl/cert.pem
|
||||
- ~/archgw_logs:/var/log/
|
||||
extra_hosts:
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ log starting > ../build.log
|
|||
|
||||
log building and running function_callling demo
|
||||
log ===========================================
|
||||
cd ../../demos/weather_forecast/
|
||||
cd ../../demos/samples_python/weather_forecast/
|
||||
docker compose up weather_forecast_service --build -d
|
||||
cd -
|
||||
|
||||
|
|
@ -53,7 +53,7 @@ cd ../../
|
|||
tail -F ~/archgw_logs/modelserver.log &
|
||||
model_server_tail_pid=$!
|
||||
archgw down
|
||||
archgw up demos/weather_forecast/arch_config.yaml
|
||||
archgw up demos/samples_python/weather_forecast/arch_config.yaml
|
||||
kill $model_server_tail_pid
|
||||
cd -
|
||||
|
||||
|
|
@ -68,6 +68,6 @@ archgw down
|
|||
|
||||
log shutting down the weather_forecast demo
|
||||
log =======================================
|
||||
cd ../../demos/weather_forecast
|
||||
cd ../../demos/samples_python/weather_forecast
|
||||
docker compose down
|
||||
cd -
|
||||
|
|
|
|||