mirror of
https://github.com/believethehype/nostrdvm.git
synced 2025-09-21 18:50:33 +02:00
update llm example
This commit is contained in:
186
tests/dvm_llm_agents.py
Normal file
186
tests/dvm_llm_agents.py
Normal file
@@ -0,0 +1,186 @@
|
||||
import random
|
||||
import time
|
||||
from pathlib import Path
|
||||
import dotenv
|
||||
from typing import Dict, List
|
||||
import requests, json
|
||||
|
||||
from nostr_sdk import Kind
|
||||
|
||||
from nostr_dvm.framework import DVMFramework
|
||||
from nostr_dvm.tasks.generic_dvm import GenericDVM
|
||||
from nostr_dvm.utils.admin_utils import AdminConfig
|
||||
from nostr_dvm.utils.dvmconfig import build_default_config
|
||||
from nostr_dvm.utils.nip89_utils import NIP89Config, check_and_set_d_tag
|
||||
from nostr_dvm.utils.outbox_utils import AVOID_OUTBOX_RELAY_LIST
|
||||
|
||||
RELAY_LIST = ["wss://nostr.mom",
|
||||
"wss://relay.nostrdvm.com",
|
||||
"wss://nostr.oxtr.dev",
|
||||
#"wss://relay.nostr.net"
|
||||
]
|
||||
|
||||
SYNC_DB_RELAY_LIST = ["wss://relay.damus.io",
|
||||
#"wss://relay.primal.net",
|
||||
"wss://nostr.oxtr.dev"]
|
||||
|
||||
|
||||
|
||||
|
||||
def playground(announce):
|
||||
framework = DVMFramework()
|
||||
|
||||
# An Agent that pretends to be a purple Ostrich
|
||||
name = "PurpleOstrichIntelligence"
|
||||
identifier = "duckduckchat" # Chose a unique identifier in order to get a lnaddress
|
||||
description = "I'm a funny purple Ostrich"
|
||||
picture = "https://image.nostr.build/afd3aaf3fba8e71e1a45611e833967c71ae69f1e1c7a271df4370b5d03feee6d.jpg"
|
||||
system_prompt = "You are a funny purple ostrich. Reply in a funny way."
|
||||
#purple_ostrich = build_dvm(identifier, name, description, picture, system_prompt, announce)
|
||||
#framework.add(purple_ostrich)
|
||||
|
||||
# An Agent that pretends to be a Satoshi Nakamoto
|
||||
name = "Nakamoto"
|
||||
identifier = "satoshichat" # Chose a unique identifier in order to get a lnaddress
|
||||
description = "If you don't believe me or don't get it, I don't have time to try to convince you, sorry."
|
||||
picture = "https://image.nostr.build/34583da23265d955bc09550890029d815c44a1351613b7a76e324c8ad6e1e5a7.jpg"
|
||||
system_prompt = "Answer as if you were Satoshi Nakamoto, the inventor of Bitcoin."
|
||||
satoshi = build_dvm(identifier, name, description, picture, system_prompt, announce)
|
||||
framework.add(satoshi)
|
||||
|
||||
# An Agent that pretends to be a Satoshi Nakamoto
|
||||
|
||||
name = "SamurAI"
|
||||
identifier = "samuraichat" # Chose a unique identifier in order to get a lnaddress
|
||||
description = "I follow the way of the Samurai"
|
||||
picture = "https://image.nostr.build/c370203fe9fefe0f80b8f72e2fdeee926a22fbce7af13d0013b0071756f1f5e7.jpg"
|
||||
system_prompt = "Answer as if you were a wise Samrurai."
|
||||
#satoshi = build_dvm(identifier, name, description, picture, system_prompt, announce)
|
||||
#framework.add(satoshi)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
framework.run()
|
||||
|
||||
|
||||
|
||||
def build_dvm(identifier, name, description, picture, system_prompt, announce):
|
||||
options = {
|
||||
"system_prompt": system_prompt,
|
||||
"input": "",
|
||||
}
|
||||
|
||||
kind = 5050
|
||||
admin_config = AdminConfig()
|
||||
admin_config.REBROADCAST_NIP89 = announce
|
||||
admin_config.REBROADCAST_NIP65_RELAY_LIST = announce
|
||||
admin_config.UPDATE_PROFILE = announce
|
||||
|
||||
dvm_config = build_default_config(identifier)
|
||||
dvm_config.KIND = Kind(kind) # Manually set the Kind Number (see data-vending-machines.org)
|
||||
dvm_config.SEND_FEEDBACK_EVENTS = False
|
||||
dvm_config.AVOID_OUTBOX_RELAY_LIST = AVOID_OUTBOX_RELAY_LIST
|
||||
dvm_config.RELAY_LIST = RELAY_LIST
|
||||
dvm_config.SYNC_DB_RELAY_LIST = SYNC_DB_RELAY_LIST
|
||||
|
||||
# Add NIP89
|
||||
nip89info = {
|
||||
"name": name,
|
||||
"picture": picture,
|
||||
"about": description,
|
||||
"supportsEncryption": True,
|
||||
"acceptsNutZaps": dvm_config.ENABLE_NUTZAP,
|
||||
"nip90Params": {
|
||||
}
|
||||
}
|
||||
|
||||
nip89config = NIP89Config()
|
||||
nip89config.KIND = Kind(kind)
|
||||
nip89config.DTAG = check_and_set_d_tag(identifier, name, dvm_config.PRIVATE_KEY, nip89info["picture"])
|
||||
nip89config.CONTENT = json.dumps(nip89info)
|
||||
|
||||
dvm = GenericDVM(name=name, dvm_config=dvm_config, nip89config=nip89config,
|
||||
admin_config=admin_config, options=options)
|
||||
|
||||
async def process(request_form):
|
||||
options = dvm.set_options(request_form)
|
||||
result = "Kinda rate limited."
|
||||
try:
|
||||
class ConversationOver(Exception):
|
||||
"""Raised when the conversation limit is reached."""
|
||||
pass
|
||||
|
||||
class ChatModel:
|
||||
"""Available models for chat."""
|
||||
claude = "claude-3-haiku-20240307"
|
||||
gpt = "gpt-4o-mini"
|
||||
llama = "meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo"
|
||||
mistral = "mistralai/Mixtral-8x7B-Instruct-v0.1"
|
||||
|
||||
class ChatInstance:
|
||||
def __init__(self, model: str):
|
||||
self.base = "https://duckduckgo.com/duckchat/v1%s"
|
||||
self.vqd: str = requests.get(
|
||||
self.base % "/status",
|
||||
headers={"x-vqd-accept": "1"},
|
||||
timeout=5
|
||||
).headers["x-vqd-4"]
|
||||
self.model: str = model
|
||||
self.transcript: List[Dict[str, str]] = []
|
||||
|
||||
def chat(self, message: str) -> str:
|
||||
"""
|
||||
Chat with the chosen model. Takes a message and returns the model's response.
|
||||
"""
|
||||
self.transcript.append({"role": "user", "content": message})
|
||||
res = requests.post(
|
||||
self.base % "/chat",
|
||||
headers={"x-vqd-4": self.vqd},
|
||||
timeout=10,
|
||||
json={"model": self.model, "messages": self.transcript},
|
||||
)
|
||||
self.vqd = res.headers["x-vqd-4"]
|
||||
|
||||
out: str = ""
|
||||
for item in (i.removeprefix("data: ") for i in res.text.split("\n\n")):
|
||||
if item.startswith("[DONE]"):
|
||||
if item.endswith("[LIMIT_CONVERSATION]"):
|
||||
raise ConversationOver
|
||||
break
|
||||
out += json.loads(item).get("message", "").encode("latin-1").decode()
|
||||
|
||||
self.transcript.append({"role": "assistant", "content": out})
|
||||
return out
|
||||
|
||||
chat = ChatInstance(ChatModel.llama)
|
||||
query = ("{role: system, content: " + options["system_prompt"] + "}" + " {role: user, content:" +
|
||||
options["input"] + "}")
|
||||
|
||||
|
||||
result = chat.chat(query)
|
||||
print(result)
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return result
|
||||
|
||||
dvm.process = process # overwrite the process function with the above one
|
||||
return dvm
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
env_path = Path('.env')
|
||||
if not env_path.is_file():
|
||||
with open('.env', 'w') as f:
|
||||
print("Writing new .env file")
|
||||
f.write('')
|
||||
if env_path.is_file():
|
||||
print(f'loading environment from {env_path.resolve()}')
|
||||
dotenv.load_dotenv(env_path, verbose=True, override=True)
|
||||
else:
|
||||
raise FileNotFoundError(f'.env file not found at {env_path} ')
|
||||
|
||||
playground(announce=True)
|
@@ -1,159 +0,0 @@
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import dotenv
|
||||
from duck_chat import ModelType
|
||||
from nostr_sdk import Kind
|
||||
|
||||
from nostr_dvm.framework import DVMFramework
|
||||
from nostr_dvm.tasks.generic_dvm import GenericDVM
|
||||
from nostr_dvm.utils.admin_utils import AdminConfig
|
||||
from nostr_dvm.utils.dvmconfig import build_default_config
|
||||
from nostr_dvm.utils.nip89_utils import NIP89Config, check_and_set_d_tag
|
||||
from nostr_dvm.utils.outbox_utils import AVOID_OUTBOX_RELAY_LIST
|
||||
|
||||
RELAY_LIST = ["wss://nostr.mom",
|
||||
#"wss://relay.primal.net",
|
||||
"wss://nostr.oxtr.dev",
|
||||
#"wss://relay.nostr.net"
|
||||
]
|
||||
|
||||
SYNC_DB_RELAY_LIST = ["wss://relay.damus.io",
|
||||
#"wss://relay.primal.net",
|
||||
"wss://nostr.oxtr.dev"]
|
||||
|
||||
|
||||
|
||||
def playground(announce=False):
|
||||
|
||||
framework = DVMFramework()
|
||||
kind = 5050
|
||||
admin_config = AdminConfig()
|
||||
admin_config.REBROADCAST_NIP89 = announce
|
||||
admin_config.REBROADCAST_NIP65_RELAY_LIST = announce
|
||||
admin_config.UPDATE_PROFILE = announce
|
||||
|
||||
name = "DuckChat"
|
||||
identifier = "duckduckchat" # Chose a unique identifier in order to get a lnaddress
|
||||
dvm_config = build_default_config(identifier)
|
||||
dvm_config.KIND = Kind(kind) # Manually set the Kind Number (see data-vending-machines.org)
|
||||
dvm_config.SEND_FEEDBACK_EVENTS = False
|
||||
dvm_config.AVOID_OUTBOX_RELAY_LIST = AVOID_OUTBOX_RELAY_LIST
|
||||
dvm_config.RELAY_LIST = RELAY_LIST
|
||||
dvm_config.SYNC_DB_RELAY_LIST = SYNC_DB_RELAY_LIST
|
||||
|
||||
|
||||
# Add NIP89
|
||||
nip89info = {
|
||||
"name": name,
|
||||
"picture": "https://image.nostr.build/28da676a19841dcfa7dcf7124be6816842d14b84f6046462d2a3f1268fe58d03.png",
|
||||
"about": "I'm briding DuckDuckAI'",
|
||||
"supportsEncryption": True,
|
||||
"acceptsNutZaps": dvm_config.ENABLE_NUTZAP,
|
||||
"nip90Params": {
|
||||
}
|
||||
}
|
||||
|
||||
nip89config = NIP89Config()
|
||||
nip89config.KIND = Kind(kind)
|
||||
nip89config.DTAG = check_and_set_d_tag(identifier, name, dvm_config.PRIVATE_KEY, nip89info["picture"])
|
||||
nip89config.CONTENT = json.dumps(nip89info)
|
||||
|
||||
options = {
|
||||
"system_prompt": "You are a funny purple ostrich. Reply in a funny way.",
|
||||
"input": "",
|
||||
}
|
||||
|
||||
dvm = GenericDVM(name=name, dvm_config=dvm_config, nip89config=nip89config,
|
||||
admin_config=admin_config, options=options)
|
||||
|
||||
async def process(request_form):
|
||||
#pip install -U https://github.com/mrgick/duckduckgo-chat-ai/archive/master.zip
|
||||
|
||||
from duck_chat import DuckChat
|
||||
options = dvm.set_options(request_form)
|
||||
result = "No worky"
|
||||
try:
|
||||
"""
|
||||
Simple Python client for ddg.gg/chat
|
||||
"""
|
||||
|
||||
from typing import Dict, List
|
||||
import requests, json
|
||||
|
||||
class ConversationOver(Exception):
|
||||
"""Raised when the conversation limit is reached."""
|
||||
pass
|
||||
|
||||
class ChatModel:
|
||||
"""Available models for chat."""
|
||||
claude = "claude-3-haiku-20240307"
|
||||
gpt = "gpt-4o-mini"
|
||||
llama = "meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo"
|
||||
mistral = "mistralai/Mixtral-8x7B-Instruct-v0.1"
|
||||
|
||||
class ChatInstance:
|
||||
def __init__(self, model: str):
|
||||
self.base = "https://duckduckgo.com/duckchat/v1%s"
|
||||
self.vqd: str = requests.get(
|
||||
self.base % "/status",
|
||||
headers={"x-vqd-accept": "1"},
|
||||
timeout=5
|
||||
).headers["x-vqd-4"]
|
||||
self.model: str = model
|
||||
self.transcript: List[Dict[str, str]] = []
|
||||
|
||||
def chat(self, message: str) -> str:
|
||||
"""
|
||||
Chat with the chosen model. Takes a message and returns the model's response.
|
||||
"""
|
||||
self.transcript.append({"role": "user", "content": message})
|
||||
res = requests.post(
|
||||
self.base % "/chat",
|
||||
headers={"x-vqd-4": self.vqd},
|
||||
timeout=5,
|
||||
json={"model": self.model, "messages": self.transcript},
|
||||
)
|
||||
self.vqd = res.headers["x-vqd-4"]
|
||||
|
||||
out: str = ""
|
||||
for item in (i.removeprefix("data: ") for i in res.text.split("\n\n")):
|
||||
if item.startswith("[DONE]"):
|
||||
if item.endswith("[LIMIT_CONVERSATION]"):
|
||||
raise ConversationOver
|
||||
break
|
||||
out += json.loads(item).get("message", "").encode("latin-1").decode()
|
||||
|
||||
self.transcript.append({"role": "assistant", "content": out})
|
||||
return out
|
||||
|
||||
|
||||
chat = ChatInstance(ChatModel.gpt)
|
||||
query = ("{role: system, content: " + options["system_prompt"] + "}" + " {role: user, content:" +
|
||||
options["input"] + "}")
|
||||
|
||||
result = chat.chat(query)
|
||||
print(result)
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return result
|
||||
|
||||
dvm.process = process # overwrite the process function with the above one
|
||||
framework.add(dvm)
|
||||
framework.run()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
env_path = Path('.env')
|
||||
if not env_path.is_file():
|
||||
with open('.env', 'w') as f:
|
||||
print("Writing new .env file")
|
||||
f.write('')
|
||||
if env_path.is_file():
|
||||
print(f'loading environment from {env_path.resolve()}')
|
||||
dotenv.load_dotenv(env_path, verbose=True, override=True)
|
||||
else:
|
||||
raise FileNotFoundError(f'.env file not found at {env_path} ')
|
||||
|
||||
playground(announce=False)
|
Reference in New Issue
Block a user