Skip to content
Open
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
Binary file added .DS_Store
Binary file not shown.
38 changes: 4 additions & 34 deletions backend/fastapi_app.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import asyncio
import json

from fastapi import FastAPI, HTTPException, Request
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import StreamingResponse

from neurons.api import initialize, query_synapse_image, query_synapse_text
from routes.chat import router as chat_router

app = FastAPI()

app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
Expand All @@ -17,32 +13,6 @@
max_age=3600,
)

_, _, subtensor, dendrite, metagraph = initialize()


@app.post("/generate-image")
async def get_image(prompt_dict: dict):
prompt = prompt_dict.get('prompt')
if not prompt:
raise HTTPException(status_code=400, detail="Prompt is required")

generated_images = asyncio.run(query_synapse_image(dendrite, metagraph, subtensor, prompt))
try:
image_url = generated_images[0].deserialize().get("url")
except Exception:
raise HTTPException(status_code=500, detail="Can't generate image. Please try again")
return image_url


@app.post("/generate-text")
async def get_text(request: Request):
try:
body = await request.json()
prompt = body.get('prompt')
except json.JSONDecodeError:
raise HTTPException(status_code=500, detail="Cant decode JSON")
if not prompt:
raise HTTPException(status_code=400, detail="Prompt is required")

return StreamingResponse(query_synapse_text(dendrite, metagraph, subtensor, prompt), media_type='text/event-stream')

app.include_router(chat_router)
23 changes: 19 additions & 4 deletions backend/neurons/api.py → backend/neurons/chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
import traceback
import asyncio
from template.protocol import StreamPrompting, ImageResponse
from neurons.conversation_history import ConversationHistory

conversation_history = ConversationHistory()
MAX_TOKENS = 4096

def initialize():
parser = argparse.ArgumentParser()
Expand All @@ -18,8 +21,6 @@ def initialize():
return config, wallet, subtensor, dendrite, metagraph


# axons = [36, 80, 255]

async def query_synapse_image(dendrite, metagraph, subtensor, prompt):
try:
axon = metagraph.axons[87] # 87, 91, 98
Expand All @@ -44,17 +45,31 @@ async def main():
bt.logging.error(f"General exception at step: {e}\n{traceback.format_exc()}")


async def query_synapse_text(dendrite, metagraph, subtensor, prompt):

async def query_synapse_text(dendrite, metagraph, subtensor, conversation_id, prompt):
try:
axon = metagraph.axons[87]
syn = StreamPrompting(messages=[{"role": "user", "content": prompt}], engine="gpt-4-1106-preview", seed=1234)
# Add user prompt to the conversation history
conversation_history.add_user_message(conversation_id, prompt)

# Get the conversation history within the token limit
history_within_limit = conversation_history.get_history_within_limit(conversation_id, MAX_TOKENS) # Set MAX_TOKENS appropriately

syn = StreamPrompting(messages=history_within_limit, engine="gpt-4-1106-preview", seed=1234)

responses = await dendrite([axon], syn, deserialize=False, streaming=True)
merged_chunks = "" # Initialize merged_chunks
for resp in responses:
async for chunk in resp:
if isinstance(chunk, list):
# Merge each streaming chunk together in the background
merged_chunks += chunk[0]

# Yield the current chunk as a response
yield f"data: {chunk[0]}\n\n"

# After all chunks have been processed, add the merged chunks as a single AI message in the conversation history
conversation_history.add_ai_message(conversation_id, merged_chunks)
except Exception as e:
bt.logging.error(f"General exception at step: {e}\n{traceback.format_exc()}")

Expand Down
2 changes: 0 additions & 2 deletions backend/neurons/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import argparse
import os


def check_config(cls, config: "bt.Config"):
bt.axon.check_config(config)
bt.logging.check_config(config)
Expand All @@ -18,7 +17,6 @@ def check_config(cls, config: "bt.Config"):
if not os.path.exists(config.miner.full_path):
os.makedirs(config.miner.full_path)


def get_config() -> "bt.Config":
parser = argparse.ArgumentParser()
parser.add_argument(
Expand Down
78 changes: 78 additions & 0 deletions backend/neurons/conversation_history.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# conversation_history.py
import uuid
from sumy.parsers.plaintext import PlaintextParser
from sumy.nlp.tokenizers import Tokenizer
from sumy.summarizers.lsa import LsaSummarizer


temp_conversation_id= str(uuid.uuid4())
class ConversationHistory:
def __init__(self):
self.history = {}

def get_history(self, conversation_id):
# Retrieve or initialize conversation history for the given conversation_id
return self.history.setdefault(conversation_id, [])

def get_history_within_limit(self, conversation_id, max_tokens, use_summaries=True, max_messages=None):
# Retrieve or initialize conversation history for the given conversation_id
history = self.history.setdefault(conversation_id, [])

if use_summaries:
# Calculate the total tokens in the conversation history
total_tokens = sum(len(message["content"].split()) for message in history)

# If it exceeds the token limit, calculate the number of messages needed
if total_tokens > max_tokens:
num_messages = 0
current_tokens = 0
for message in history:
current_tokens += len(message["content"].split())
num_messages += 1
if current_tokens > max_tokens:
break
else:
num_messages = len(history)

# Return the history within the calculated number of messages
return history[-num_messages:]
elif max_messages is not None:
# Get the last 'max_messages' messages from the history
return history[-max_messages:]
else:
# Return the entire history
return history

def get_summarized_history(self, conversation_id, max_tokens):
# Retrieve or initialize conversation history for the given conversation_id
history = self.history.setdefault(conversation_id, [])

# Combine all messages into a single document
document = " ".join(message["content"] for message in history)

# Summarize the document
summarizer = LsaSummarizer()
parser = PlaintextParser.from_string(document, Tokenizer("english"))
summary = summarizer(parser.document, 1) # Get a single sentence summary

# Return the summarized history
return [{"role": "summarized", "content": str(sentence)} for sentence in summary]

def add_user_message(self, conversation_id, prompt):
# Add user prompt to the conversation history
history = self.get_history(conversation_id)
history.append({"role": "user", "content": prompt})

def add_ai_message(self, conversation_id, response):
# Add AI response to the conversation history
history = self.get_history(conversation_id)
history.append({"role": "assistant", "content": response})

def clear_history(self, conversation_id):
# Clear conversation history for the given conversation_id
if conversation_id in self.history:
del self.history[conversation_id]

def generate_conversation_id(self):
# Function to generate a unique conversation_id for each request
return temp_conversation_id
3 changes: 1 addition & 2 deletions backend/neurons/miner.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@
from openai import OpenAI
from openai import AsyncOpenAI
import bittensor as bt
from transformers import GPT2Tokenizer
from typing import List, Dict, Tuple, Union, Callable, Awaitable
from typing import Dict, Tuple
from template.protocol import StreamPrompting, IsAlive, ImageResponse
from config import get_config, check_config

Expand Down
9 changes: 0 additions & 9 deletions backend/neurons/validator.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,15 @@
import os
import re
import json
import math
import time
import torch
import wandb
import random
import string
import asyncio
import template
import requests
import argparse
import datetime
import traceback
import bittensor as bt
import concurrent.futures
from PIL import Image
from io import BytesIO
from openai import AsyncOpenAI
from typing import List, Optional
from template.protocol import StreamPrompting, IsAlive, ImageResponse

AsyncOpenAI.api_key = os.environ.get('OPENAI_API_KEY')
Expand Down
120 changes: 3 additions & 117 deletions backend/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,128 +1,14 @@
aiohttp==3.8.5
aiosignal==1.3.1
ansible==6.7.0
ansible-core==2.13.13
ansible-vault==2.1.0
anyio==3.7.1
appdirs==1.4.4
async-timeout==4.0.3
attrs==23.1.0
backoff==2.2.1
base58==2.1.1
bittensor==6.3.0
black==23.7.0
certifi==2023.11.17
cffi==1.16.0
charset-normalizer==3.3.2
click==8.1.7
cryptography==41.0.3
cytoolz==0.12.2
ddt==1.6.0
decorator==5.1.1
distro==1.8.0
docker-pycreds==0.4.0
ecdsa==0.18.0
eth-hash==0.5.2
eth-keys==0.4.0
eth-typing==3.5.2
eth-utils==2.3.1
exceptiongroup==1.2.0
fastapi==0.99.1
filelock==3.13.1
frozenlist==1.4.0
fsspec==2023.10.0
fuzzywuzzy==0.18.0
gitdb==4.0.11
GitPython==3.1.40
h11==0.14.0
httpcore==1.0.2
httpx==0.25.1
huggingface-hub==0.19.4
idna==3.4
iniconfig==2.0.0
Jinja2==3.1.2
joblib==1.3.2
Levenshtein==0.23.0
loguru==0.7.0
markdown-it-py==3.0.0
MarkupSafe==2.1.3
mdurl==0.1.2
more-itertools==10.1.0
mpmath==1.3.0
msgpack==1.0.7
msgpack-numpy-opentensor==0.5.0
multidict==6.0.4
munch==2.5.0
mypy-extensions==1.0.0
nest-asyncio==1.5.8
netaddr==0.9.0
networkx==3.2.1
numpy==1.26.2
nvidia-cublas-cu12==12.1.3.1
nvidia-cuda-cupti-cu12==12.1.105
nvidia-cuda-nvrtc-cu12==12.1.105
nvidia-cuda-runtime-cu12==12.1.105
nvidia-cudnn-cu12==8.9.2.26
nvidia-cufft-cu12==11.0.2.54
nvidia-curand-cu12==10.3.2.106
nvidia-cusolver-cu12==11.4.5.107
nvidia-cusparse-cu12==12.1.0.106
nvidia-nccl-cu12==2.18.1
nvidia-nvjitlink-cu12==12.3.101
nvidia-nvtx-cu12==12.1.105
openai>=1.3.2
packaging==23.2
password-strength==0.0.3.post2
pathspec==0.11.2
Pillow==10.1.0
platformdirs==4.0.0
pluggy==1.3.0
protobuf==4.25.1
psutil==5.9.6
py==1.11.0
py-bip39-bindings==0.1.11
py-ed25519-zebra-bindings==1.0.1
py-sr25519-bindings==0.2.0
pycparser==2.21
pycryptodome==3.19.0
pydantic==1.10.13
Pygments==2.17.2
PyNaCl==1.5.0
pytest==7.4.3
pytest-asyncio==0.21.1
python-Levenshtein==0.23.0
PyYAML==6.0.1
rapidfuzz==3.5.2
regex==2023.10.3
requests==2.31.0
resolvelib==0.8.1
retry==0.9.2
rich==13.7.0
safetensors==0.4.0
scalecodec==1.2.0
scikit-learn==1.3.2
scipy==1.11.4
sentry-sdk==1.36.0
setproctitle==1.3.3
six==1.16.0
smmap==5.0.1
sniffio==1.3.0
starlette==0.27.0
substrate-interface==1.5.0
sympy==1.12
termcolor==2.3.0
threadpoolctl==3.2.0
tokenizers==0.15.0
tomli==2.0.1
toolz==0.12.0
torch==2.1.1
tqdm==4.66.1
transformers==4.35.2
triton==2.1.0
typing_extensions==4.8.0
urllib3==2.1.0
uvicorn==0.22.0
wandb==0.16.0
websocket-client==1.6.4
xxhash==3.4.1
yarl==1.9.3
scikit-learn==1.3.2
Pillow==10.1.0
sumy==0.11.0
Loading