Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ollama meetup demo #18

Merged
merged 1 commit into from
Apr 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
add ollama meetup demo
  • Loading branch information
hrjn committed Mar 21, 2024
commit 0715459a7be6236d8eba07a162fdfccacc557823
34 changes: 34 additions & 0 deletions demos/20240321_ollama_meetup/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Ollama meetup demo (5mn)

- Make sure that Docker is installed and running on your laptop with Kubernetes enabled.

- Install ollama, start it and pull the mistral model:

```shell
ollama pull mistral
```

By default, the server is reachable on port 11434.

- Install the Python requirements in a virtualenv and activate it.

- To prove that you are not scamming people, start some random deployment in a custom namespace:

```shell
kubectl create ns demo
kubectl apply -f https://k8s.io/examples/controllers/nginx-deployment.yaml -n demo
```

- Profit:

```shell
python run.py
```

There is a lot to improve, namely:
- handling empty outputs gracefully
- asking explicitly for the namespace when it is not provided by the user
- just shelling out kubectl instead of installing the K8S Python client

...but that's the beauty of the game: giving ideas to the audience for building cool stuff !

15 changes: 15 additions & 0 deletions demos/20240321_ollama_meetup/myfuncs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from kubernetes import client, config

def list_pods(namespace):
# Load kubeconfig
config.load_kube_config()
# Create API client instance
api_instance = client.CoreV1Api()
# Call API to list all pods in the given namespace
response = api_instance.list_namespaced_pod(namespace)
out = {"pods": []}
for pod in response.items:
out["pods"].append({"name": pod.metadata.name, "status": pod.status.phase})
return out


3 changes: 3 additions & 0 deletions demos/20240321_ollama_meetup/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
openai==1.14.2
kubernetes==29.0.0
mistralai==0.1.6
67 changes: 67 additions & 0 deletions demos/20240321_ollama_meetup/run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import functools
import json
import os

from mistralai.client import MistralClient
from openai import OpenAI

from myfuncs import list_pods

api_key = os.environ.get("MISTRAL_API_KEY")

online_model = "mistral-small-latest"
offline_model = "mistral" # ollama naming convention

tools = [
{
"type": "function",
"function": {
"name": "list_pods",
"description": "Get the list of all Kubernetes pods and their status in a given namespace",
"parameters": {
"type": "object",
"properties": {
"namespace": {
"type": "string",
"description": "The name of the namespace to look into",
},
},
"required": ["namespace"],
},
}
},
]

callables = {"list_pods": list_pods}

user_input = input("😺 Hello! How can I help you?\n")

# Retrieve user input then generate function inputs with mistral-small
messages = []
messages.append({"role": "system", "content": "Don't make assumptions about what values to plug into functions. Ask for clarification if a user request is ambiguous."})
messages.append({"role": "user", "content": f"Execute the following task on your K8S cluster: {user_input}"})
online_client = MistralClient(api_key=api_key)
resp_tool= online_client.chat(model=online_model, messages=messages, tools=tools, tool_choice="any")
print(f"⏳ Using online model {online_model} to generate function inputs, un instant svp...")
tool_call = resp_tool.choices[0].message.tool_calls[0]
function_name = tool_call.function.name
function_params = json.loads(tool_call.function.arguments)
print(f"😎 Switching to offline execution and calling ollama's {offline_model}. C'est parti!\n\n")

# Run the function
partial_func = functools.partial(callables[function_name], **function_params)
out = partial_func()

# Format the function output with ollama-mistral (7b)
local_client = OpenAI(base_url = "https://127.0.0.1:11434/v1", api_key='ollama')
response = local_client.chat.completions.create(stream=True, model=offline_model, messages=[
{"role": "system", "content": "You are a master of Kubernetes who likes friendly French-related jokes."},
{"role": "user", "content": f"""
Here is a list of K8S pods in a JSON format:\n {out}
Transform it into a bullet-point-like list in idiomatic English and add a few French-related jokes.
"""}])

for chunk in response:
if chunk.choices[0].delta.content is not None:
print(chunk.choices[0].delta.content, end="")